138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-or-later 238c8a9a5SSteve French /* 338c8a9a5SSteve French * Copyright (C) 2019 Samsung Electronics Co., Ltd. 438c8a9a5SSteve French */ 538c8a9a5SSteve French 638c8a9a5SSteve French #include <linux/list.h> 738c8a9a5SSteve French #include <linux/mm.h> 838c8a9a5SSteve French #include <linux/slab.h> 938c8a9a5SSteve French #include <linux/workqueue.h> 1038c8a9a5SSteve French 1138c8a9a5SSteve French #include "server.h" 1238c8a9a5SSteve French #include "connection.h" 1338c8a9a5SSteve French #include "ksmbd_work.h" 1438c8a9a5SSteve French #include "mgmt/ksmbd_ida.h" 1538c8a9a5SSteve French 1638c8a9a5SSteve French static struct kmem_cache *work_cache; 1738c8a9a5SSteve French static struct workqueue_struct *ksmbd_wq; 1838c8a9a5SSteve French 1938c8a9a5SSteve French struct ksmbd_work *ksmbd_alloc_work_struct(void) 2038c8a9a5SSteve French { 2138c8a9a5SSteve French struct ksmbd_work *work = kmem_cache_zalloc(work_cache, GFP_KERNEL); 2238c8a9a5SSteve French 2338c8a9a5SSteve French if (work) { 2438c8a9a5SSteve French work->compound_fid = KSMBD_NO_FID; 2538c8a9a5SSteve French work->compound_pfid = KSMBD_NO_FID; 2638c8a9a5SSteve French INIT_LIST_HEAD(&work->request_entry); 2738c8a9a5SSteve French INIT_LIST_HEAD(&work->async_request_entry); 2838c8a9a5SSteve French INIT_LIST_HEAD(&work->fp_entry); 2938c8a9a5SSteve French INIT_LIST_HEAD(&work->interim_entry); 30e2b76ab8SNamjae Jeon INIT_LIST_HEAD(&work->aux_read_list); 31e2b76ab8SNamjae Jeon work->iov_alloc_cnt = 4; 32e2b76ab8SNamjae Jeon work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec), 33e2b76ab8SNamjae Jeon GFP_KERNEL); 34e2b76ab8SNamjae Jeon if (!work->iov) { 35e2b76ab8SNamjae Jeon kmem_cache_free(work_cache, work); 36e2b76ab8SNamjae Jeon work = NULL; 37e2b76ab8SNamjae Jeon } 3838c8a9a5SSteve French } 3938c8a9a5SSteve French return work; 4038c8a9a5SSteve French } 4138c8a9a5SSteve French 4238c8a9a5SSteve French void ksmbd_free_work_struct(struct ksmbd_work *work) 4338c8a9a5SSteve French { 44e2b76ab8SNamjae Jeon struct aux_read *ar, *tmp; 45e2b76ab8SNamjae Jeon 4638c8a9a5SSteve French WARN_ON(work->saved_cred != NULL); 4738c8a9a5SSteve French 4838c8a9a5SSteve French kvfree(work->response_buf); 49e2b76ab8SNamjae Jeon 50e2b76ab8SNamjae Jeon list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) { 51e2b76ab8SNamjae Jeon kvfree(ar->buf); 52e2b76ab8SNamjae Jeon list_del(&ar->entry); 53e2b76ab8SNamjae Jeon kfree(ar); 54e2b76ab8SNamjae Jeon } 55e2b76ab8SNamjae Jeon 5638c8a9a5SSteve French kfree(work->tr_buf); 5738c8a9a5SSteve French kvfree(work->request_buf); 58e2b76ab8SNamjae Jeon kfree(work->iov); 5938c8a9a5SSteve French if (work->async_id) 6038c8a9a5SSteve French ksmbd_release_id(&work->conn->async_ida, work->async_id); 6138c8a9a5SSteve French kmem_cache_free(work_cache, work); 6238c8a9a5SSteve French } 6338c8a9a5SSteve French 6438c8a9a5SSteve French void ksmbd_work_pool_destroy(void) 6538c8a9a5SSteve French { 6638c8a9a5SSteve French kmem_cache_destroy(work_cache); 6738c8a9a5SSteve French } 6838c8a9a5SSteve French 6938c8a9a5SSteve French int ksmbd_work_pool_init(void) 7038c8a9a5SSteve French { 7138c8a9a5SSteve French work_cache = kmem_cache_create("ksmbd_work_cache", 7238c8a9a5SSteve French sizeof(struct ksmbd_work), 0, 7338c8a9a5SSteve French SLAB_HWCACHE_ALIGN, NULL); 7438c8a9a5SSteve French if (!work_cache) 7538c8a9a5SSteve French return -ENOMEM; 7638c8a9a5SSteve French return 0; 7738c8a9a5SSteve French } 7838c8a9a5SSteve French 7938c8a9a5SSteve French int ksmbd_workqueue_init(void) 8038c8a9a5SSteve French { 8138c8a9a5SSteve French ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0); 8238c8a9a5SSteve French if (!ksmbd_wq) 8338c8a9a5SSteve French return -ENOMEM; 8438c8a9a5SSteve French return 0; 8538c8a9a5SSteve French } 8638c8a9a5SSteve French 8738c8a9a5SSteve French void ksmbd_workqueue_destroy(void) 8838c8a9a5SSteve French { 8938c8a9a5SSteve French destroy_workqueue(ksmbd_wq); 9038c8a9a5SSteve French ksmbd_wq = NULL; 9138c8a9a5SSteve French } 9238c8a9a5SSteve French 9338c8a9a5SSteve French bool ksmbd_queue_work(struct ksmbd_work *work) 9438c8a9a5SSteve French { 9538c8a9a5SSteve French return queue_work(ksmbd_wq, &work->work); 9638c8a9a5SSteve French } 97e2b76ab8SNamjae Jeon 98*d7373788SNamjae Jeon static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib, 99e2b76ab8SNamjae Jeon unsigned int ib_len) 100e2b76ab8SNamjae Jeon { 101*d7373788SNamjae Jeon work->iov[++work->iov_idx].iov_base = ib; 102*d7373788SNamjae Jeon work->iov[work->iov_idx].iov_len = ib_len; 103*d7373788SNamjae Jeon work->iov_cnt++; 104*d7373788SNamjae Jeon } 105e2b76ab8SNamjae Jeon 106*d7373788SNamjae Jeon static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len, 107*d7373788SNamjae Jeon void *aux_buf, unsigned int aux_size) 108*d7373788SNamjae Jeon { 109*d7373788SNamjae Jeon struct aux_read *ar; 110*d7373788SNamjae Jeon int need_iov_cnt = 1; 111*d7373788SNamjae Jeon 112*d7373788SNamjae Jeon if (aux_size) { 113*d7373788SNamjae Jeon need_iov_cnt++; 114*d7373788SNamjae Jeon ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL); 115*d7373788SNamjae Jeon if (!ar) 116*d7373788SNamjae Jeon return -ENOMEM; 117*d7373788SNamjae Jeon } 118*d7373788SNamjae Jeon 119*d7373788SNamjae Jeon if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) { 120e2b76ab8SNamjae Jeon struct kvec *new; 121e2b76ab8SNamjae Jeon 122e2b76ab8SNamjae Jeon work->iov_alloc_cnt += 4; 123e2b76ab8SNamjae Jeon new = krealloc(work->iov, 124e2b76ab8SNamjae Jeon sizeof(struct kvec) * work->iov_alloc_cnt, 125e2b76ab8SNamjae Jeon GFP_KERNEL | __GFP_ZERO); 126e2b76ab8SNamjae Jeon if (!new) 127e2b76ab8SNamjae Jeon return -ENOMEM; 128e2b76ab8SNamjae Jeon work->iov = new; 129e2b76ab8SNamjae Jeon } 130e2b76ab8SNamjae Jeon 131e2b76ab8SNamjae Jeon /* Plus rfc_length size on first iov */ 132e2b76ab8SNamjae Jeon if (!work->iov_idx) { 133e2b76ab8SNamjae Jeon work->iov[work->iov_idx].iov_base = work->response_buf; 134e2b76ab8SNamjae Jeon *(__be32 *)work->iov[0].iov_base = 0; 135e2b76ab8SNamjae Jeon work->iov[work->iov_idx].iov_len = 4; 136e2b76ab8SNamjae Jeon work->iov_cnt++; 137e2b76ab8SNamjae Jeon } 138e2b76ab8SNamjae Jeon 139*d7373788SNamjae Jeon __ksmbd_iov_pin(work, ib, len); 140e2b76ab8SNamjae Jeon inc_rfc1001_len(work->iov[0].iov_base, len); 141e2b76ab8SNamjae Jeon 142e2b76ab8SNamjae Jeon if (aux_size) { 143*d7373788SNamjae Jeon __ksmbd_iov_pin(work, aux_buf, aux_size); 144e2b76ab8SNamjae Jeon inc_rfc1001_len(work->iov[0].iov_base, aux_size); 145e2b76ab8SNamjae Jeon 146e2b76ab8SNamjae Jeon ar->buf = aux_buf; 147e2b76ab8SNamjae Jeon list_add(&ar->entry, &work->aux_read_list); 148e2b76ab8SNamjae Jeon } 149e2b76ab8SNamjae Jeon 150e2b76ab8SNamjae Jeon return 0; 151e2b76ab8SNamjae Jeon } 152e2b76ab8SNamjae Jeon 153e2b76ab8SNamjae Jeon int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len) 154e2b76ab8SNamjae Jeon { 155e2b76ab8SNamjae Jeon return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0); 156e2b76ab8SNamjae Jeon } 157e2b76ab8SNamjae Jeon 158e2b76ab8SNamjae Jeon int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len, 159e2b76ab8SNamjae Jeon void *aux_buf, unsigned int aux_size) 160e2b76ab8SNamjae Jeon { 161e2b76ab8SNamjae Jeon return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size); 162e2b76ab8SNamjae Jeon } 163e2b76ab8SNamjae Jeon 164041bba44SNamjae Jeon int allocate_interim_rsp_buf(struct ksmbd_work *work) 165e2b76ab8SNamjae Jeon { 166041bba44SNamjae Jeon work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL); 167041bba44SNamjae Jeon if (!work->response_buf) 168041bba44SNamjae Jeon return -ENOMEM; 169041bba44SNamjae Jeon work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE; 170041bba44SNamjae Jeon return 0; 171e2b76ab8SNamjae Jeon } 172