Re: [PATCH 2/3] ksmbd: add durable scavenger timer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Minor compile warning was generated by this:

/home/smfrench/smb3-kernel/fs/smb/server/vfs_cache.c:39:19: warning:
symbol 'dh_task' was not declared. Should it be static?
/home/smfrench/smb3-kernel/fs/smb/server/vfs_cache.c:40:19: warning:
symbol 'dh_wq' was not declared. Should it be static?

On Mon, Jun 10, 2024 at 9:14 AM Namjae Jeon <linkinjeon@xxxxxxxxxx> wrote:
>
> 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 <linkinjeon@xxxxxxxxxx>
> ---
>  fs/smb/server/mgmt/user_session.c |   2 +
>  fs/smb/server/server.c            |   1 +
>  fs/smb/server/server.h            |   1 +
>  fs/smb/server/smb2pdu.c           |   2 +-
>  fs/smb/server/smb2pdu.h           |   2 +
>  fs/smb/server/vfs_cache.c         | 165 +++++++++++++++++++++++++++++-
>  fs/smb/server/vfs_cache.h         |   2 +
>  7 files changed, 169 insertions(+), 6 deletions(-)
>
> diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
> index aec0a7a12405..162a12685d2c 100644
> --- a/fs/smb/server/mgmt/user_session.c
> +++ b/fs/smb/server/mgmt/user_session.c
> @@ -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);
> diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
> index c67fbc8d6683..4d24cc105ef6 100644
> --- a/fs/smb/server/server.c
> +++ b/fs/smb/server/server.c
> @@ -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);
> diff --git a/fs/smb/server/server.h b/fs/smb/server/server.h
> index db7278181760..4fc529335271 100644
> --- a/fs/smb/server/server.h
> +++ b/fs/smb/server/server.h
> @@ -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;
> diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
> index b6c5a8ea3887..4fb5070d3dc5 100644
> --- a/fs/smb/server/smb2pdu.c
> +++ b/fs/smb/server/smb2pdu.c
> @@ -3519,7 +3519,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;
>                 }
> diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
> index 643f5e1cfe35..3be7d5ae65a8 100644
> --- a/fs/smb/server/smb2pdu.h
> +++ b/fs/smb/server/smb2pdu.h
> @@ -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];
> diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
> index a6804545db28..882a87f9e3ab 100644
> --- a/fs/smb/server/vfs_cache.c
> +++ b/fs/smb/server/vfs_cache.c
> @@ -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,11 @@ 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);
> +struct task_struc *dh_task;
> +wait_queue_head_t dh_wq;
> +
>  void ksmbd_set_fd_limit(unsigned long limit)
>  {
>         limit = min(limit, get_max_files());
> @@ -279,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)
> @@ -304,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);
>
> @@ -696,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)
>  {
> @@ -756,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,
> @@ -816,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;
> @@ -855,6 +1008,8 @@ int ksmbd_init_file_cache(void)
>         if (!filp_cache)
>                 goto out;
>
> +       init_waitqueue_head(&dh_wq);
> +
>         return 0;
>
>  out:
> diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
> index f2ab1514e81a..b0f6d0f94cb8 100644
> --- a/fs/smb/server/vfs_cache.h
> +++ b/fs/smb/server/vfs_cache.h
> @@ -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);
> --
> 2.25.1
>


-- 
Thanks,

Steve





[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux