diff mbox series

fuse: make delete_stale configurable

Message ID 20231023115341.60127-1-jefflexu@linux.alibaba.com (mailing list archive)
State New, archived
Headers show
Series fuse: make delete_stale configurable | expand

Commit Message

Jingbo Xu Oct. 23, 2023, 11:53 a.m. UTC
From: Yifei Zhang <zyfjeff@linux.alibaba.com>

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.

Signed-off-by: Yifei Zhang <zyfjeff@linux.alibaba.com>
Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 fs/fuse/inode.c           | 5 ++++-
 include/uapi/linux/fuse.h | 2 ++
 2 files changed, 6 insertions(+), 1 deletion(-)

Comments

Jingbo Xu Nov. 15, 2023, 6:24 a.m. UTC | #1
Hi,

On 10/23/23 7:53 PM, Jingbo Xu wrote:
> From: Yifei Zhang <zyfjeff@linux.alibaba.com>
> 
> 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@linux.alibaba.com>
> Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
> ---
>  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
diff mbox series

Patch

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