Skip to content

Commit

Permalink
cifsd: add file operations
Browse files Browse the repository at this point in the history
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
Show file tree
Hide file tree
Showing 6 changed files with 3,691 additions and 0 deletions.
292 changes: 292 additions & 0 deletions fs/cifsd/buffer_pool.c
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;
}
28 changes: 28 additions & 0 deletions fs/cifsd/buffer_pool.h
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__ */
Loading

0 comments on commit f441584

Please sign in to comment.