diff mbox series

[v2] fuse: allow FUSE drivers to declare themselves free from outside changes

Message ID 20240402-setlease-v2-1-b098a5f9295d@kernel.org (mailing list archive)
State New
Headers show
Series [v2] fuse: allow FUSE drivers to declare themselves free from outside changes | expand

Commit Message

Jeffrey Layton April 2, 2024, 1:10 p.m. UTC
Traditionally, we've allowed people to set leases on FUSE inodes.  Some
FUSE drivers are effectively local filesystems and should be fine with
kernel-internal lease support. Others are backed by a network server
that may have multiple clients, or may be backed by something non-file
like entirely. On those, we don't want to allow leases.

Have the filesytem driver to set a fuse_conn flag to indicate whether
the inodes are subject to outside changes, not done via kernel APIs.  If
the flag is unset (the default), then setlease attempts will fail with
-EINVAL, indicating that leases aren't supported on that inode.

Local-ish filesystems may want to start setting this value to true to
preserve the ability to set leases.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
This is only tested for compilation, but it's fairly straightforward.

I've left the default the "safe" value of false, so that we assume that
outside changes are possible unless told otherwise.
---
Changes in v2:
- renamed flag to FUSE_NO_OUTSIDE_CHANGES
- flesh out comment describing the new flag
---
 fs/fuse/file.c            | 11 +++++++++++
 fs/fuse/fuse_i.h          |  5 +++++
 fs/fuse/inode.c           |  4 +++-
 include/uapi/linux/fuse.h |  1 +
 4 files changed, 20 insertions(+), 1 deletion(-)


---
base-commit: 026e680b0a08a62b1d948e5a8ca78700bfac0e6e
change-id: 20240319-setlease-ce31fb8777b0

Best regards,

Comments

Bernd Schubert April 2, 2024, 1:23 p.m. UTC | #1
On 4/2/24 15:10, Jeff Layton wrote:
> Traditionally, we've allowed people to set leases on FUSE inodes.  Some
> FUSE drivers are effectively local filesystems and should be fine with
> kernel-internal lease support. Others are backed by a network server
> that may have multiple clients, or may be backed by something non-file
> like entirely. On those, we don't want to allow leases.
> 
> Have the filesytem driver to set a fuse_conn flag to indicate whether
> the inodes are subject to outside changes, not done via kernel APIs.  If
> the flag is unset (the default), then setlease attempts will fail with
> -EINVAL, indicating that leases aren't supported on that inode.
> 
> Local-ish filesystems may want to start setting this value to true to
> preserve the ability to set leases.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
> This is only tested for compilation, but it's fairly straightforward.
> 
> I've left the default the "safe" value of false, so that we assume that
> outside changes are possible unless told otherwise.
> ---
> Changes in v2:
> - renamed flag to FUSE_NO_OUTSIDE_CHANGES
> - flesh out comment describing the new flag
> ---
>  fs/fuse/file.c            | 11 +++++++++++
>  fs/fuse/fuse_i.h          |  5 +++++
>  fs/fuse/inode.c           |  4 +++-
>  include/uapi/linux/fuse.h |  1 +
>  4 files changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index a56e7bffd000..79c7152c0d12 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -3298,6 +3298,16 @@ static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
>  	return ret;
>  }
>  
> +static int fuse_setlease(struct file *file, int arg,
> +			 struct file_lease **flp, void **priv)
> +{
> +	struct fuse_conn *fc = get_fuse_conn(file_inode(file));
> +
> +	if (fc->no_outside_changes)
> +		return generic_setlease(file, arg, flp, priv);
> +	return -EINVAL;
> +}
> +
>  static const struct file_operations fuse_file_operations = {
>  	.llseek		= fuse_file_llseek,
>  	.read_iter	= fuse_file_read_iter,
> @@ -3317,6 +3327,7 @@ static const struct file_operations fuse_file_operations = {
>  	.poll		= fuse_file_poll,
>  	.fallocate	= fuse_file_fallocate,
>  	.copy_file_range = fuse_copy_file_range,
> +	.setlease	= fuse_setlease,
>  };
>  
>  static const struct address_space_operations fuse_file_aops  = {
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index b24084b60864..49d44a07b0db 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -860,6 +860,11 @@ struct fuse_conn {
>  	/** Passthrough support for read/write IO */
>  	unsigned int passthrough:1;
>  
> +	/** Can we assume that the only changes will be done via the local
> +	 *  kernel? If the driver represents a network filesystem or is a front
> +	 *  for data that can change on its own, set this to false. */
> +	unsigned int no_outside_changes:1;
> +
>  	/** Maximum stack depth for passthrough backing files */
>  	int max_stack_depth;
>  
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 3a5d88878335..f33aedccdb26 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -1330,6 +1330,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
>  			}
>  			if (flags & FUSE_NO_EXPORT_SUPPORT)
>  				fm->sb->s_export_op = &fuse_export_fid_operations;
> +			if (flags & FUSE_NO_OUTSIDE_CHANGES)
> +				fc->no_outside_changes = 1;
>  		} else {
>  			ra_pages = fc->max_read / PAGE_SIZE;
>  			fc->no_lock = 1;
> @@ -1377,7 +1379,7 @@ void fuse_send_init(struct fuse_mount *fm)
>  		FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
>  		FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
>  		FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
> -		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
> +		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_NO_OUTSIDE_CHANGES;
>  #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 d08b99d60f6f..703d149d45ff 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -463,6 +463,7 @@ struct fuse_file_lock {
>  #define FUSE_PASSTHROUGH	(1ULL << 37)
>  #define FUSE_NO_EXPORT_SUPPORT	(1ULL << 38)
>  #define FUSE_HAS_RESEND		(1ULL << 39)
> +#define FUSE_NO_OUTSIDE_CHANGES	(1ULL << 40)

Above all of these flags are comments explaining the flags, so that one
doesn't need to look up in kernel sources what the exact meaning is.

Could you please add something like below?

FUSE_NO_OUTSIDE_CHANGES: No file changes through other mounts / clients



Thanks,
Bernd
Jeffrey Layton April 2, 2024, 1:27 p.m. UTC | #2
On Tue, 2024-04-02 at 15:23 +0200, Bernd Schubert wrote:
> 
> On 4/2/24 15:10, Jeff Layton wrote:
> > Traditionally, we've allowed people to set leases on FUSE inodes.  Some
> > FUSE drivers are effectively local filesystems and should be fine with
> > kernel-internal lease support. Others are backed by a network server
> > that may have multiple clients, or may be backed by something non-file
> > like entirely. On those, we don't want to allow leases.
> > 
> > Have the filesytem driver to set a fuse_conn flag to indicate whether
> > the inodes are subject to outside changes, not done via kernel APIs.  If
> > the flag is unset (the default), then setlease attempts will fail with
> > -EINVAL, indicating that leases aren't supported on that inode.
> > 
> > Local-ish filesystems may want to start setting this value to true to
> > preserve the ability to set leases.
> > 
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> > This is only tested for compilation, but it's fairly straightforward.
> > 
> > I've left the default the "safe" value of false, so that we assume that
> > outside changes are possible unless told otherwise.
> > ---
> > Changes in v2:
> > - renamed flag to FUSE_NO_OUTSIDE_CHANGES
> > - flesh out comment describing the new flag
> > ---
> >  fs/fuse/file.c            | 11 +++++++++++
> >  fs/fuse/fuse_i.h          |  5 +++++
> >  fs/fuse/inode.c           |  4 +++-
> >  include/uapi/linux/fuse.h |  1 +
> >  4 files changed, 20 insertions(+), 1 deletion(-)
> > 
> > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > index a56e7bffd000..79c7152c0d12 100644
> > --- a/fs/fuse/file.c
> > +++ b/fs/fuse/file.c
> > @@ -3298,6 +3298,16 @@ static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
> >  	return ret;
> >  }
> >  
> > +static int fuse_setlease(struct file *file, int arg,
> > +			 struct file_lease **flp, void **priv)
> > +{
> > +	struct fuse_conn *fc = get_fuse_conn(file_inode(file));
> > +
> > +	if (fc->no_outside_changes)
> > +		return generic_setlease(file, arg, flp, priv);
> > +	return -EINVAL;
> > +}
> > +
> >  static const struct file_operations fuse_file_operations = {
> >  	.llseek		= fuse_file_llseek,
> >  	.read_iter	= fuse_file_read_iter,
> > @@ -3317,6 +3327,7 @@ static const struct file_operations fuse_file_operations = {
> >  	.poll		= fuse_file_poll,
> >  	.fallocate	= fuse_file_fallocate,
> >  	.copy_file_range = fuse_copy_file_range,
> > +	.setlease	= fuse_setlease,
> >  };
> >  
> >  static const struct address_space_operations fuse_file_aops  = {
> > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> > index b24084b60864..49d44a07b0db 100644
> > --- a/fs/fuse/fuse_i.h
> > +++ b/fs/fuse/fuse_i.h
> > @@ -860,6 +860,11 @@ struct fuse_conn {
> >  	/** Passthrough support for read/write IO */
> >  	unsigned int passthrough:1;
> >  
> > +	/** Can we assume that the only changes will be done via the local
> > +	 *  kernel? If the driver represents a network filesystem or is a front
> > +	 *  for data that can change on its own, set this to false. */
> > +	unsigned int no_outside_changes:1;
> > +
> >  	/** Maximum stack depth for passthrough backing files */
> >  	int max_stack_depth;
> >  
> > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> > index 3a5d88878335..f33aedccdb26 100644
> > --- a/fs/fuse/inode.c
> > +++ b/fs/fuse/inode.c
> > @@ -1330,6 +1330,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
> >  			}
> >  			if (flags & FUSE_NO_EXPORT_SUPPORT)
> >  				fm->sb->s_export_op = &fuse_export_fid_operations;
> > +			if (flags & FUSE_NO_OUTSIDE_CHANGES)
> > +				fc->no_outside_changes = 1;
> >  		} else {
> >  			ra_pages = fc->max_read / PAGE_SIZE;
> >  			fc->no_lock = 1;
> > @@ -1377,7 +1379,7 @@ void fuse_send_init(struct fuse_mount *fm)
> >  		FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
> >  		FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
> >  		FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
> > -		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
> > +		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_NO_OUTSIDE_CHANGES;
> >  #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 d08b99d60f6f..703d149d45ff 100644
> > --- a/include/uapi/linux/fuse.h
> > +++ b/include/uapi/linux/fuse.h
> > @@ -463,6 +463,7 @@ struct fuse_file_lock {
> >  #define FUSE_PASSTHROUGH	(1ULL << 37)
> >  #define FUSE_NO_EXPORT_SUPPORT	(1ULL << 38)
> >  #define FUSE_HAS_RESEND		(1ULL << 39)
> > +#define FUSE_NO_OUTSIDE_CHANGES	(1ULL << 40)
> 
> Above all of these flags are comments explaining the flags, so that one
> doesn't need to look up in kernel sources what the exact meaning is.
> 
> Could you please add something like below?
> 
> FUSE_NO_OUTSIDE_CHANGES: No file changes through other mounts / clients
> 

Definitely. I've added that in my local branch. I can either resend
later, or maybe Miklos can just add that if he's otherwise OK with this
patch.
Amir Goldstein April 2, 2024, 2:02 p.m. UTC | #3
On Tue, Apr 2, 2024 at 4:29 PM Jeff Layton <jlayton@kernel.org> wrote:
>
> On Tue, 2024-04-02 at 15:23 +0200, Bernd Schubert wrote:
> >
> > On 4/2/24 15:10, Jeff Layton wrote:
> > > Traditionally, we've allowed people to set leases on FUSE inodes.  Some
> > > FUSE drivers are effectively local filesystems and should be fine with
> > > kernel-internal lease support. Others are backed by a network server
> > > that may have multiple clients, or may be backed by something non-file
> > > like entirely. On those, we don't want to allow leases.
> > >
> > > Have the filesytem driver to set a fuse_conn flag to indicate whether
> > > the inodes are subject to outside changes, not done via kernel APIs.  If
> > > the flag is unset (the default), then setlease attempts will fail with
> > > -EINVAL, indicating that leases aren't supported on that inode.
> > >
> > > Local-ish filesystems may want to start setting this value to true to
> > > preserve the ability to set leases.
> > >
> > > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > > ---
> > > This is only tested for compilation, but it's fairly straightforward.
> > >
> > > I've left the default the "safe" value of false, so that we assume that
> > > outside changes are possible unless told otherwise.
> > > ---
> > > Changes in v2:
> > > - renamed flag to FUSE_NO_OUTSIDE_CHANGES
> > > - flesh out comment describing the new flag
> > > ---
> > >  fs/fuse/file.c            | 11 +++++++++++
> > >  fs/fuse/fuse_i.h          |  5 +++++
> > >  fs/fuse/inode.c           |  4 +++-
> > >  include/uapi/linux/fuse.h |  1 +
> > >  4 files changed, 20 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> > > index a56e7bffd000..79c7152c0d12 100644
> > > --- a/fs/fuse/file.c
> > > +++ b/fs/fuse/file.c
> > > @@ -3298,6 +3298,16 @@ static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
> > >     return ret;
> > >  }
> > >
> > > +static int fuse_setlease(struct file *file, int arg,
> > > +                    struct file_lease **flp, void **priv)
> > > +{
> > > +   struct fuse_conn *fc = get_fuse_conn(file_inode(file));
> > > +
> > > +   if (fc->no_outside_changes)
> > > +           return generic_setlease(file, arg, flp, priv);
> > > +   return -EINVAL;
> > > +}
> > > +
> > >  static const struct file_operations fuse_file_operations = {
> > >     .llseek         = fuse_file_llseek,
> > >     .read_iter      = fuse_file_read_iter,
> > > @@ -3317,6 +3327,7 @@ static const struct file_operations fuse_file_operations = {
> > >     .poll           = fuse_file_poll,
> > >     .fallocate      = fuse_file_fallocate,
> > >     .copy_file_range = fuse_copy_file_range,
> > > +   .setlease       = fuse_setlease,
> > >  };
> > >
> > >  static const struct address_space_operations fuse_file_aops  = {
> > > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> > > index b24084b60864..49d44a07b0db 100644
> > > --- a/fs/fuse/fuse_i.h
> > > +++ b/fs/fuse/fuse_i.h
> > > @@ -860,6 +860,11 @@ struct fuse_conn {
> > >     /** Passthrough support for read/write IO */
> > >     unsigned int passthrough:1;
> > >
> > > +   /** Can we assume that the only changes will be done via the local
> > > +    *  kernel? If the driver represents a network filesystem or is a front
> > > +    *  for data that can change on its own, set this to false. */
> > > +   unsigned int no_outside_changes:1;
> > > +
> > >     /** Maximum stack depth for passthrough backing files */
> > >     int max_stack_depth;
> > >
> > > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> > > index 3a5d88878335..f33aedccdb26 100644
> > > --- a/fs/fuse/inode.c
> > > +++ b/fs/fuse/inode.c
> > > @@ -1330,6 +1330,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
> > >                     }
> > >                     if (flags & FUSE_NO_EXPORT_SUPPORT)
> > >                             fm->sb->s_export_op = &fuse_export_fid_operations;
> > > +                   if (flags & FUSE_NO_OUTSIDE_CHANGES)
> > > +                           fc->no_outside_changes = 1;
> > >             } else {
> > >                     ra_pages = fc->max_read / PAGE_SIZE;
> > >                     fc->no_lock = 1;
> > > @@ -1377,7 +1379,7 @@ void fuse_send_init(struct fuse_mount *fm)
> > >             FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
> > >             FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
> > >             FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
> > > -           FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
> > > +           FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_NO_OUTSIDE_CHANGES;
> > >  #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 d08b99d60f6f..703d149d45ff 100644
> > > --- a/include/uapi/linux/fuse.h
> > > +++ b/include/uapi/linux/fuse.h
> > > @@ -463,6 +463,7 @@ struct fuse_file_lock {
> > >  #define FUSE_PASSTHROUGH   (1ULL << 37)
> > >  #define FUSE_NO_EXPORT_SUPPORT     (1ULL << 38)
> > >  #define FUSE_HAS_RESEND            (1ULL << 39)
> > > +#define FUSE_NO_OUTSIDE_CHANGES    (1ULL << 40)
> >
> > Above all of these flags are comments explaining the flags, so that one
> > doesn't need to look up in kernel sources what the exact meaning is.
> >
> > Could you please add something like below?
> >
> > FUSE_NO_OUTSIDE_CHANGES: No file changes through other mounts / clients
> >
>
> Definitely. I've added that in my local branch. I can either resend
> later, or maybe Miklos can just add that if he's otherwise OK with this
> patch.

Don't love the name but don't have any suggestions either.

I am wondering out loud, if we have such a mode for the fs,
if and how should it affect caching configuration?

Thanks,
Amir.
Miklos Szeredi April 2, 2024, 2:38 p.m. UTC | #4
On Tue, 2 Apr 2024 at 16:02, Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Tue, Apr 2, 2024 at 4:29 PM Jeff Layton <jlayton@kernel.org> wrote:
> >
> > On Tue, 2024-04-02 at 15:23 +0200, Bernd Schubert wrote:

> > > Could you please add something like below?
> > >
> > > FUSE_NO_OUTSIDE_CHANGES: No file changes through other mounts / clients
> > >

"through other mounts" is confusing, since one instance of the fuse
filesystem can have many mounts, and changes can be done through all
of them.   The issue is if changes are spontaneous from the viewpoint
of the fuse client.

> >
> > Definitely. I've added that in my local branch. I can either resend
> > later, or maybe Miklos can just add that if he's otherwise OK with this
> > patch.
>
> Don't love the name but don't have any suggestions either.
>
> I am wondering out loud, if we have such a mode for the fs,
> if and how should it affect caching configuration?

IMO it should enable all caching and override any conflicting options.
That's a separate patch, but should be done within the next cycle.
I'll look into that.

Thanks,
Miklos
Christoph Hellwig April 2, 2024, 2:49 p.m. UTC | #5
On Tue, Apr 02, 2024 at 09:10:59AM -0400, Jeff Layton wrote:
> Traditionally, we've allowed people to set leases on FUSE inodes.  Some
> FUSE drivers are effectively local filesystems and should be fine with
> kernel-internal lease support. Others are backed by a network server
> that may have multiple clients, or may be backed by something non-file
> like entirely. On those, we don't want to allow leases.
> 
> Have the filesytem driver to set a fuse_conn flag to indicate whether
> the inodes are subject to outside changes, not done via kernel APIs.  If
> the flag is unset (the default), then setlease attempts will fail with
> -EINVAL, indicating that leases aren't supported on that inode.

So while this polarity is how we should be doing it, doesn't it risk
breaking all the local fuse file systems?  I.e. shouldn't the flag be
inverse to maximize backwards compatibility?
Jeffrey Layton April 2, 2024, 2:51 p.m. UTC | #6
On Tue, 2024-04-02 at 16:38 +0200, Miklos Szeredi wrote:
> On Tue, 2 Apr 2024 at 16:02, Amir Goldstein <amir73il@gmail.com> wrote:
> > 
> > On Tue, Apr 2, 2024 at 4:29 PM Jeff Layton <jlayton@kernel.org> wrote:
> > > 
> > > On Tue, 2024-04-02 at 15:23 +0200, Bernd Schubert wrote:
> 
> > > > Could you please add something like below?
> > > > 
> > > > FUSE_NO_OUTSIDE_CHANGES: No file changes through other mounts / clients
> > > > 
> 
> "through other mounts" is confusing, since one instance of the fuse
> filesystem can have many mounts, and changes can be done through all
> of them.   The issue is if changes are spontaneous from the viewpoint
> of the fuse client.
> 

I'm fine with whatever verbiage you prefer. Let me know if you need me
to resend.

> > > 
> > > Definitely. I've added that in my local branch. I can either resend
> > > later, or maybe Miklos can just add that if he's otherwise OK with this
> > > patch.
> > 
> > Don't love the name but don't have any suggestions either.
> > 
> > I am wondering out loud, if we have such a mode for the fs,
> > if and how should it affect caching configuration?

Another thing to consider: what about fsnotify? Should notifications be
allowed when this flag isn't set?

> 
> IMO it should enable all caching and override any conflicting options.
> That's a separate patch, but should be done within the next cycle.
> I'll look into that.
> 

Thanks!
Miklos Szeredi April 2, 2024, 2:54 p.m. UTC | #7
On Tue, 2 Apr 2024 at 16:51, Jeff Layton <jlayton@kernel.org> wrote:
>
> I'm fine with whatever verbiage you prefer. Let me know if you need me
> to resend.

I'll do this, no need to resend.

> Another thing to consider: what about fsnotify? Should notifications be
> allowed when this flag isn't set?

Aren't local notification done for all network filesystems?

Thanks,
Miklos
Jeffrey Layton April 2, 2024, 2:57 p.m. UTC | #8
On Tue, 2024-04-02 at 16:54 +0200, Miklos Szeredi wrote:
> On Tue, 2 Apr 2024 at 16:51, Jeff Layton <jlayton@kernel.org> wrote:
> > 
> > I'm fine with whatever verbiage you prefer. Let me know if you need me
> > to resend.
> 
> I'll do this, no need to resend.
> 
> > Another thing to consider: what about fsnotify? Should notifications be
> > allowed when this flag isn't set?
> 
> Aren't local notification done for all network filesystems?
> 

I think you may be correct. I suppose we lost that battle years ago.
diff mbox series

Patch

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a56e7bffd000..79c7152c0d12 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3298,6 +3298,16 @@  static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
 	return ret;
 }
 
+static int fuse_setlease(struct file *file, int arg,
+			 struct file_lease **flp, void **priv)
+{
+	struct fuse_conn *fc = get_fuse_conn(file_inode(file));
+
+	if (fc->no_outside_changes)
+		return generic_setlease(file, arg, flp, priv);
+	return -EINVAL;
+}
+
 static const struct file_operations fuse_file_operations = {
 	.llseek		= fuse_file_llseek,
 	.read_iter	= fuse_file_read_iter,
@@ -3317,6 +3327,7 @@  static const struct file_operations fuse_file_operations = {
 	.poll		= fuse_file_poll,
 	.fallocate	= fuse_file_fallocate,
 	.copy_file_range = fuse_copy_file_range,
+	.setlease	= fuse_setlease,
 };
 
 static const struct address_space_operations fuse_file_aops  = {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index b24084b60864..49d44a07b0db 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -860,6 +860,11 @@  struct fuse_conn {
 	/** Passthrough support for read/write IO */
 	unsigned int passthrough:1;
 
+	/** Can we assume that the only changes will be done via the local
+	 *  kernel? If the driver represents a network filesystem or is a front
+	 *  for data that can change on its own, set this to false. */
+	unsigned int no_outside_changes:1;
+
 	/** Maximum stack depth for passthrough backing files */
 	int max_stack_depth;
 
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 3a5d88878335..f33aedccdb26 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1330,6 +1330,8 @@  static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
 			}
 			if (flags & FUSE_NO_EXPORT_SUPPORT)
 				fm->sb->s_export_op = &fuse_export_fid_operations;
+			if (flags & FUSE_NO_OUTSIDE_CHANGES)
+				fc->no_outside_changes = 1;
 		} else {
 			ra_pages = fc->max_read / PAGE_SIZE;
 			fc->no_lock = 1;
@@ -1377,7 +1379,7 @@  void fuse_send_init(struct fuse_mount *fm)
 		FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
 		FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
 		FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
-		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND;
+		FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_NO_OUTSIDE_CHANGES;
 #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 d08b99d60f6f..703d149d45ff 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -463,6 +463,7 @@  struct fuse_file_lock {
 #define FUSE_PASSTHROUGH	(1ULL << 37)
 #define FUSE_NO_EXPORT_SUPPORT	(1ULL << 38)
 #define FUSE_HAS_RESEND		(1ULL << 39)
+#define FUSE_NO_OUTSIDE_CHANGES	(1ULL << 40)
 
 /* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
 #define FUSE_DIRECT_IO_RELAX	FUSE_DIRECT_IO_ALLOW_MMAP