mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Luis Henriques <luis@igalia.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: Bernd Schubert <bernd@bsbernd.com>,
	 Laura Promberger <laura.promberger@cern.ch>,
	 Dave Chinner <david@fromorbit.com>,
	 Matt Harvey <mharvey@jumptrading.com>,
	 linux-fsdevel@vger.kernel.org, kernel-dev@igalia.com,
	 linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH v5 1/2] fuse: new work queue to periodically invalidate expired dentries
Date: Thu, 04 Sep 2025 15:00:12 +0100	[thread overview]
Message-ID: <87y0qul3mb.fsf@wotan.olymp> (raw)
In-Reply-To: <CAJfpegtfeCJgzSLOYABTaZ7Hec6JDMHpQtxDzg61jAPJcRZQZA@mail.gmail.com> (Miklos Szeredi's message of "Thu, 4 Sep 2025 12:20:46 +0200")

Hi Miklos,

On Thu, Sep 04 2025, Miklos Szeredi wrote:

> On Thu, 28 Aug 2025 at 18:30, Luis Henriques <luis@igalia.com> wrote:
>
>> +#define HASH_BITS      12
>
> Definitely too large.  My gut feeling gives 5, but it obviously
> depends on a lot of factors.

Right, to be honest I didn't spent a lot of time thinking about the
correct value for this constant.  But sure, 5 seems to be much more
reasonable.

>> +               schedule_delayed_work(&dentry_tree_work,
>> +                                     secs_to_jiffies(num));
>
> secs_to_jiffues() doesn't check overflow.  Perhaps simplest fix would
> be to constrain parameter to unsigned short.

Sounds good, thanks.

>> +MODULE_PARM_DESC(inval_wq,
>> +                "Dentries invalidation work queue period in secs (>= 5).");
>
> __stringify(FUSE_DENTRY_INVAL_FREQ_MIN)
>
>> +       if (!inval_wq && RB_EMPTY_NODE(&fd->node))
>> +               return;
>
> inval_wq can change to zero, which shouldn't prevent removing from the rbtree.

Maybe I didn't understood your comment, but isn't that what's happening
here?  If the 'fd' is in a tree, it will be removed, independently of the
'inval_wq' value.

>> +static void fuse_dentry_tree_work(struct work_struct *work)
>> +{
>> +       struct fuse_dentry *fd;
>> +       struct rb_node *node;
>> +       int i;
>> +
>> +       for (i = 0; i < HASH_SIZE; i++) {
>> +               spin_lock(&dentry_hash[i].lock);
>> +               node = rb_first(&dentry_hash[i].tree);
>> +               while (node && !need_resched()) {
>
> Wrong place.
>
>> +                       fd = rb_entry(node, struct fuse_dentry, node);
>> +                       if (time_after64(get_jiffies_64(), fd->time)) {
>> +                               rb_erase(&fd->node, &dentry_hash[i].tree);
>> +                               RB_CLEAR_NODE(&fd->node);
>> +                               spin_unlock(&dentry_hash[i].lock);
>
> cond_resched() here instead.

/me slaps himself.

>> +                               d_invalidate(fd->dentry);
>
> Okay, so I understand the reasoning: the validity timeout for the
> dentry expired, hence it's invalid.  The problem is, this is not quite
> right.  The validity timeout says "this dentry is assumed valid for
> this period", it doesn't say the dentry is invalid after the timeout.
>
> Doing d_invalidate() means we "know the dentry is invalid", which will
> get it off the hash tables, giving it a "(deleted)" tag in proc
> strings, etc.  This would be wrong.

Understood.  Thanks a lot for taking the time to explain it.  This makes
it clear that using d_invalidate() here is incorrect, of course.

> What we want here is just get rid of *unused* dentries, which don't
> have any reference.  Referenced ones will get revalidated with
> ->d_revalidate() and if one turns out to be actually invalid, it will
> then be invalidated with d_invalidate(), otherwise the timeout will
> just be reset.
>
> There doesn't seem to be a function that does this, so new
> infrastructure will need to be added to fs/dcache.c.  Exporting
> shrink_dentry_list() and to_shrink_list() would suffice, but I wonder
> if the helpers should be a little higher level.

OK, I see how the to_shrink_list() and shrink_dentry_list() pair could
easily be used here.  This would even remove the need to do the
unlock/lock in the loop.

(By the way, I considered using mutexes here instead.  Do you have any
thoughts on this?)

What I don't understand in your comment is where you suggest these helpers
could be in a higher level.  Could you elaborate on what exactly you have
in mind?

>> +void fuse_dentry_tree_cleanup(void)
>> +{
>> +       struct rb_node *n;
>> +       int i;
>> +
>> +       inval_wq = 0;
>> +       cancel_delayed_work_sync(&dentry_tree_work);
>> +
>> +       for (i = 0; i < HASH_SIZE; i++) {
>
> If we have anything in there at module remove, then something is
> horribly broken.  A WARN_ON definitely suffices here.
>
>> --- a/fs/fuse/fuse_i.h
>> +++ b/fs/fuse/fuse_i.h
>> @@ -54,6 +54,12 @@
>>  /** Frequency (in jiffies) of request timeout checks, if opted into */
>>  extern const unsigned long fuse_timeout_timer_freq;
>>
>> +/*
>> + * Dentries invalidation workqueue period, in seconds.  It shall be >= 5
>
> If we have a definition of this constant, please refer to that
> definition here too.
>
>> @@ -2045,6 +2045,10 @@ void fuse_conn_destroy(struct fuse_mount *fm)
>>
>>         fuse_abort_conn(fc);
>>         fuse_wait_aborted(fc);
>> +       /*
>> +        * XXX prune dentries:
>> +        * fuse_dentry_tree_prune(fc);
>> +        */
>
> No need.

Yeah, I wasn't totally sure this would really be required here.

And again, thanks a lot for your review, Miklos!

Cheers,
-- 
Luís

  reply	other threads:[~2025-09-04 14:00 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-28 16:29 [RFC PATCH v5 0/2] fuse: work queues to invalided dentries Luis Henriques
2025-08-28 16:29 ` [RFC PATCH v5 1/2] fuse: new work queue to periodically invalidate expired dentries Luis Henriques
2025-09-04 10:20   ` Miklos Szeredi
2025-09-04 14:00     ` Luis Henriques [this message]
2025-09-04 15:12       ` Miklos Szeredi
2025-09-04 15:30         ` Luis Henriques
2025-08-28 16:29 ` [RFC PATCH v5 2/2] fuse: new work queue to invalidate dentries from old epochs Luis Henriques
2025-09-04 10:35   ` Miklos Szeredi
2025-09-04 14:11     ` Luis Henriques
2025-09-04 14:38       ` Miklos Szeredi
2025-09-04 15:21         ` Luis Henriques

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y0qul3mb.fsf@wotan.olymp \
    --to=luis@igalia.com \
    --cc=bernd@bsbernd.com \
    --cc=david@fromorbit.com \
    --cc=kernel-dev@igalia.com \
    --cc=laura.promberger@cern.ch \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mharvey@jumptrading.com \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®