diff mbox series

cifs: Add a laundromat thread for cached directories

Message ID 20230706023224.609324-1-lsahlber@redhat.com (mailing list archive)
State New, archived
Headers show
Series cifs: Add a laundromat thread for cached directories | expand

Commit Message

Ronnie Sahlberg July 6, 2023, 2:32 a.m. UTC
and drop cached directories after 30 seconds

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 fs/smb/client/cached_dir.c | 67 ++++++++++++++++++++++++++++++++++++++
 fs/smb/client/cached_dir.h |  1 +
 2 files changed, 68 insertions(+)

Comments

Steve French July 6, 2023, 3:07 a.m. UTC | #1
updated to fix two checkpatch warnings (see attached) and tentatively
merged into for-next pending review/testing


On Wed, Jul 5, 2023 at 9:32 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> and drop cached directories after 30 seconds
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  fs/smb/client/cached_dir.c | 67 ++++++++++++++++++++++++++++++++++++++
>  fs/smb/client/cached_dir.h |  1 +
>  2 files changed, 68 insertions(+)
>
> diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> index bfc964b36c72..f567eea0a456 100644
> --- a/fs/smb/client/cached_dir.c
> +++ b/fs/smb/client/cached_dir.c
> @@ -568,6 +568,53 @@ static void free_cached_dir(struct cached_fid *cfid)
>         kfree(cfid);
>  }
>
> +static int
> +cifs_cfids_laundromat_thread(void *p)
> +{
> +       struct cached_fids *cfids = p;
> +       struct cached_fid *cfid, *q;
> +       struct list_head entry;
> +
> +       while (!kthread_should_stop()) {
> +               ssleep(1);
> +               INIT_LIST_HEAD(&entry);
> +               if (kthread_should_stop())
> +                       return 0;
> +               spin_lock(&cfids->cfid_list_lock);
> +               list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> +                       if (jiffies > cfid->time + HZ * 30) {
> +                               list_del(&cfid->entry);
> +                               list_add(&cfid->entry, &entry);
> +                               cfids->num_entries--;
> +                       }
> +               }
> +               spin_unlock(&cfids->cfid_list_lock);
> +
> +               list_for_each_entry_safe(cfid, q, &entry, entry) {
> +                       cfid->on_list = false;
> +                       list_del(&cfid->entry);
> +                       /*
> +                        * Cancel, and wait for the work to finish in
> +                        * case we are racing with it.
> +                        */
> +                       cancel_work_sync(&cfid->lease_break);
> +                       if (cfid->has_lease) {
> +                               /*
> +                                * We lease has not yet been cancelled from
> +                                * the server so we need to drop the reference.
> +                                */
> +                               spin_lock(&cfids->cfid_list_lock);
> +                               cfid->has_lease = false;
> +                               spin_unlock(&cfids->cfid_list_lock);
> +                               kref_put(&cfid->refcount, smb2_close_cached_fid);
> +                       }
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +
>  struct cached_fids *init_cached_dirs(void)
>  {
>         struct cached_fids *cfids;
> @@ -577,6 +624,20 @@ struct cached_fids *init_cached_dirs(void)
>                 return NULL;
>         spin_lock_init(&cfids->cfid_list_lock);
>         INIT_LIST_HEAD(&cfids->entries);
> +
> +       /*
> +        * since we're in a cifs function already, we know that
> +        * this will succeed. No need for try_module_get().
> +        */
> +       __module_get(THIS_MODULE);
> +       cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
> +                                 cfids, "cifsd-cfid-laundromat");
> +       if (IS_ERR(cfids->laundromat)) {
> +               cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
> +               kfree(cfids);
> +               module_put(THIS_MODULE);
> +               return NULL;
> +       }
>         return cfids;
>  }
>
> @@ -589,6 +650,12 @@ void free_cached_dirs(struct cached_fids *cfids)
>         struct cached_fid *cfid, *q;
>         LIST_HEAD(entry);
>
> +       if (cfids->laundromat) {
> +               kthread_stop(cfids->laundromat);
> +               cfids->laundromat = NULL;
> +               module_put(THIS_MODULE);
> +       }
> +
>         spin_lock(&cfids->cfid_list_lock);
>         list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
>                 cfid->on_list = false;
> diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
> index 2f4e764c9ca9..facc9b154d00 100644
> --- a/fs/smb/client/cached_dir.h
> +++ b/fs/smb/client/cached_dir.h
> @@ -57,6 +57,7 @@ struct cached_fids {
>         spinlock_t cfid_list_lock;
>         int num_entries;
>         struct list_head entries;
> +       struct task_struct *laundromat;
>  };
>
>  extern struct cached_fids *init_cached_dirs(void);
> --
> 2.35.3
>
Shyam Prasad N July 7, 2023, 5:31 a.m. UTC | #2
On Thu, Jul 6, 2023 at 8:51 AM Steve French <smfrench@gmail.com> wrote:
>
> updated to fix two checkpatch warnings (see attached) and tentatively
> merged into for-next pending review/testing
>
>
> On Wed, Jul 5, 2023 at 9:32 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
> >
> > and drop cached directories after 30 seconds
> >
> > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> > ---
> >  fs/smb/client/cached_dir.c | 67 ++++++++++++++++++++++++++++++++++++++
> >  fs/smb/client/cached_dir.h |  1 +
> >  2 files changed, 68 insertions(+)
> >
> > diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> > index bfc964b36c72..f567eea0a456 100644
> > --- a/fs/smb/client/cached_dir.c
> > +++ b/fs/smb/client/cached_dir.c
> > @@ -568,6 +568,53 @@ static void free_cached_dir(struct cached_fid *cfid)
> >         kfree(cfid);
> >  }
> >
> > +static int
> > +cifs_cfids_laundromat_thread(void *p)
> > +{
> > +       struct cached_fids *cfids = p;
> > +       struct cached_fid *cfid, *q;
> > +       struct list_head entry;
> > +
> > +       while (!kthread_should_stop()) {
> > +               ssleep(1);
> > +               INIT_LIST_HEAD(&entry);
> > +               if (kthread_should_stop())
> > +                       return 0;
> > +               spin_lock(&cfids->cfid_list_lock);
> > +               list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> > +                       if (jiffies > cfid->time + HZ * 30) {
> > +                               list_del(&cfid->entry);
> > +                               list_add(&cfid->entry, &entry);
> > +                               cfids->num_entries--;
> > +                       }
> > +               }
> > +               spin_unlock(&cfids->cfid_list_lock);
> > +
> > +               list_for_each_entry_safe(cfid, q, &entry, entry) {
> > +                       cfid->on_list = false;
> > +                       list_del(&cfid->entry);
> > +                       /*
> > +                        * Cancel, and wait for the work to finish in
> > +                        * case we are racing with it.
> > +                        */
> > +                       cancel_work_sync(&cfid->lease_break);
> > +                       if (cfid->has_lease) {
> > +                               /*
> > +                                * We lease has not yet been cancelled from
> > +                                * the server so we need to drop the reference.
> > +                                */
> > +                               spin_lock(&cfids->cfid_list_lock);
> > +                               cfid->has_lease = false;
> > +                               spin_unlock(&cfids->cfid_list_lock);
> > +                               kref_put(&cfid->refcount, smb2_close_cached_fid);
> > +                       }
> > +               }
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +
> >  struct cached_fids *init_cached_dirs(void)
> >  {
> >         struct cached_fids *cfids;
> > @@ -577,6 +624,20 @@ struct cached_fids *init_cached_dirs(void)
> >                 return NULL;
> >         spin_lock_init(&cfids->cfid_list_lock);
> >         INIT_LIST_HEAD(&cfids->entries);
> > +
> > +       /*
> > +        * since we're in a cifs function already, we know that
> > +        * this will succeed. No need for try_module_get().
> > +        */
> > +       __module_get(THIS_MODULE);
> > +       cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
> > +                                 cfids, "cifsd-cfid-laundromat");
> > +       if (IS_ERR(cfids->laundromat)) {
> > +               cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
> > +               kfree(cfids);
> > +               module_put(THIS_MODULE);
> > +               return NULL;
> > +       }
> >         return cfids;
> >  }
> >
> > @@ -589,6 +650,12 @@ void free_cached_dirs(struct cached_fids *cfids)
> >         struct cached_fid *cfid, *q;
> >         LIST_HEAD(entry);
> >
> > +       if (cfids->laundromat) {
> > +               kthread_stop(cfids->laundromat);
> > +               cfids->laundromat = NULL;
> > +               module_put(THIS_MODULE);
> > +       }
> > +
> >         spin_lock(&cfids->cfid_list_lock);
> >         list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> >                 cfid->on_list = false;
> > diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
> > index 2f4e764c9ca9..facc9b154d00 100644
> > --- a/fs/smb/client/cached_dir.h
> > +++ b/fs/smb/client/cached_dir.h
> > @@ -57,6 +57,7 @@ struct cached_fids {
> >         spinlock_t cfid_list_lock;
> >         int num_entries;
> >         struct list_head entries;
> > +       struct task_struct *laundromat;
> >  };
> >
> >  extern struct cached_fids *init_cached_dirs(void);
> > --
> > 2.35.3
> >
>
>
> --
> Thanks,
>
> Steve

Hi Ronnie,

Why do we need this?
We only cache dirents if we have the parent directory lease. As long
as we have the lease, why can't we continue to cache these?
ronnie sahlberg July 7, 2023, 5:50 a.m. UTC | #3
We can only cache a limited amount of entries.
We need to force entries to be dropped from the cache at regular
intervals to make room for potential new entries/different
directories.

Access patterns change over time and what is the "hot" directory will
also change over time so we need to drop entries to make sure that
when some directory becomes hot there will be decent chance that it
will be able to become cached.

If a directory becomes "cold" we no longer want it to take up entries
in our cache.

regards
ronnie sahlberg


On Fri, 7 Jul 2023 at 15:37, Shyam Prasad N <nspmangalore@gmail.com> wrote:
>
> On Thu, Jul 6, 2023 at 8:51 AM Steve French <smfrench@gmail.com> wrote:
> >
> > updated to fix two checkpatch warnings (see attached) and tentatively
> > merged into for-next pending review/testing
> >
> >
> > On Wed, Jul 5, 2023 at 9:32 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
> > >
> > > and drop cached directories after 30 seconds
> > >
> > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> > > ---
> > >  fs/smb/client/cached_dir.c | 67 ++++++++++++++++++++++++++++++++++++++
> > >  fs/smb/client/cached_dir.h |  1 +
> > >  2 files changed, 68 insertions(+)
> > >
> > > diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> > > index bfc964b36c72..f567eea0a456 100644
> > > --- a/fs/smb/client/cached_dir.c
> > > +++ b/fs/smb/client/cached_dir.c
> > > @@ -568,6 +568,53 @@ static void free_cached_dir(struct cached_fid *cfid)
> > >         kfree(cfid);
> > >  }
> > >
> > > +static int
> > > +cifs_cfids_laundromat_thread(void *p)
> > > +{
> > > +       struct cached_fids *cfids = p;
> > > +       struct cached_fid *cfid, *q;
> > > +       struct list_head entry;
> > > +
> > > +       while (!kthread_should_stop()) {
> > > +               ssleep(1);
> > > +               INIT_LIST_HEAD(&entry);
> > > +               if (kthread_should_stop())
> > > +                       return 0;
> > > +               spin_lock(&cfids->cfid_list_lock);
> > > +               list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> > > +                       if (jiffies > cfid->time + HZ * 30) {
> > > +                               list_del(&cfid->entry);
> > > +                               list_add(&cfid->entry, &entry);
> > > +                               cfids->num_entries--;
> > > +                       }
> > > +               }
> > > +               spin_unlock(&cfids->cfid_list_lock);
> > > +
> > > +               list_for_each_entry_safe(cfid, q, &entry, entry) {
> > > +                       cfid->on_list = false;
> > > +                       list_del(&cfid->entry);
> > > +                       /*
> > > +                        * Cancel, and wait for the work to finish in
> > > +                        * case we are racing with it.
> > > +                        */
> > > +                       cancel_work_sync(&cfid->lease_break);
> > > +                       if (cfid->has_lease) {
> > > +                               /*
> > > +                                * We lease has not yet been cancelled from
> > > +                                * the server so we need to drop the reference.
> > > +                                */
> > > +                               spin_lock(&cfids->cfid_list_lock);
> > > +                               cfid->has_lease = false;
> > > +                               spin_unlock(&cfids->cfid_list_lock);
> > > +                               kref_put(&cfid->refcount, smb2_close_cached_fid);
> > > +                       }
> > > +               }
> > > +       }
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +
> > >  struct cached_fids *init_cached_dirs(void)
> > >  {
> > >         struct cached_fids *cfids;
> > > @@ -577,6 +624,20 @@ struct cached_fids *init_cached_dirs(void)
> > >                 return NULL;
> > >         spin_lock_init(&cfids->cfid_list_lock);
> > >         INIT_LIST_HEAD(&cfids->entries);
> > > +
> > > +       /*
> > > +        * since we're in a cifs function already, we know that
> > > +        * this will succeed. No need for try_module_get().
> > > +        */
> > > +       __module_get(THIS_MODULE);
> > > +       cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
> > > +                                 cfids, "cifsd-cfid-laundromat");
> > > +       if (IS_ERR(cfids->laundromat)) {
> > > +               cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
> > > +               kfree(cfids);
> > > +               module_put(THIS_MODULE);
> > > +               return NULL;
> > > +       }
> > >         return cfids;
> > >  }
> > >
> > > @@ -589,6 +650,12 @@ void free_cached_dirs(struct cached_fids *cfids)
> > >         struct cached_fid *cfid, *q;
> > >         LIST_HEAD(entry);
> > >
> > > +       if (cfids->laundromat) {
> > > +               kthread_stop(cfids->laundromat);
> > > +               cfids->laundromat = NULL;
> > > +               module_put(THIS_MODULE);
> > > +       }
> > > +
> > >         spin_lock(&cfids->cfid_list_lock);
> > >         list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> > >                 cfid->on_list = false;
> > > diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
> > > index 2f4e764c9ca9..facc9b154d00 100644
> > > --- a/fs/smb/client/cached_dir.h
> > > +++ b/fs/smb/client/cached_dir.h
> > > @@ -57,6 +57,7 @@ struct cached_fids {
> > >         spinlock_t cfid_list_lock;
> > >         int num_entries;
> > >         struct list_head entries;
> > > +       struct task_struct *laundromat;
> > >  };
> > >
> > >  extern struct cached_fids *init_cached_dirs(void);
> > > --
> > > 2.35.3
> > >
> >
> >
> > --
> > Thanks,
> >
> > Steve
>
> Hi Ronnie,
>
> Why do we need this?
> We only cache dirents if we have the parent directory lease. As long
> as we have the lease, why can't we continue to cache these?
>
> --
> Regards,
> Shyam
Shyam Prasad N July 7, 2023, 6:37 a.m. UTC | #4
On Fri, Jul 7, 2023 at 11:20 AM ronnie sahlberg
<ronniesahlberg@gmail.com> wrote:
>
> We can only cache a limited amount of entries.
> We need to force entries to be dropped from the cache at regular
> intervals to make room for potential new entries/different
> directories.
>
> Access patterns change over time and what is the "hot" directory will
> also change over time so we need to drop entries to make sure that
> when some directory becomes hot there will be decent chance that it
> will be able to become cached.
>
> If a directory becomes "cold" we no longer want it to take up entries
> in our cache.
>

Makes sense.

However, the value of MAX_CACHED_FIDS to 16 seems very restrictive.
And as Steve suggested, 30s expiry seems very aggressive.
I think we can increase both.

Also, I was wondering how do we handle cleanup of cfids when VFS
decides to free the inode (maybe due to memory crunch?).

Regards,
Shyam

> regards
> ronnie sahlberg
>
>
> On Fri, 7 Jul 2023 at 15:37, Shyam Prasad N <nspmangalore@gmail.com> wrote:
> >
> > On Thu, Jul 6, 2023 at 8:51 AM Steve French <smfrench@gmail.com> wrote:
> > >
> > > updated to fix two checkpatch warnings (see attached) and tentatively
> > > merged into for-next pending review/testing
> > >
> > >
> > > On Wed, Jul 5, 2023 at 9:32 PM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
> > > >
> > > > and drop cached directories after 30 seconds
> > > >
> > > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> > > > ---
> > > >  fs/smb/client/cached_dir.c | 67 ++++++++++++++++++++++++++++++++++++++
> > > >  fs/smb/client/cached_dir.h |  1 +
> > > >  2 files changed, 68 insertions(+)
> > > >
> > > > diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> > > > index bfc964b36c72..f567eea0a456 100644
> > > > --- a/fs/smb/client/cached_dir.c
> > > > +++ b/fs/smb/client/cached_dir.c
> > > > @@ -568,6 +568,53 @@ static void free_cached_dir(struct cached_fid *cfid)
> > > >         kfree(cfid);
> > > >  }
> > > >
> > > > +static int
> > > > +cifs_cfids_laundromat_thread(void *p)
> > > > +{
> > > > +       struct cached_fids *cfids = p;
> > > > +       struct cached_fid *cfid, *q;
> > > > +       struct list_head entry;
> > > > +
> > > > +       while (!kthread_should_stop()) {
> > > > +               ssleep(1);
> > > > +               INIT_LIST_HEAD(&entry);
> > > > +               if (kthread_should_stop())
> > > > +                       return 0;
> > > > +               spin_lock(&cfids->cfid_list_lock);
> > > > +               list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> > > > +                       if (jiffies > cfid->time + HZ * 30) {
> > > > +                               list_del(&cfid->entry);
> > > > +                               list_add(&cfid->entry, &entry);
> > > > +                               cfids->num_entries--;
> > > > +                       }
> > > > +               }
> > > > +               spin_unlock(&cfids->cfid_list_lock);
> > > > +
> > > > +               list_for_each_entry_safe(cfid, q, &entry, entry) {
> > > > +                       cfid->on_list = false;
> > > > +                       list_del(&cfid->entry);
> > > > +                       /*
> > > > +                        * Cancel, and wait for the work to finish in
> > > > +                        * case we are racing with it.
> > > > +                        */
> > > > +                       cancel_work_sync(&cfid->lease_break);
> > > > +                       if (cfid->has_lease) {
> > > > +                               /*
> > > > +                                * We lease has not yet been cancelled from
> > > > +                                * the server so we need to drop the reference.
> > > > +                                */
> > > > +                               spin_lock(&cfids->cfid_list_lock);
> > > > +                               cfid->has_lease = false;
> > > > +                               spin_unlock(&cfids->cfid_list_lock);
> > > > +                               kref_put(&cfid->refcount, smb2_close_cached_fid);
> > > > +                       }
> > > > +               }
> > > > +       }
> > > > +
> > > > +       return 0;
> > > > +}
> > > > +
> > > > +
> > > >  struct cached_fids *init_cached_dirs(void)
> > > >  {
> > > >         struct cached_fids *cfids;
> > > > @@ -577,6 +624,20 @@ struct cached_fids *init_cached_dirs(void)
> > > >                 return NULL;
> > > >         spin_lock_init(&cfids->cfid_list_lock);
> > > >         INIT_LIST_HEAD(&cfids->entries);
> > > > +
> > > > +       /*
> > > > +        * since we're in a cifs function already, we know that
> > > > +        * this will succeed. No need for try_module_get().
> > > > +        */
> > > > +       __module_get(THIS_MODULE);
> > > > +       cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
> > > > +                                 cfids, "cifsd-cfid-laundromat");
> > > > +       if (IS_ERR(cfids->laundromat)) {
> > > > +               cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
> > > > +               kfree(cfids);
> > > > +               module_put(THIS_MODULE);
> > > > +               return NULL;
> > > > +       }
> > > >         return cfids;
> > > >  }
> > > >
> > > > @@ -589,6 +650,12 @@ void free_cached_dirs(struct cached_fids *cfids)
> > > >         struct cached_fid *cfid, *q;
> > > >         LIST_HEAD(entry);
> > > >
> > > > +       if (cfids->laundromat) {
> > > > +               kthread_stop(cfids->laundromat);
> > > > +               cfids->laundromat = NULL;
> > > > +               module_put(THIS_MODULE);
> > > > +       }
> > > > +
> > > >         spin_lock(&cfids->cfid_list_lock);
> > > >         list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
> > > >                 cfid->on_list = false;
> > > > diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
> > > > index 2f4e764c9ca9..facc9b154d00 100644
> > > > --- a/fs/smb/client/cached_dir.h
> > > > +++ b/fs/smb/client/cached_dir.h
> > > > @@ -57,6 +57,7 @@ struct cached_fids {
> > > >         spinlock_t cfid_list_lock;
> > > >         int num_entries;
> > > >         struct list_head entries;
> > > > +       struct task_struct *laundromat;
> > > >  };
> > > >
> > > >  extern struct cached_fids *init_cached_dirs(void);
> > > > --
> > > > 2.35.3
> > > >
> > >
> > >
> > > --
> > > Thanks,
> > >
> > > Steve
> >
> > Hi Ronnie,
> >
> > Why do we need this?
> > We only cache dirents if we have the parent directory lease. As long
> > as we have the lease, why can't we continue to cache these?
> >
> > --
> > Regards,
> > Shyam
ronnie sahlberg July 7, 2023, 6:41 a.m. UTC | #5
On Fri, 7 Jul 2023 at 16:37, Shyam Prasad N <nspmangalore@gmail.com> wrote:
>
> On Fri, Jul 7, 2023 at 11:20 AM ronnie sahlberg
> <ronniesahlberg@gmail.com> wrote:
> >
> > We can only cache a limited amount of entries.
> > We need to force entries to be dropped from the cache at regular
> > intervals to make room for potential new entries/different
> > directories.
> >
> > Access patterns change over time and what is the "hot" directory will
> > also change over time so we need to drop entries to make sure that
> > when some directory becomes hot there will be decent chance that it
> > will be able to become cached.
> >
> > If a directory becomes "cold" we no longer want it to take up entries
> > in our cache.
> >
>
> Makes sense.
>
> However, the value of MAX_CACHED_FIDS to 16 seems very restrictive.
> And as Steve suggested, 30s expiry seems very aggressive.
> I think we can increase both.

We can and should increase it at some stage but lets keep it small and
short for now until we feel confident it is all stable.
Once we are confident it is good we can increase these quite a bit.
Steve French July 7, 2023, 4:17 p.m. UTC | #6
On Fri, Jul 7, 2023 at 1:37 AM Shyam Prasad N <nspmangalore@gmail.com> wrote:
>
> On Fri, Jul 7, 2023 at 11:20 AM ronnie sahlberg
> <ronniesahlberg@gmail.com> wrote:
> >
> > We can only cache a limited amount of entries.
> > We need to force entries to be dropped from the cache at regular
> > intervals to make room for potential new entries/different
> > directories.
> >
> > Access patterns change over time and what is the "hot" directory will
> > also change over time so we need to drop entries to make sure that
> > when some directory becomes hot there will be decent chance that it
> > will be able to become cached.
> >
> > If a directory becomes "cold" we no longer want it to take up entries
> > in our cache.
> >
>
> Makes sense.
>
> However, the value of MAX_CACHED_FIDS to 16 seems very restrictive.
> And as Steve suggested, 30s expiry seems very aggressive.
> I think we can increase both.

At least for the short term we can make this configurable (which will
make it easier to test the best default values in the long run) e.g.
via mount parm.   Will make it much easier to experiment to optimize
the value
diff mbox series

Patch

diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index bfc964b36c72..f567eea0a456 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -568,6 +568,53 @@  static void free_cached_dir(struct cached_fid *cfid)
 	kfree(cfid);
 }
 
+static int
+cifs_cfids_laundromat_thread(void *p)
+{
+	struct cached_fids *cfids = p;
+	struct cached_fid *cfid, *q;
+	struct list_head entry;
+
+	while (!kthread_should_stop()) {
+		ssleep(1);
+		INIT_LIST_HEAD(&entry);
+		if (kthread_should_stop())
+			return 0;
+		spin_lock(&cfids->cfid_list_lock);
+		list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
+			if (jiffies > cfid->time + HZ * 30) {
+				list_del(&cfid->entry);
+				list_add(&cfid->entry, &entry);
+				cfids->num_entries--;
+			}
+		}
+		spin_unlock(&cfids->cfid_list_lock);
+
+		list_for_each_entry_safe(cfid, q, &entry, entry) {
+			cfid->on_list = false;
+			list_del(&cfid->entry);
+			/*
+			 * Cancel, and wait for the work to finish in
+			 * case we are racing with it.
+			 */
+			cancel_work_sync(&cfid->lease_break);
+			if (cfid->has_lease) {
+				/*
+				 * We lease has not yet been cancelled from
+				 * the server so we need to drop the reference.
+				 */
+				spin_lock(&cfids->cfid_list_lock);
+				cfid->has_lease = false;
+				spin_unlock(&cfids->cfid_list_lock);
+				kref_put(&cfid->refcount, smb2_close_cached_fid);
+			}
+		}
+	}
+
+	return 0;
+}
+
+
 struct cached_fids *init_cached_dirs(void)
 {
 	struct cached_fids *cfids;
@@ -577,6 +624,20 @@  struct cached_fids *init_cached_dirs(void)
 		return NULL;
 	spin_lock_init(&cfids->cfid_list_lock);
 	INIT_LIST_HEAD(&cfids->entries);
+
+	/*
+	 * since we're in a cifs function already, we know that
+	 * this will succeed. No need for try_module_get().
+	 */
+	__module_get(THIS_MODULE);
+	cfids->laundromat = kthread_run(cifs_cfids_laundromat_thread,
+				  cfids, "cifsd-cfid-laundromat");
+	if (IS_ERR(cfids->laundromat)) {
+		cifs_dbg(VFS, "Failed to start cfids laundromat thread.\n");
+		kfree(cfids);
+		module_put(THIS_MODULE);
+		return NULL;
+	}
 	return cfids;
 }
 
@@ -589,6 +650,12 @@  void free_cached_dirs(struct cached_fids *cfids)
 	struct cached_fid *cfid, *q;
 	LIST_HEAD(entry);
 
+	if (cfids->laundromat) {
+		kthread_stop(cfids->laundromat);
+		cfids->laundromat = NULL;
+		module_put(THIS_MODULE);
+	}
+	
 	spin_lock(&cfids->cfid_list_lock);
 	list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
 		cfid->on_list = false;
diff --git a/fs/smb/client/cached_dir.h b/fs/smb/client/cached_dir.h
index 2f4e764c9ca9..facc9b154d00 100644
--- a/fs/smb/client/cached_dir.h
+++ b/fs/smb/client/cached_dir.h
@@ -57,6 +57,7 @@  struct cached_fids {
 	spinlock_t cfid_list_lock;
 	int num_entries;
 	struct list_head entries;
+	struct task_struct *laundromat;
 };
 
 extern struct cached_fids *init_cached_dirs(void);