brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · d7c676c Raw
178 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   Copyright (C) 2019 Samsung Electronics Co., Ltd.4 */5 6#include <linux/list.h>7#include <linux/mm.h>8#include <linux/slab.h>9#include <linux/workqueue.h>10 11#include "server.h"12#include "connection.h"13#include "ksmbd_work.h"14#include "mgmt/ksmbd_ida.h"15 16static struct kmem_cache *work_cache;17static struct workqueue_struct *ksmbd_wq;18 19struct ksmbd_work *ksmbd_alloc_work_struct(void)20{21	struct ksmbd_work *work = kmem_cache_zalloc(work_cache, GFP_KERNEL);22 23	if (work) {24		work->compound_fid = KSMBD_NO_FID;25		work->compound_pfid = KSMBD_NO_FID;26		INIT_LIST_HEAD(&work->request_entry);27		INIT_LIST_HEAD(&work->async_request_entry);28		INIT_LIST_HEAD(&work->fp_entry);29		INIT_LIST_HEAD(&work->interim_entry);30		INIT_LIST_HEAD(&work->aux_read_list);31		work->iov_alloc_cnt = 4;32		work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec),33				    GFP_KERNEL);34		if (!work->iov) {35			kmem_cache_free(work_cache, work);36			work = NULL;37		}38	}39	return work;40}41 42void ksmbd_free_work_struct(struct ksmbd_work *work)43{44	struct aux_read *ar, *tmp;45 46	WARN_ON(work->saved_cred != NULL);47 48	kvfree(work->response_buf);49 50	list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) {51		kvfree(ar->buf);52		list_del(&ar->entry);53		kfree(ar);54	}55 56	kfree(work->tr_buf);57	kvfree(work->request_buf);58	kfree(work->iov);59	if (!list_empty(&work->interim_entry))60		list_del(&work->interim_entry);61 62	if (work->async_id)63		ksmbd_release_id(&work->conn->async_ida, work->async_id);64	kmem_cache_free(work_cache, work);65}66 67void ksmbd_work_pool_destroy(void)68{69	kmem_cache_destroy(work_cache);70}71 72int ksmbd_work_pool_init(void)73{74	work_cache = kmem_cache_create("ksmbd_work_cache",75				       sizeof(struct ksmbd_work), 0,76				       SLAB_HWCACHE_ALIGN, NULL);77	if (!work_cache)78		return -ENOMEM;79	return 0;80}81 82int ksmbd_workqueue_init(void)83{84	ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0);85	if (!ksmbd_wq)86		return -ENOMEM;87	return 0;88}89 90void ksmbd_workqueue_destroy(void)91{92	destroy_workqueue(ksmbd_wq);93	ksmbd_wq = NULL;94}95 96bool ksmbd_queue_work(struct ksmbd_work *work)97{98	return queue_work(ksmbd_wq, &work->work);99}100 101static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,102				   unsigned int ib_len)103{104	work->iov[++work->iov_idx].iov_base = ib;105	work->iov[work->iov_idx].iov_len = ib_len;106	work->iov_cnt++;107}108 109static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,110			       void *aux_buf, unsigned int aux_size)111{112	struct aux_read *ar = NULL;113	int need_iov_cnt = 1;114 115	if (aux_size) {116		need_iov_cnt++;117		ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);118		if (!ar)119			return -ENOMEM;120	}121 122	if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {123		struct kvec *new;124 125		work->iov_alloc_cnt += 4;126		new = krealloc(work->iov,127			       sizeof(struct kvec) * work->iov_alloc_cnt,128			       GFP_KERNEL | __GFP_ZERO);129		if (!new) {130			kfree(ar);131			work->iov_alloc_cnt -= 4;132			return -ENOMEM;133		}134		work->iov = new;135	}136 137	/* Plus rfc_length size on first iov */138	if (!work->iov_idx) {139		work->iov[work->iov_idx].iov_base = work->response_buf;140		*(__be32 *)work->iov[0].iov_base = 0;141		work->iov[work->iov_idx].iov_len = 4;142		work->iov_cnt++;143	}144 145	__ksmbd_iov_pin(work, ib, len);146	inc_rfc1001_len(work->iov[0].iov_base, len);147 148	if (aux_size) {149		__ksmbd_iov_pin(work, aux_buf, aux_size);150		inc_rfc1001_len(work->iov[0].iov_base, aux_size);151 152		ar->buf = aux_buf;153		list_add(&ar->entry, &work->aux_read_list);154	}155 156	return 0;157}158 159int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len)160{161	return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0);162}163 164int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,165			   void *aux_buf, unsigned int aux_size)166{167	return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);168}169 170int allocate_interim_rsp_buf(struct ksmbd_work *work)171{172	work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);173	if (!work->response_buf)174		return -ENOMEM;175	work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;176	return 0;177}178