On Thu, 28 Aug 2025 at 18:30, Luis Henriques <luis@xxxxxxxxxx> wrote: > +#define HASH_BITS 12 Definitely too large. My gut feeling gives 5, but it obviously depends on a lot of factors. > + 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. > +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. > +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. > + 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. 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. > +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. Thanks, Miklos