Hi, On 10/23/23 7:53 PM, Jingbo Xu wrote: > From: Yifei Zhang <zyfjeff@xxxxxxxxxxxxxxxxx> > > Fuse tends to cache dentries in LRU list for performance, which makes > the fuse server always keep a reference to the opened fd. If the file > is deleted by a third party process (neither fuse server nor fuse > client), the fuse server will always keep a reference to the deleted > file, in which case the deleted file cannot be released. > > Fix this by making the delete_stale feature configurable. Fuse servers > can enable this if a file may be unlinked not through fuse server nor > client. Actually virtiofs enables this by default. Make this > configurable for other fuse filesystems. Is there any comment? Without this patch, when files are unlinked by third-party processes, the fuse daemon will keep reference to the fd of those files, and the disk space of those files also can not be released. The above issue doesn't exist if the fuse client tries to access the unlinked file later, as it will trigger a new FUSE_LOOKUP and get -ENOENT returned, and thus making the dentry finally get invalidated. However it depends on the explicit access from the fuse client. As long as the path is not accessed, the unused dentry will be cached there, while the fd descriptor and the disk space of the unlinked file also can not be released. Thanks, Jingbo > > Signed-off-by: Yifei Zhang <zyfjeff@xxxxxxxxxxxxxxxxx> > Signed-off-by: Jingbo Xu <jefflexu@xxxxxxxxxxxxxxxxx> > --- > fs/fuse/inode.c | 5 ++++- > include/uapi/linux/fuse.h | 2 ++ > 2 files changed, 6 insertions(+), 1 deletion(-) > > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index 2e4eb7cf26fb..635bf0b11147 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -1234,6 +1234,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, > fc->create_supp_group = 1; > if (flags & FUSE_DIRECT_IO_RELAX) > fc->direct_io_relax = 1; > + if (flags & FUSE_DELETE_STALE) > + fc->delete_stale = 1; > } else { > ra_pages = fc->max_read / PAGE_SIZE; > fc->no_lock = 1; > @@ -1280,7 +1282,8 @@ void fuse_send_init(struct fuse_mount *fm) > FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | > FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | > FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP | > - FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX; > + FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX | > + FUSE_DELETE_STALE; > #ifdef CONFIG_FUSE_DAX > if (fm->fc->dax) > flags |= FUSE_MAP_ALIGNMENT; > diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h > index db92a7202b34..8d0926d21d2e 100644 > --- a/include/uapi/linux/fuse.h > +++ b/include/uapi/linux/fuse.h > @@ -411,6 +411,7 @@ struct fuse_file_lock { > * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation > * FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now > * allow shared mmap > + * FUSE_DELETE_STALE: delete dentry if timeout is zero > */ > #define FUSE_ASYNC_READ (1 << 0) > #define FUSE_POSIX_LOCKS (1 << 1) > @@ -450,6 +451,7 @@ struct fuse_file_lock { > #define FUSE_CREATE_SUPP_GROUP (1ULL << 34) > #define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) > #define FUSE_DIRECT_IO_RELAX (1ULL << 36) > +#define FUSE_DELETE_STALE (1ULL << 37) > > /** > * CUSE INIT request/reply flags -- Thanks, Jingbo