* [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> @ 2025-09-02 14:41 Miklos Szeredi 2025-09-02 14:41 ` [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() Miklos Szeredi ` (3 more replies) 0 siblings, 4 replies; 11+ messages in thread From: Miklos Szeredi @ 2025-09-02 14:41 UTC (permalink / raw) To: linux-fsdevel; +Cc: Jim Harris Constants that change value from version to version have no place in an interface definition. Hopefully this won't break anything. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> --- include/uapi/linux/fuse.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 6b9fb8b08768..30bf0846547f 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -680,7 +680,6 @@ enum fuse_notify_code { FUSE_NOTIFY_DELETE = 6, FUSE_NOTIFY_RESEND = 7, FUSE_NOTIFY_INC_EPOCH = 8, - FUSE_NOTIFY_CODE_MAX, }; /* The read buffer is required to be at least 8k, but may be much larger */ -- 2.49.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() 2025-09-02 14:41 [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Miklos Szeredi @ 2025-09-02 14:41 ` Miklos Szeredi 2025-09-02 21:48 ` Joanne Koong 2025-09-02 14:41 ` [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() " Miklos Szeredi ` (2 subsequent siblings) 3 siblings, 1 reply; 11+ messages in thread From: Miklos Szeredi @ 2025-09-02 14:41 UTC (permalink / raw) To: linux-fsdevel; +Cc: Jim Harris, stable In case of FUSE_NOTIFY_RESEND and FUSE_NOTIFY_INC_EPOCH fuse_copy_finish() isn't called. Fix by always calling fuse_copy_finish() after fuse_notify(). It's a no-op if called a second time. Fixes: 760eac73f9f6 ("fuse: Introduce a new notification type for resend pending requests") Fixes: 2396356a945b ("fuse: add more control over cache invalidation behaviour") Cc: <stable@vger.kernel.org> # v6.9 Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> --- fs/fuse/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index df793003eb0c..85d05a5e40e9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2178,7 +2178,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, */ if (!oh.unique) { err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs); - goto out; + goto copy_finish; } err = -EINVAL; -- 2.49.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() 2025-09-02 14:41 ` [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() Miklos Szeredi @ 2025-09-02 21:48 ` Joanne Koong 0 siblings, 0 replies; 11+ messages in thread From: Joanne Koong @ 2025-09-02 21:48 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel, Jim Harris, stable On Tue, Sep 2, 2025 at 7:44 AM Miklos Szeredi <mszeredi@redhat.com> wrote: > > In case of FUSE_NOTIFY_RESEND and FUSE_NOTIFY_INC_EPOCH fuse_copy_finish() > isn't called. > > Fix by always calling fuse_copy_finish() after fuse_notify(). It's a no-op > if called a second time. > > Fixes: 760eac73f9f6 ("fuse: Introduce a new notification type for resend pending requests") > Fixes: 2396356a945b ("fuse: add more control over cache invalidation behaviour") > Cc: <stable@vger.kernel.org> # v6.9 > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Joanne Koong <joannelkoong@gmail.com> > --- > fs/fuse/dev.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index df793003eb0c..85d05a5e40e9 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -2178,7 +2178,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, > */ > if (!oh.unique) { > err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), cs); > - goto out; > + goto copy_finish; > } > > err = -EINVAL; > -- > 2.49.0 > > ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() in fuse_notify() 2025-09-02 14:41 [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Miklos Szeredi 2025-09-02 14:41 ` [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() Miklos Szeredi @ 2025-09-02 14:41 ` Miklos Szeredi 2025-09-02 21:53 ` Joanne Koong 2025-09-03 10:25 ` Luis Henriques 2025-09-02 14:41 ` [PATCH 4/4] fuse: add prune notification Miklos Szeredi 2025-09-02 21:31 ` [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Joanne Koong 3 siblings, 2 replies; 11+ messages in thread From: Miklos Szeredi @ 2025-09-02 14:41 UTC (permalink / raw) To: linux-fsdevel; +Cc: Jim Harris Remove tail calls of fuse_copy_finish(), since it's now done from fuse_dev_do_write(). No functional change. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> --- fs/fuse/dev.c | 79 +++++++++++++++------------------------------------ 1 file changed, 23 insertions(+), 56 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 85d05a5e40e9..1258acee9704 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1622,35 +1622,31 @@ static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size, struct fuse_copy_state *cs) { struct fuse_notify_poll_wakeup_out outarg; - int err = -EINVAL; + int err; if (size != sizeof(outarg)) - goto err; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto err; + return err; fuse_copy_finish(cs); return fuse_notify_poll_wakeup(fc, &outarg); - -err: - fuse_copy_finish(cs); - return err; } static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, struct fuse_copy_state *cs) { struct fuse_notify_inval_inode_out outarg; - int err = -EINVAL; + int err; if (size != sizeof(outarg)) - goto err; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto err; + return err; fuse_copy_finish(cs); down_read(&fc->killsb); @@ -1658,10 +1654,6 @@ static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, outarg.off, outarg.len); up_read(&fc->killsb); return err; - -err: - fuse_copy_finish(cs); - return err; } static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, @@ -1669,29 +1661,26 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, { struct fuse_notify_inval_entry_out outarg; int err; - char *buf = NULL; + char *buf; struct qstr name; - err = -EINVAL; if (size < sizeof(outarg)) - goto err; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto err; + return err; - err = -ENAMETOOLONG; if (outarg.namelen > fc->name_max) - goto err; + return -ENAMETOOLONG; err = -EINVAL; if (size != sizeof(outarg) + outarg.namelen + 1) - goto err; + return -EINVAL; - err = -ENOMEM; buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); if (!buf) - goto err; + return -ENOMEM; name.name = buf; name.len = outarg.namelen; @@ -1704,12 +1693,8 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, down_read(&fc->killsb); err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags); up_read(&fc->killsb); - kfree(buf); - return err; - err: kfree(buf); - fuse_copy_finish(cs); return err; } @@ -1718,29 +1703,25 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, { struct fuse_notify_delete_out outarg; int err; - char *buf = NULL; + char *buf; struct qstr name; - err = -EINVAL; if (size < sizeof(outarg)) - goto err; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto err; + return err; - err = -ENAMETOOLONG; if (outarg.namelen > fc->name_max) - goto err; + return -ENAMETOOLONG; - err = -EINVAL; if (size != sizeof(outarg) + outarg.namelen + 1) - goto err; + return -EINVAL; - err = -ENOMEM; buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); if (!buf) - goto err; + return -ENOMEM; name.name = buf; name.len = outarg.namelen; @@ -1753,12 +1734,8 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, down_read(&fc->killsb); err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0); up_read(&fc->killsb); - kfree(buf); - return err; - err: kfree(buf); - fuse_copy_finish(cs); return err; } @@ -1776,17 +1753,15 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, loff_t file_size; loff_t end; - err = -EINVAL; if (size < sizeof(outarg)) - goto out_finish; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto out_finish; + return err; - err = -EINVAL; if (size - sizeof(outarg) != outarg.size) - goto out_finish; + return -EINVAL; nodeid = outarg.nodeid; @@ -1846,8 +1821,6 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, iput(inode); out_up_killsb: up_read(&fc->killsb); -out_finish: - fuse_copy_finish(cs); return err; } @@ -1962,13 +1935,12 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, u64 nodeid; int err; - err = -EINVAL; if (size != sizeof(outarg)) - goto copy_finish; + return -EINVAL; err = fuse_copy_one(cs, &outarg, sizeof(outarg)); if (err) - goto copy_finish; + return err; fuse_copy_finish(cs); @@ -1984,10 +1956,6 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, up_read(&fc->killsb); return err; - -copy_finish: - fuse_copy_finish(cs); - return err; } /* @@ -2098,7 +2066,6 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, return fuse_notify_inc_epoch(fc); default: - fuse_copy_finish(cs); return -EINVAL; } } -- 2.49.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() in fuse_notify() 2025-09-02 14:41 ` [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() " Miklos Szeredi @ 2025-09-02 21:53 ` Joanne Koong 2025-09-03 10:25 ` Luis Henriques 1 sibling, 0 replies; 11+ messages in thread From: Joanne Koong @ 2025-09-02 21:53 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel, Jim Harris On Tue, Sep 2, 2025 at 7:44 AM Miklos Szeredi <mszeredi@redhat.com> wrote: > > Remove tail calls of fuse_copy_finish(), since it's now done from > fuse_dev_do_write(). > > No functional change. > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Joanne Koong <joannelkoong@gmail.com> > --- > fs/fuse/dev.c | 79 +++++++++++++++------------------------------------ > 1 file changed, 23 insertions(+), 56 deletions(-) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index 85d05a5e40e9..1258acee9704 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -1622,35 +1622,31 @@ static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size, > struct fuse_copy_state *cs) > { > struct fuse_notify_poll_wakeup_out outarg; > - int err = -EINVAL; > + int err; > > if (size != sizeof(outarg)) > - goto err; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto err; > + return err; > > fuse_copy_finish(cs); Maybe worth also removing fuse_copy_finish() here (and for the other notify handlers) since it's going to get called anyways? Thanks, Joanne > return fuse_notify_poll_wakeup(fc, &outarg); > - ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() in fuse_notify() 2025-09-02 14:41 ` [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() " Miklos Szeredi 2025-09-02 21:53 ` Joanne Koong @ 2025-09-03 10:25 ` Luis Henriques 2025-09-03 10:43 ` Miklos Szeredi 1 sibling, 1 reply; 11+ messages in thread From: Luis Henriques @ 2025-09-03 10:25 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel, Jim Harris On Tue, Sep 02 2025, Miklos Szeredi wrote: > Remove tail calls of fuse_copy_finish(), since it's now done from > fuse_dev_do_write(). > > No functional change. > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> > --- > fs/fuse/dev.c | 79 +++++++++++++++------------------------------------ > 1 file changed, 23 insertions(+), 56 deletions(-) > > diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c > index 85d05a5e40e9..1258acee9704 100644 > --- a/fs/fuse/dev.c > +++ b/fs/fuse/dev.c > @@ -1622,35 +1622,31 @@ static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size, > struct fuse_copy_state *cs) > { > struct fuse_notify_poll_wakeup_out outarg; > - int err = -EINVAL; > + int err; > > if (size != sizeof(outarg)) > - goto err; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto err; > + return err; > > fuse_copy_finish(cs); > return fuse_notify_poll_wakeup(fc, &outarg); > - > -err: > - fuse_copy_finish(cs); > - return err; > } > > static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, > struct fuse_copy_state *cs) > { > struct fuse_notify_inval_inode_out outarg; > - int err = -EINVAL; > + int err; > > if (size != sizeof(outarg)) > - goto err; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto err; > + return err; > fuse_copy_finish(cs); I wonder if these extra fuse_copy_finish() calls should also be removed. It doesn't seem to be a problem to call it twice, but maybe it's not needed, or am I missing something? This happens in a few places. Other than that, and FWIW, the series look good to me. Cheers, -- Luís > > down_read(&fc->killsb); > @@ -1658,10 +1654,6 @@ static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, > outarg.off, outarg.len); > up_read(&fc->killsb); > return err; > - > -err: > - fuse_copy_finish(cs); > - return err; > } > > static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, > @@ -1669,29 +1661,26 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, > { > struct fuse_notify_inval_entry_out outarg; > int err; > - char *buf = NULL; > + char *buf; > struct qstr name; > > - err = -EINVAL; > if (size < sizeof(outarg)) > - goto err; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto err; > + return err; > > - err = -ENAMETOOLONG; > if (outarg.namelen > fc->name_max) > - goto err; > + return -ENAMETOOLONG; > > err = -EINVAL; > if (size != sizeof(outarg) + outarg.namelen + 1) > - goto err; > + return -EINVAL; > > - err = -ENOMEM; > buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); > if (!buf) > - goto err; > + return -ENOMEM; > > name.name = buf; > name.len = outarg.namelen; > @@ -1704,12 +1693,8 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, > down_read(&fc->killsb); > err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags); > up_read(&fc->killsb); > - kfree(buf); > - return err; > - > err: > kfree(buf); > - fuse_copy_finish(cs); > return err; > } > > @@ -1718,29 +1703,25 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, > { > struct fuse_notify_delete_out outarg; > int err; > - char *buf = NULL; > + char *buf; > struct qstr name; > > - err = -EINVAL; > if (size < sizeof(outarg)) > - goto err; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto err; > + return err; > > - err = -ENAMETOOLONG; > if (outarg.namelen > fc->name_max) > - goto err; > + return -ENAMETOOLONG; > > - err = -EINVAL; > if (size != sizeof(outarg) + outarg.namelen + 1) > - goto err; > + return -EINVAL; > > - err = -ENOMEM; > buf = kzalloc(outarg.namelen + 1, GFP_KERNEL); > if (!buf) > - goto err; > + return -ENOMEM; > > name.name = buf; > name.len = outarg.namelen; > @@ -1753,12 +1734,8 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size, > down_read(&fc->killsb); > err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0); > up_read(&fc->killsb); > - kfree(buf); > - return err; > - > err: > kfree(buf); > - fuse_copy_finish(cs); > return err; > } > > @@ -1776,17 +1753,15 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, > loff_t file_size; > loff_t end; > > - err = -EINVAL; > if (size < sizeof(outarg)) > - goto out_finish; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto out_finish; > + return err; > > - err = -EINVAL; > if (size - sizeof(outarg) != outarg.size) > - goto out_finish; > + return -EINVAL; > > nodeid = outarg.nodeid; > > @@ -1846,8 +1821,6 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size, > iput(inode); > out_up_killsb: > up_read(&fc->killsb); > -out_finish: > - fuse_copy_finish(cs); > return err; > } > > @@ -1962,13 +1935,12 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, > u64 nodeid; > int err; > > - err = -EINVAL; > if (size != sizeof(outarg)) > - goto copy_finish; > + return -EINVAL; > > err = fuse_copy_one(cs, &outarg, sizeof(outarg)); > if (err) > - goto copy_finish; > + return err; > > fuse_copy_finish(cs); > > @@ -1984,10 +1956,6 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, > up_read(&fc->killsb); > > return err; > - > -copy_finish: > - fuse_copy_finish(cs); > - return err; > } > > /* > @@ -2098,7 +2066,6 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, > return fuse_notify_inc_epoch(fc); > > default: > - fuse_copy_finish(cs); > return -EINVAL; > } > } > -- > 2.49.0 > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() in fuse_notify() 2025-09-03 10:25 ` Luis Henriques @ 2025-09-03 10:43 ` Miklos Szeredi 0 siblings, 0 replies; 11+ messages in thread From: Miklos Szeredi @ 2025-09-03 10:43 UTC (permalink / raw) To: Luis Henriques; +Cc: Miklos Szeredi, linux-fsdevel, Jim Harris On Wed, 3 Sept 2025 at 12:26, Luis Henriques <luis@igalia.com> wrote: > I wonder if these extra fuse_copy_finish() calls should also be removed. > It doesn't seem to be a problem to call it twice, but maybe it's not > needed, or am I missing something? This happens in a few places. It's not a clear no-op, since the put_page() for the userspace buffer is being moved to after processing the notification. I don't think this should cause problems, but it's something that I wouldn't like to do without a bit of thought. Thanks, Miklos ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/4] fuse: add prune notification 2025-09-02 14:41 [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Miklos Szeredi 2025-09-02 14:41 ` [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() Miklos Szeredi 2025-09-02 14:41 ` [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() " Miklos Szeredi @ 2025-09-02 14:41 ` Miklos Szeredi 2025-09-02 22:40 ` Joanne Koong 2025-09-04 21:07 ` Jim Harris 2025-09-02 21:31 ` [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Joanne Koong 3 siblings, 2 replies; 11+ messages in thread From: Miklos Szeredi @ 2025-09-02 14:41 UTC (permalink / raw) To: linux-fsdevel; +Cc: Jim Harris Some fuse servers need to prune their caches, which can only be done if the kernel's own dentry/inode caches are pruned first to avoid dangling references. Add FUSE_NOTIFY_PRUNE, which takes an array of node ID's to try and get rid of. Inodes with active references are skipped. A similar functionality is already provided by FUSE_NOTIFY_INVAL_ENTRY with the FUSE_EXPIRE_ONLY flag. Differences in the interface are FUSE_NOTIFY_INVAL_ENTRY: - can only prune one dentry - dentry is determined by parent ID and name - if inode has multiple aliases (cached hard links), then they would have to be invalidated individually to be able to get rid of the inode FUSE_NOTIFY_PRUNE: - can prune multiple inodes - inodes determined by their node ID - aliases are taken care of automatically Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> --- fs/fuse/dev.c | 39 +++++++++++++++++++++++++++++++++++++++ fs/fuse/fuse_i.h | 6 ++++++ fs/fuse/inode.c | 11 +++++++++++ include/uapi/linux/fuse.h | 8 ++++++++ 4 files changed, 64 insertions(+) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 1258acee9704..4229b38546bb 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2034,6 +2034,42 @@ static int fuse_notify_inc_epoch(struct fuse_conn *fc) return 0; } +static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size, + struct fuse_copy_state *cs) +{ + struct fuse_notify_prune_out outarg; + const unsigned int batch = 512; + u64 *nodeids __free(kfree) = kmalloc(sizeof(u64) * batch, GFP_KERNEL); + unsigned int num, i; + int err; + + if (!nodeids) + return -ENOMEM; + + if (size < sizeof(outarg)) + return -EINVAL; + + err = fuse_copy_one(cs, &outarg, sizeof(outarg)); + if (err) + return err; + + if (size - sizeof(outarg) != outarg.count * sizeof(u64)) + return -EINVAL; + + for (; outarg.count; outarg.count -= num) { + num = min(batch, outarg.count); + err = fuse_copy_one(cs, nodeids, num * sizeof(u64)); + if (err) + return err; + + scoped_guard(rwsem_read, &fc->killsb) { + for (i = 0; i < num; i++) + fuse_try_prune_one_inode(fc, nodeids[i]); + } + } + return 0; +} + static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, unsigned int size, struct fuse_copy_state *cs) { @@ -2065,6 +2101,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, case FUSE_NOTIFY_INC_EPOCH: return fuse_notify_inc_epoch(fc); + case FUSE_NOTIFY_PRUNE: + return fuse_notify_prune(fc, size, cs); + default: return -EINVAL; } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 233c6111f768..fb6604120b53 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1413,6 +1413,12 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid, int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, u64 child_nodeid, struct qstr *name, u32 flags); +/* + * Try to prune this inode. If neither the inode itself nor dentries associated + * with this inode have any external reference, then the inode can be freed. + */ +void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid); + int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, bool isdir); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5b7897bf7e45..a4d361b34d06 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -585,6 +585,17 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid, return 0; } +void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid) +{ + struct inode *inode; + + inode = fuse_ilookup(fc, nodeid, NULL); + if (!inode) + return; + d_prune_aliases(inode); + iput(inode); +} + bool fuse_lock_inode(struct inode *inode) { bool locked = false; diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 30bf0846547f..c13e1f9a2f12 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -239,6 +239,7 @@ * 7.45 * - add FUSE_COPY_FILE_RANGE_64 * - add struct fuse_copy_file_range_out + * - add FUSE_NOTIFY_PRUNE */ #ifndef _LINUX_FUSE_H @@ -680,6 +681,7 @@ enum fuse_notify_code { FUSE_NOTIFY_DELETE = 6, FUSE_NOTIFY_RESEND = 7, FUSE_NOTIFY_INC_EPOCH = 8, + FUSE_NOTIFY_PRUNE = 9, }; /* The read buffer is required to be at least 8k, but may be much larger */ @@ -1118,6 +1120,12 @@ struct fuse_notify_retrieve_in { uint64_t dummy4; }; +struct fuse_notify_prune_out { + uint32_t count; + uint32_t padding; + uint64_t spare; +}; + struct fuse_backing_map { int32_t fd; uint32_t flags; -- 2.49.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 4/4] fuse: add prune notification 2025-09-02 14:41 ` [PATCH 4/4] fuse: add prune notification Miklos Szeredi @ 2025-09-02 22:40 ` Joanne Koong 2025-09-04 21:07 ` Jim Harris 1 sibling, 0 replies; 11+ messages in thread From: Joanne Koong @ 2025-09-02 22:40 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel, Jim Harris On Tue, Sep 2, 2025 at 7:44 AM Miklos Szeredi <mszeredi@redhat.com> wrote: > > Some fuse servers need to prune their caches, which can only be done if the > kernel's own dentry/inode caches are pruned first to avoid dangling > references. > > Add FUSE_NOTIFY_PRUNE, which takes an array of node ID's to try and get rid > of. Inodes with active references are skipped. > > A similar functionality is already provided by FUSE_NOTIFY_INVAL_ENTRY with > the FUSE_EXPIRE_ONLY flag. Differences in the interface are > > FUSE_NOTIFY_INVAL_ENTRY: > > - can only prune one dentry > > - dentry is determined by parent ID and name > > - if inode has multiple aliases (cached hard links), then they would have > to be invalidated individually to be able to get rid of the inode > > FUSE_NOTIFY_PRUNE: > > - can prune multiple inodes > > - inodes determined by their node ID > > - aliases are taken care of automatically > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Joanne Koong <joannelkoong@gmail.com> ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 4/4] fuse: add prune notification 2025-09-02 14:41 ` [PATCH 4/4] fuse: add prune notification Miklos Szeredi 2025-09-02 22:40 ` Joanne Koong @ 2025-09-04 21:07 ` Jim Harris 1 sibling, 0 replies; 11+ messages in thread From: Jim Harris @ 2025-09-04 21:07 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel@vger.kernel.org [-- Attachment #1: Type: text/plain, Size: 1188 bytes --] > On Sep 2, 2025, at 7:41 AM, Miklos Szeredi <mszeredi@redhat.com> wrote: > > External email: Use caution opening links or attachments > > > Some fuse servers need to prune their caches, which can only be done if the > kernel's own dentry/inode caches are pruned first to avoid dangling > references. > > Add FUSE_NOTIFY_PRUNE, which takes an array of node ID's to try and get rid > of. Inodes with active references are skipped. > > A similar functionality is already provided by FUSE_NOTIFY_INVAL_ENTRY with > the FUSE_EXPIRE_ONLY flag. Differences in the interface are > > FUSE_NOTIFY_INVAL_ENTRY: > > - can only prune one dentry > > - dentry is determined by parent ID and name > > - if inode has multiple aliases (cached hard links), then they would have > to be invalidated individually to be able to get rid of the inode > > FUSE_NOTIFY_PRUNE: > > - can prune multiple inodes > > - inodes determined by their node ID > > - aliases are taken care of automatically > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Thanks Miklos, this looks great. I’ll give this a spin in our virtio-fs FUSE device. <snip> [-- Attachment #2: smime.p7s --] [-- Type: application/pkcs7-signature, Size: 4312 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> 2025-09-02 14:41 [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Miklos Szeredi ` (2 preceding siblings ...) 2025-09-02 14:41 ` [PATCH 4/4] fuse: add prune notification Miklos Szeredi @ 2025-09-02 21:31 ` Joanne Koong 3 siblings, 0 replies; 11+ messages in thread From: Joanne Koong @ 2025-09-02 21:31 UTC (permalink / raw) To: Miklos Szeredi; +Cc: linux-fsdevel, Jim Harris On Tue, Sep 2, 2025 at 7:46 AM Miklos Szeredi <mszeredi@redhat.com> wrote: > > Constants that change value from version to version have no place in an > interface definition. > > Hopefully this won't break anything. > > Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Joanne Koong <joannelkoong@gmail.com> > --- > include/uapi/linux/fuse.h | 1 - > 1 file changed, 1 deletion(-) > > diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h > index 6b9fb8b08768..30bf0846547f 100644 > --- a/include/uapi/linux/fuse.h > +++ b/include/uapi/linux/fuse.h > @@ -680,7 +680,6 @@ enum fuse_notify_code { > FUSE_NOTIFY_DELETE = 6, > FUSE_NOTIFY_RESEND = 7, > FUSE_NOTIFY_INC_EPOCH = 8, > - FUSE_NOTIFY_CODE_MAX, > }; > > /* The read buffer is required to be at least 8k, but may be much larger */ > -- > 2.49.0 > > ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-09-04 21:07 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-09-02 14:41 [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Miklos Szeredi 2025-09-02 14:41 ` [PATCH 2/4] fuse: fix possibly missing fuse_copy_finish() call in fuse_notify() Miklos Szeredi 2025-09-02 21:48 ` Joanne Koong 2025-09-02 14:41 ` [PATCH 3/4] fuse: remove redundant calls to fuse_copy_finish() " Miklos Szeredi 2025-09-02 21:53 ` Joanne Koong 2025-09-03 10:25 ` Luis Henriques 2025-09-03 10:43 ` Miklos Szeredi 2025-09-02 14:41 ` [PATCH 4/4] fuse: add prune notification Miklos Szeredi 2025-09-02 22:40 ` Joanne Koong 2025-09-04 21:07 ` Jim Harris 2025-09-02 21:31 ` [PATCH 1/4] fuse: remove FUSE_NOTIFY_CODE_MAX from <uapi/linux/fuse.h> Joanne Koong
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).