-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds file operations and buffer pool for cifsd. Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Acked-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
- Loading branch information
Namjae Jeon
authored and
Steve French
committed
May 11, 2021
1 parent
e2f3448
commit f441584
Showing
6 changed files
with
3,691 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
/* | ||
* Copyright (C) 2018 Samsung Electronics Co., Ltd. | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/wait.h> | ||
#include <linux/sched.h> | ||
#include <linux/mm.h> | ||
#include <linux/slab.h> | ||
#include <linux/vmalloc.h> | ||
#include <linux/rwlock.h> | ||
|
||
#include "glob.h" | ||
#include "buffer_pool.h" | ||
#include "connection.h" | ||
#include "mgmt/ksmbd_ida.h" | ||
|
||
static struct kmem_cache *filp_cache; | ||
|
||
struct wm { | ||
struct list_head list; | ||
unsigned int sz; | ||
char buffer[0]; | ||
}; | ||
|
||
struct wm_list { | ||
struct list_head list; | ||
unsigned int sz; | ||
|
||
spinlock_t wm_lock; | ||
int avail_wm; | ||
struct list_head idle_wm; | ||
wait_queue_head_t wm_wait; | ||
}; | ||
|
||
static LIST_HEAD(wm_lists); | ||
static DEFINE_RWLOCK(wm_lists_lock); | ||
|
||
void *ksmbd_alloc(size_t size) | ||
{ | ||
return kvmalloc(size, GFP_KERNEL | __GFP_ZERO); | ||
} | ||
|
||
void ksmbd_free(void *ptr) | ||
{ | ||
kvfree(ptr); | ||
} | ||
|
||
static struct wm *wm_alloc(size_t sz, gfp_t flags) | ||
{ | ||
struct wm *wm; | ||
size_t alloc_sz = sz + sizeof(struct wm); | ||
|
||
wm = kvmalloc(alloc_sz, flags); | ||
if (!wm) | ||
return NULL; | ||
wm->sz = sz; | ||
return wm; | ||
} | ||
|
||
static int register_wm_size_class(size_t sz) | ||
{ | ||
struct wm_list *l, *nl; | ||
|
||
nl = kvmalloc(sizeof(struct wm_list), GFP_KERNEL); | ||
if (!nl) | ||
return -ENOMEM; | ||
|
||
nl->sz = sz; | ||
spin_lock_init(&nl->wm_lock); | ||
INIT_LIST_HEAD(&nl->idle_wm); | ||
INIT_LIST_HEAD(&nl->list); | ||
init_waitqueue_head(&nl->wm_wait); | ||
nl->avail_wm = 0; | ||
|
||
write_lock(&wm_lists_lock); | ||
list_for_each_entry(l, &wm_lists, list) { | ||
if (l->sz == sz) { | ||
write_unlock(&wm_lists_lock); | ||
kvfree(nl); | ||
return 0; | ||
} | ||
} | ||
|
||
list_add(&nl->list, &wm_lists); | ||
write_unlock(&wm_lists_lock); | ||
return 0; | ||
} | ||
|
||
static struct wm_list *match_wm_list(size_t size) | ||
{ | ||
struct wm_list *l, *rl = NULL; | ||
|
||
read_lock(&wm_lists_lock); | ||
list_for_each_entry(l, &wm_lists, list) { | ||
if (l->sz == size) { | ||
rl = l; | ||
break; | ||
} | ||
} | ||
read_unlock(&wm_lists_lock); | ||
return rl; | ||
} | ||
|
||
static struct wm *find_wm(size_t size) | ||
{ | ||
struct wm_list *wm_list; | ||
struct wm *wm; | ||
|
||
wm_list = match_wm_list(size); | ||
if (!wm_list) { | ||
if (register_wm_size_class(size)) | ||
return NULL; | ||
wm_list = match_wm_list(size); | ||
} | ||
|
||
if (!wm_list) | ||
return NULL; | ||
|
||
while (1) { | ||
spin_lock(&wm_list->wm_lock); | ||
if (!list_empty(&wm_list->idle_wm)) { | ||
wm = list_entry(wm_list->idle_wm.next, | ||
struct wm, | ||
list); | ||
list_del(&wm->list); | ||
spin_unlock(&wm_list->wm_lock); | ||
return wm; | ||
} | ||
|
||
if (wm_list->avail_wm > num_online_cpus()) { | ||
spin_unlock(&wm_list->wm_lock); | ||
wait_event(wm_list->wm_wait, | ||
!list_empty(&wm_list->idle_wm)); | ||
continue; | ||
} | ||
|
||
wm_list->avail_wm++; | ||
spin_unlock(&wm_list->wm_lock); | ||
|
||
wm = wm_alloc(size, GFP_KERNEL); | ||
if (!wm) { | ||
spin_lock(&wm_list->wm_lock); | ||
wm_list->avail_wm--; | ||
spin_unlock(&wm_list->wm_lock); | ||
wait_event(wm_list->wm_wait, | ||
!list_empty(&wm_list->idle_wm)); | ||
continue; | ||
} | ||
break; | ||
} | ||
|
||
return wm; | ||
} | ||
|
||
static void release_wm(struct wm *wm, struct wm_list *wm_list) | ||
{ | ||
if (!wm) | ||
return; | ||
|
||
spin_lock(&wm_list->wm_lock); | ||
if (wm_list->avail_wm <= num_online_cpus()) { | ||
list_add(&wm->list, &wm_list->idle_wm); | ||
spin_unlock(&wm_list->wm_lock); | ||
wake_up(&wm_list->wm_wait); | ||
return; | ||
} | ||
|
||
wm_list->avail_wm--; | ||
spin_unlock(&wm_list->wm_lock); | ||
ksmbd_free(wm); | ||
} | ||
|
||
static void wm_list_free(struct wm_list *l) | ||
{ | ||
struct wm *wm; | ||
|
||
while (!list_empty(&l->idle_wm)) { | ||
wm = list_entry(l->idle_wm.next, struct wm, list); | ||
list_del(&wm->list); | ||
kvfree(wm); | ||
} | ||
kvfree(l); | ||
} | ||
|
||
static void wm_lists_destroy(void) | ||
{ | ||
struct wm_list *l; | ||
|
||
while (!list_empty(&wm_lists)) { | ||
l = list_entry(wm_lists.next, struct wm_list, list); | ||
list_del(&l->list); | ||
wm_list_free(l); | ||
} | ||
} | ||
|
||
void ksmbd_free_request(void *addr) | ||
{ | ||
kvfree(addr); | ||
} | ||
|
||
void *ksmbd_alloc_request(size_t size) | ||
{ | ||
return kvmalloc(size, GFP_KERNEL); | ||
} | ||
|
||
void ksmbd_free_response(void *buffer) | ||
{ | ||
kvfree(buffer); | ||
} | ||
|
||
void *ksmbd_alloc_response(size_t size) | ||
{ | ||
return kvmalloc(size, GFP_KERNEL | __GFP_ZERO); | ||
} | ||
|
||
void *ksmbd_find_buffer(size_t size) | ||
{ | ||
struct wm *wm; | ||
|
||
wm = find_wm(size); | ||
|
||
WARN_ON(!wm); | ||
if (wm) | ||
return wm->buffer; | ||
return NULL; | ||
} | ||
|
||
void ksmbd_release_buffer(void *buffer) | ||
{ | ||
struct wm_list *wm_list; | ||
struct wm *wm; | ||
|
||
if (!buffer) | ||
return; | ||
|
||
wm = container_of(buffer, struct wm, buffer); | ||
wm_list = match_wm_list(wm->sz); | ||
WARN_ON(!wm_list); | ||
if (wm_list) | ||
release_wm(wm, wm_list); | ||
} | ||
|
||
void *ksmbd_realloc_response(void *ptr, size_t old_sz, size_t new_sz) | ||
{ | ||
size_t sz = min(old_sz, new_sz); | ||
void *nptr; | ||
|
||
nptr = ksmbd_alloc_response(new_sz); | ||
if (!nptr) | ||
return ptr; | ||
memcpy(nptr, ptr, sz); | ||
ksmbd_free_response(ptr); | ||
return nptr; | ||
} | ||
|
||
void ksmbd_free_file_struct(void *filp) | ||
{ | ||
kmem_cache_free(filp_cache, filp); | ||
} | ||
|
||
void *ksmbd_alloc_file_struct(void) | ||
{ | ||
return kmem_cache_zalloc(filp_cache, GFP_KERNEL); | ||
} | ||
|
||
void ksmbd_destroy_buffer_pools(void) | ||
{ | ||
wm_lists_destroy(); | ||
ksmbd_work_pool_destroy(); | ||
kmem_cache_destroy(filp_cache); | ||
} | ||
|
||
int ksmbd_init_buffer_pools(void) | ||
{ | ||
if (ksmbd_work_pool_init()) | ||
goto out; | ||
|
||
filp_cache = kmem_cache_create("ksmbd_file_cache", | ||
sizeof(struct ksmbd_file), 0, | ||
SLAB_HWCACHE_ALIGN, NULL); | ||
if (!filp_cache) | ||
goto out; | ||
|
||
return 0; | ||
|
||
out: | ||
ksmbd_err("failed to allocate memory\n"); | ||
ksmbd_destroy_buffer_pools(); | ||
return -ENOMEM; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
/* | ||
* Copyright (C) 2018 Samsung Electronics Co., Ltd. | ||
*/ | ||
|
||
#ifndef __KSMBD_BUFFER_POOL_H__ | ||
#define __KSMBD_BUFFER_POOL_H__ | ||
|
||
void *ksmbd_find_buffer(size_t size); | ||
void ksmbd_release_buffer(void *buffer); | ||
|
||
void *ksmbd_alloc(size_t size); | ||
void ksmbd_free(void *ptr); | ||
|
||
void ksmbd_free_request(void *addr); | ||
void *ksmbd_alloc_request(size_t size); | ||
void ksmbd_free_response(void *buffer); | ||
void *ksmbd_alloc_response(size_t size); | ||
|
||
void *ksmbd_realloc_response(void *ptr, size_t old_sz, size_t new_sz); | ||
|
||
void ksmbd_free_file_struct(void *filp); | ||
void *ksmbd_alloc_file_struct(void); | ||
|
||
void ksmbd_destroy_buffer_pools(void); | ||
int ksmbd_init_buffer_pools(void); | ||
|
||
#endif /* __KSMBD_BUFFER_POOL_H__ */ |
Oops, something went wrong.