Commit d484d621 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French

ksmbd: add durable scavenger timer

Launch ksmbd-durable-scavenger kernel thread to scan durable fps that
have not been reclaimed by a client within the configured time.
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 520da3c4
...@@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) ...@@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
ksmbd_tree_conn_session_logoff(sess); ksmbd_tree_conn_session_logoff(sess);
ksmbd_destroy_file_table(&sess->file_table); ksmbd_destroy_file_table(&sess->file_table);
ksmbd_launch_ksmbd_durable_scavenger();
ksmbd_session_rpc_clear_list(sess); ksmbd_session_rpc_clear_list(sess);
free_channel_list(sess); free_channel_list(sess);
kfree(sess->Preauth_HashValue); kfree(sess->Preauth_HashValue);
...@@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, ...@@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
ksmbd_destroy_file_table(&prev_sess->file_table); ksmbd_destroy_file_table(&prev_sess->file_table);
prev_sess->state = SMB2_SESSION_EXPIRED; prev_sess->state = SMB2_SESSION_EXPIRED;
ksmbd_launch_ksmbd_durable_scavenger();
out: out:
up_write(&conn->session_lock); up_write(&conn->session_lock);
up_write(&sessions_table_lock); up_write(&sessions_table_lock);
......
...@@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl) ...@@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
{ {
ksmbd_ipc_soft_reset(); ksmbd_ipc_soft_reset();
ksmbd_conn_transport_destroy(); ksmbd_conn_transport_destroy();
ksmbd_stop_durable_scavenger();
server_conf_free(); server_conf_free();
server_conf_init(); server_conf_init();
WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
......
...@@ -44,6 +44,7 @@ struct ksmbd_server_config { ...@@ -44,6 +44,7 @@ struct ksmbd_server_config {
unsigned int max_connections; unsigned int max_connections;
char *conf[SERVER_CONF_WORK_GROUP + 1]; char *conf[SERVER_CONF_WORK_GROUP + 1];
struct task_struct *dh_task;
}; };
extern struct ksmbd_server_config server_conf; extern struct ksmbd_server_config server_conf;
......
...@@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work) ...@@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work)
SMB2_CREATE_GUID_SIZE); SMB2_CREATE_GUID_SIZE);
if (dh_info.timeout) if (dh_info.timeout)
fp->durable_timeout = min(dh_info.timeout, fp->durable_timeout = min(dh_info.timeout,
300000); DURABLE_HANDLE_MAX_TIMEOUT);
else else
fp->durable_timeout = 60; fp->durable_timeout = 60;
} }
......
...@@ -72,6 +72,8 @@ struct create_durable_req_v2 { ...@@ -72,6 +72,8 @@ struct create_durable_req_v2 {
__u8 CreateGuid[16]; __u8 CreateGuid[16];
} __packed; } __packed;
#define DURABLE_HANDLE_MAX_TIMEOUT 300000
struct create_durable_reconn_req { struct create_durable_reconn_req {
struct create_context_hdr ccontext; struct create_context_hdr ccontext;
__u8 Name[8]; __u8 Name[8];
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <linux/filelock.h> #include <linux/filelock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include "glob.h" #include "glob.h"
#include "vfs_cache.h" #include "vfs_cache.h"
...@@ -17,6 +19,7 @@ ...@@ -17,6 +19,7 @@
#include "mgmt/tree_connect.h" #include "mgmt/tree_connect.h"
#include "mgmt/user_session.h" #include "mgmt/user_session.h"
#include "smb_common.h" #include "smb_common.h"
#include "server.h"
#define S_DEL_PENDING 1 #define S_DEL_PENDING 1
#define S_DEL_ON_CLS 2 #define S_DEL_ON_CLS 2
...@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft; ...@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
static atomic_long_t fd_limit; static atomic_long_t fd_limit;
static struct kmem_cache *filp_cache; static struct kmem_cache *filp_cache;
static bool durable_scavenger_running;
static DEFINE_MUTEX(durable_scavenger_lock);
static wait_queue_head_t dh_wq;
void ksmbd_set_fd_limit(unsigned long limit) void ksmbd_set_fd_limit(unsigned long limit)
{ {
limit = min(limit, get_max_files()); limit = min(limit, get_max_files());
...@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp) ...@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
if (!has_file_id(fp->persistent_id)) if (!has_file_id(fp->persistent_id))
return; return;
write_lock(&global_ft.lock);
idr_remove(global_ft.idr, fp->persistent_id); idr_remove(global_ft.idr, fp->persistent_id);
}
static void ksmbd_remove_durable_fd(struct ksmbd_file *fp)
{
write_lock(&global_ft.lock);
__ksmbd_remove_durable_fd(fp);
write_unlock(&global_ft.lock); write_unlock(&global_ft.lock);
if (waitqueue_active(&dh_wq))
wake_up(&dh_wq);
} }
static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) static void __ksmbd_remove_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
...@@ -305,7 +319,7 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) ...@@ -305,7 +319,7 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
struct ksmbd_lock *smb_lock, *tmp_lock; struct ksmbd_lock *smb_lock, *tmp_lock;
fd_limit_close(); fd_limit_close();
__ksmbd_remove_durable_fd(fp); ksmbd_remove_durable_fd(fp);
if (ft) if (ft)
__ksmbd_remove_fd(ft, fp); __ksmbd_remove_fd(ft, fp);
...@@ -697,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, ...@@ -697,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
return fp->tcon != tcon; return fp->tcon != tcon;
} }
static bool ksmbd_durable_scavenger_alive(void)
{
mutex_lock(&durable_scavenger_lock);
if (!durable_scavenger_running) {
mutex_unlock(&durable_scavenger_lock);
return false;
}
mutex_unlock(&durable_scavenger_lock);
if (kthread_should_stop())
return false;
if (idr_is_empty(global_ft.idr))
return false;
return true;
}
static void ksmbd_scavenger_dispose_dh(struct list_head *head)
{
while (!list_empty(head)) {
struct ksmbd_file *fp;
fp = list_first_entry(head, struct ksmbd_file, node);
list_del_init(&fp->node);
__ksmbd_close_fd(NULL, fp);
}
}
static int ksmbd_durable_scavenger(void *dummy)
{
struct ksmbd_file *fp = NULL;
unsigned int id;
unsigned int min_timeout = 1;
bool found_fp_timeout;
LIST_HEAD(scavenger_list);
unsigned long remaining_jiffies;
__module_get(THIS_MODULE);
set_freezable();
while (ksmbd_durable_scavenger_alive()) {
if (try_to_freeze())
continue;
found_fp_timeout = false;
remaining_jiffies = wait_event_timeout(dh_wq,
ksmbd_durable_scavenger_alive() == false,
__msecs_to_jiffies(min_timeout));
if (remaining_jiffies)
min_timeout = jiffies_to_msecs(remaining_jiffies);
else
min_timeout = DURABLE_HANDLE_MAX_TIMEOUT;
write_lock(&global_ft.lock);
idr_for_each_entry(global_ft.idr, fp, id) {
if (!fp->durable_timeout)
continue;
if (atomic_read(&fp->refcount) > 1 ||
fp->conn)
continue;
found_fp_timeout = true;
if (fp->durable_scavenger_timeout <=
jiffies_to_msecs(jiffies)) {
__ksmbd_remove_durable_fd(fp);
list_add(&fp->node, &scavenger_list);
} else {
unsigned long durable_timeout;
durable_timeout =
fp->durable_scavenger_timeout -
jiffies_to_msecs(jiffies);
if (min_timeout > durable_timeout)
min_timeout = durable_timeout;
}
}
write_unlock(&global_ft.lock);
ksmbd_scavenger_dispose_dh(&scavenger_list);
if (found_fp_timeout == false)
break;
}
mutex_lock(&durable_scavenger_lock);
durable_scavenger_running = false;
mutex_unlock(&durable_scavenger_lock);
module_put(THIS_MODULE);
return 0;
}
void ksmbd_launch_ksmbd_durable_scavenger(void)
{
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
return;
mutex_lock(&durable_scavenger_lock);
if (durable_scavenger_running == true) {
mutex_unlock(&durable_scavenger_lock);
return;
}
durable_scavenger_running = true;
server_conf.dh_task = kthread_run(ksmbd_durable_scavenger,
(void *)NULL, "ksmbd-durable-scavenger");
if (IS_ERR(server_conf.dh_task))
pr_err("cannot start conn thread, err : %ld\n",
PTR_ERR(server_conf.dh_task));
mutex_unlock(&durable_scavenger_lock);
}
void ksmbd_stop_durable_scavenger(void)
{
if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE))
return;
mutex_lock(&durable_scavenger_lock);
if (!durable_scavenger_running) {
mutex_unlock(&durable_scavenger_lock);
return;
}
durable_scavenger_running = false;
if (waitqueue_active(&dh_wq))
wake_up(&dh_wq);
mutex_unlock(&durable_scavenger_lock);
kthread_stop(server_conf.dh_task);
}
static bool session_fd_check(struct ksmbd_tree_connect *tcon, static bool session_fd_check(struct ksmbd_tree_connect *tcon,
struct ksmbd_file *fp) struct ksmbd_file *fp)
{ {
...@@ -757,11 +907,12 @@ void ksmbd_free_global_file_table(void) ...@@ -757,11 +907,12 @@ void ksmbd_free_global_file_table(void)
unsigned int id; unsigned int id;
idr_for_each_entry(global_ft.idr, fp, id) { idr_for_each_entry(global_ft.idr, fp, id) {
__ksmbd_remove_durable_fd(fp); ksmbd_remove_durable_fd(fp);
kmem_cache_free(filp_cache, fp); __ksmbd_close_fd(NULL, fp);
} }
ksmbd_destroy_file_table(&global_ft); idr_destroy(global_ft.idr);
kfree(global_ft.idr);
} }
int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share,
...@@ -817,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) ...@@ -817,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
} }
up_write(&ci->m_lock); up_write(&ci->m_lock);
fp->f_state = FP_NEW;
__open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
if (!has_file_id(fp->volatile_id)) { if (!has_file_id(fp->volatile_id)) {
fp->conn = NULL; fp->conn = NULL;
...@@ -856,6 +1008,8 @@ int ksmbd_init_file_cache(void) ...@@ -856,6 +1008,8 @@ int ksmbd_init_file_cache(void)
if (!filp_cache) if (!filp_cache)
goto out; goto out;
init_waitqueue_head(&dh_wq);
return 0; return 0;
out: out:
......
...@@ -153,6 +153,8 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); ...@@ -153,6 +153,8 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry); struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp); struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_launch_ksmbd_durable_scavenger(void);
void ksmbd_stop_durable_scavenger(void);
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work); void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
void ksmbd_close_session_fds(struct ksmbd_work *work); void ksmbd_close_session_fds(struct ksmbd_work *work);
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode); int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment