]> Git Repo - J-linux.git/commitdiff
ksmbd: add durable scavenger timer
authorNamjae Jeon <[email protected]>
Sun, 14 Jul 2024 23:29:39 +0000 (08:29 +0900)
committerSteve French <[email protected]>
Mon, 15 Jul 2024 02:45:40 +0000 (21:45 -0500)
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: Namjae Jeon <[email protected]>
Signed-off-by: Steve French <[email protected]>
fs/smb/server/mgmt/user_session.c
fs/smb/server/server.c
fs/smb/server/server.h
fs/smb/server/smb2pdu.c
fs/smb/server/smb2pdu.h
fs/smb/server/vfs_cache.c
fs/smb/server/vfs_cache.h

index aec0a7a124052a43700e331d93acaafa76bc4392..162a12685d2c956222eae5438c8887afe3711c20 100644 (file)
@@ -149,6 +149,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
 
        ksmbd_tree_conn_session_logoff(sess);
        ksmbd_destroy_file_table(&sess->file_table);
+       ksmbd_launch_ksmbd_durable_scavenger();
        ksmbd_session_rpc_clear_list(sess);
        free_channel_list(sess);
        kfree(sess->Preauth_HashValue);
@@ -326,6 +327,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
 
        ksmbd_destroy_file_table(&prev_sess->file_table);
        prev_sess->state = SMB2_SESSION_EXPIRED;
+       ksmbd_launch_ksmbd_durable_scavenger();
 out:
        up_write(&conn->session_lock);
        up_write(&sessions_table_lock);
index c67fbc8d6683ef957b2b39601031c0aa25d22ac7..4d24cc105ef6b59f34d693545ec22a1f7ed51012 100644 (file)
@@ -377,6 +377,7 @@ static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
 {
        ksmbd_ipc_soft_reset();
        ksmbd_conn_transport_destroy();
+       ksmbd_stop_durable_scavenger();
        server_conf_free();
        server_conf_init();
        WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
index db727818176038e23d8e1ed8025606501feabc64..4fc529335271f7eac52c93e3978e9e259b9e6d82 100644 (file)
@@ -44,6 +44,7 @@ struct ksmbd_server_config {
        unsigned int            max_connections;
 
        char                    *conf[SERVER_CONF_WORK_GROUP + 1];
+       struct task_struct      *dh_task;
 };
 
 extern struct ksmbd_server_config server_conf;
index 840c71c66b30b180eaafe2bf6884621e3f2bfdc3..37a39ab4ee6543fbec2adb6dcb5fdfef93492e8d 100644 (file)
@@ -3526,7 +3526,7 @@ int smb2_open(struct ksmbd_work *work)
                                        SMB2_CREATE_GUID_SIZE);
                        if (dh_info.timeout)
                                fp->durable_timeout = min(dh_info.timeout,
-                                               300000);
+                                               DURABLE_HANDLE_MAX_TIMEOUT);
                        else
                                fp->durable_timeout = 60;
                }
index 643f5e1cfe3570ef9f9eae4ca7c3bb7cfd6adbd5..3be7d5ae65a807dc9e4c880c9db71599155d76cd 100644 (file)
@@ -72,6 +72,8 @@ struct create_durable_req_v2 {
        __u8 CreateGuid[16];
 } __packed;
 
+#define DURABLE_HANDLE_MAX_TIMEOUT     300000
+
 struct create_durable_reconn_req {
        struct create_context_hdr ccontext;
        __u8   Name[8];
index baf7f67ec21234c400db5b77034f06a3981d2d67..4d4ee696e37cdfa2e9b10ca66498beb52a3660e6 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/filelock.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include "glob.h"
 #include "vfs_cache.h"
@@ -17,6 +19,7 @@
 #include "mgmt/tree_connect.h"
 #include "mgmt/user_session.h"
 #include "smb_common.h"
+#include "server.h"
 
 #define S_DEL_PENDING                  1
 #define S_DEL_ON_CLS                   2
@@ -31,6 +34,10 @@ static struct ksmbd_file_table global_ft;
 static atomic_long_t fd_limit;
 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)
 {
        limit = min(limit, get_max_files());
@@ -280,9 +287,16 @@ static void __ksmbd_remove_durable_fd(struct ksmbd_file *fp)
        if (!has_file_id(fp->persistent_id))
                return;
 
-       write_lock(&global_ft.lock);
        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);
+       if (waitqueue_active(&dh_wq))
+               wake_up(&dh_wq);
 }
 
 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)
        struct ksmbd_lock *smb_lock, *tmp_lock;
 
        fd_limit_close();
-       __ksmbd_remove_durable_fd(fp);
+       ksmbd_remove_durable_fd(fp);
        if (ft)
                __ksmbd_remove_fd(ft, fp);
 
@@ -697,6 +711,142 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *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,
                             struct ksmbd_file *fp)
 {
@@ -757,11 +907,12 @@ void ksmbd_free_global_file_table(void)
        unsigned int            id;
 
        idr_for_each_entry(global_ft.idr, fp, id) {
-               __ksmbd_remove_durable_fd(fp);
-               kmem_cache_free(filp_cache, fp);
+               ksmbd_remove_durable_fd(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,
@@ -817,6 +968,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
        }
        up_write(&ci->m_lock);
 
+       fp->f_state = FP_NEW;
        __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID);
        if (!has_file_id(fp->volatile_id)) {
                fp->conn = NULL;
@@ -856,6 +1008,8 @@ int ksmbd_init_file_cache(void)
        if (!filp_cache)
                goto out;
 
+       init_waitqueue_head(&dh_wq);
+
        return 0;
 
 out:
index f2ab1514e81a7901e25a0af7b7ebda5bc6cec4ec..b0f6d0f94cb8dee3113f03b5a9fe4e1af331854f 100644 (file)
@@ -153,6 +153,8 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
 struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
 unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
 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_session_fds(struct ksmbd_work *work);
 int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
This page took 0.079973 seconds and 4 git commands to generate.