Re: [PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
Vivek Goyal writes: > On Mon, Mar 29, 2021 at 03:54:03PM +0100, Luis Henriques wrote: >> On Thu, Mar 25, 2021 at 11:18:22AM -0400, Vivek Goyal wrote: >> > Fuse client needs to send additional information to file server when >> > it calls SETXATTR(system.posix_acl_access). Right now there is no extra >> > space in fuse_setxattr_in. So introduce a v2 of the structure which has >> > more space in it and can be used to send extra flags. >> > >> > "struct fuse_setxattr_in_v2" is only used if file server opts-in for it >> > using >> > flag FUSE_SETXATTR_V2 during feature negotiations. >> > >> > Signed-off-by: Vivek Goyal >> > --- >> > fs/fuse/acl.c | 2 +- >> > fs/fuse/fuse_i.h | 5 - >> > fs/fuse/inode.c | 4 +++- >> > fs/fuse/xattr.c | 21 +++-- >> > include/uapi/linux/fuse.h | 10 ++ >> > 5 files changed, 33 insertions(+), 9 deletions(-) >> > >> > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c >> > index e9c0f916349d..d31260a139d4 100644 >> > --- a/fs/fuse/acl.c >> > +++ b/fs/fuse/acl.c >> > @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, >> > struct inode *inode, >> >return ret; >> >} >> > >> > - ret = fuse_setxattr(inode, name, value, size, 0); >> > + ret = fuse_setxattr(inode, name, value, size, 0, 0); >> >kfree(value); >> >} else { >> >ret = fuse_removexattr(inode, name); >> > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h >> > index 63d97a15ffde..d00bf0b9a38c 100644 >> > --- a/fs/fuse/fuse_i.h >> > +++ b/fs/fuse/fuse_i.h >> > @@ -668,6 +668,9 @@ struct fuse_conn { >> >/** Is setxattr not implemented by fs? */ >> >unsigned no_setxattr:1; >> > >> > + /** Does file server support setxattr_v2 */ >> > + unsigned setxattr_v2:1; >> > + >> >/** Is getxattr not implemented by fs? */ >> >unsigned no_getxattr:1; >> > >> > @@ -1170,7 +1173,7 @@ void fuse_unlock_inode(struct inode *inode, bool >> > locked); >> > bool fuse_lock_inode(struct inode *inode); >> > >> > int fuse_setxattr(struct inode *inode, const char *name, const void >> > *value, >> > -size_t size, int flags); >> > +size_t size, int flags, unsigned extra_flags); >> > ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, >> > size_t size); >> > ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); >> > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c >> > index b0e18b470e91..1c726df13f80 100644 >> > --- a/fs/fuse/inode.c >> > +++ b/fs/fuse/inode.c >> > @@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount >> > *fm, struct fuse_args *args, >> >fc->handle_killpriv_v2 = 1; >> >fm->sb->s_flags |= SB_NOSEC; >> >} >> > + if (arg->flags & FUSE_SETXATTR_V2) >> > + fc->setxattr_v2 = 1; >> >} else { >> >ra_pages = fc->max_read / PAGE_SIZE; >> >fc->no_lock = 1; >> > @@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm) >> >FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | >> >FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | >> >FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | >> > - FUSE_HANDLE_KILLPRIV_V2; >> > + FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2; >> > #ifdef CONFIG_FUSE_DAX >> >if (fm->fc->dax) >> >ia->in.flags |= FUSE_MAP_ALIGNMENT; >> > diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c >> > index 1a7d7ace54e1..f2aae72653dc 100644 >> > --- a/fs/fuse/xattr.c >> > +++ b/fs/fuse/xattr.c >> > @@ -12,24 +12,33 @@ >> > #include >> > >> > int fuse_setxattr(struct inode *inode, const char *name, const void >> > *value, >> > -size_t size, int flags) >> > +size_t size, int flags, unsigned extra_flags) >> > { >> >struct fuse_mount *fm = get_fuse_mount(inode); >> >FUSE_ARGS(args); >> >struct fuse_setxattr_in inarg; >> > + struct fuse_setxattr_in_v2 inarg_v2; >> > + bool setxattr_v2 = fm->fc->setxattr_v2; >> >int err; >> > >> >if (fm->fc->no_setxattr) >> >return -EOPNOTSUPP; >> > >> >memset(&inarg, 0, sizeof(inarg)); >> > - inarg.size = size; >> > - inarg.flags = flags; >> > + memset(&inarg_v2, 0, sizeof(inarg_v2)); >> > + if (setxattr_v2) { >> > + inarg_v2.size = size; >> > + inarg_v2.flags = flags; >> > + inarg_v2.setxattr_flags = extra_flags; >> > + } else { >> > + inarg.size = size; >> > + inarg.flags = flags; >> > + } >> >args.opcode = FUSE_SETXATTR; >> >args.nodeid = get_node_id(inode); >> >args.in_numargs = 3; >> > - args.in_args[0].size = sizeof(inarg); >> > - args.in_args[0].value = &inarg; >> > + args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) :
Re: [PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
On Mon, Mar 29, 2021 at 03:54:03PM +0100, Luis Henriques wrote: > On Thu, Mar 25, 2021 at 11:18:22AM -0400, Vivek Goyal wrote: > > Fuse client needs to send additional information to file server when > > it calls SETXATTR(system.posix_acl_access). Right now there is no extra > > space in fuse_setxattr_in. So introduce a v2 of the structure which has > > more space in it and can be used to send extra flags. > > > > "struct fuse_setxattr_in_v2" is only used if file server opts-in for it > > using > > flag FUSE_SETXATTR_V2 during feature negotiations. > > > > Signed-off-by: Vivek Goyal > > --- > > fs/fuse/acl.c | 2 +- > > fs/fuse/fuse_i.h | 5 - > > fs/fuse/inode.c | 4 +++- > > fs/fuse/xattr.c | 21 +++-- > > include/uapi/linux/fuse.h | 10 ++ > > 5 files changed, 33 insertions(+), 9 deletions(-) > > > > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > > index e9c0f916349d..d31260a139d4 100644 > > --- a/fs/fuse/acl.c > > +++ b/fs/fuse/acl.c > > @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, > > struct inode *inode, > > return ret; > > } > > > > - ret = fuse_setxattr(inode, name, value, size, 0); > > + ret = fuse_setxattr(inode, name, value, size, 0, 0); > > kfree(value); > > } else { > > ret = fuse_removexattr(inode, name); > > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > > index 63d97a15ffde..d00bf0b9a38c 100644 > > --- a/fs/fuse/fuse_i.h > > +++ b/fs/fuse/fuse_i.h > > @@ -668,6 +668,9 @@ struct fuse_conn { > > /** Is setxattr not implemented by fs? */ > > unsigned no_setxattr:1; > > > > + /** Does file server support setxattr_v2 */ > > + unsigned setxattr_v2:1; > > + > > /** Is getxattr not implemented by fs? */ > > unsigned no_getxattr:1; > > > > @@ -1170,7 +1173,7 @@ void fuse_unlock_inode(struct inode *inode, bool > > locked); > > bool fuse_lock_inode(struct inode *inode); > > > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > > - size_t size, int flags); > > + size_t size, int flags, unsigned extra_flags); > > ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, > > size_t size); > > ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); > > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > > index b0e18b470e91..1c726df13f80 100644 > > --- a/fs/fuse/inode.c > > +++ b/fs/fuse/inode.c > > @@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount *fm, > > struct fuse_args *args, > > fc->handle_killpriv_v2 = 1; > > fm->sb->s_flags |= SB_NOSEC; > > } > > + if (arg->flags & FUSE_SETXATTR_V2) > > + fc->setxattr_v2 = 1; > > } else { > > ra_pages = fc->max_read / PAGE_SIZE; > > fc->no_lock = 1; > > @@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm) > > FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | > > FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | > > FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | > > - FUSE_HANDLE_KILLPRIV_V2; > > + FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2; > > #ifdef CONFIG_FUSE_DAX > > if (fm->fc->dax) > > ia->in.flags |= FUSE_MAP_ALIGNMENT; > > diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c > > index 1a7d7ace54e1..f2aae72653dc 100644 > > --- a/fs/fuse/xattr.c > > +++ b/fs/fuse/xattr.c > > @@ -12,24 +12,33 @@ > > #include > > > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > > - size_t size, int flags) > > + size_t size, int flags, unsigned extra_flags) > > { > > struct fuse_mount *fm = get_fuse_mount(inode); > > FUSE_ARGS(args); > > struct fuse_setxattr_in inarg; > > + struct fuse_setxattr_in_v2 inarg_v2; > > + bool setxattr_v2 = fm->fc->setxattr_v2; > > int err; > > > > if (fm->fc->no_setxattr) > > return -EOPNOTSUPP; > > > > memset(&inarg, 0, sizeof(inarg)); > > - inarg.size = size; > > - inarg.flags = flags; > > + memset(&inarg_v2, 0, sizeof(inarg_v2)); > > + if (setxattr_v2) { > > + inarg_v2.size = size; > > + inarg_v2.flags = flags; > > + inarg_v2.setxattr_flags = extra_flags; > > + } else { > > + inarg.size = size; > > + inarg.flags = flags; > > + } > > args.opcode = FUSE_SETXATTR; > > args.nodeid = get_node_id(inode); > > args.in_numargs = 3; > > - args.in_args[0].size = sizeof(inarg); > > - args.in_args[0].value = &inarg; > > + args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) : sizeof(inarg); > > + args.in_args[0].value = setxattr_v2 ? &inarg_v2 : (void *)&inarg; > > A
Re: [PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
On Mon, Mar 29, 2021 at 03:50:37PM +0100, Luis Henriques wrote: > On Thu, Mar 25, 2021 at 11:18:22AM -0400, Vivek Goyal wrote: > > Fuse client needs to send additional information to file server when > > it calls SETXATTR(system.posix_acl_access). Right now there is no extra > > space in fuse_setxattr_in. So introduce a v2 of the structure which has > > more space in it and can be used to send extra flags. > > > > "struct fuse_setxattr_in_v2" is only used if file server opts-in for it > > using > > flag FUSE_SETXATTR_V2 during feature negotiations. > > > > Signed-off-by: Vivek Goyal > > --- > > fs/fuse/acl.c | 2 +- > > fs/fuse/fuse_i.h | 5 - > > fs/fuse/inode.c | 4 +++- > > fs/fuse/xattr.c | 21 +++-- > > include/uapi/linux/fuse.h | 10 ++ > > 5 files changed, 33 insertions(+), 9 deletions(-) > > > > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > > index e9c0f916349d..d31260a139d4 100644 > > --- a/fs/fuse/acl.c > > +++ b/fs/fuse/acl.c > > @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, > > struct inode *inode, > > return ret; > > } > > > > - ret = fuse_setxattr(inode, name, value, size, 0); > > + ret = fuse_setxattr(inode, name, value, size, 0, 0); > > kfree(value); > > } else { > > ret = fuse_removexattr(inode, name); > > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > > index 63d97a15ffde..d00bf0b9a38c 100644 > > --- a/fs/fuse/fuse_i.h > > +++ b/fs/fuse/fuse_i.h > > @@ -668,6 +668,9 @@ struct fuse_conn { > > /** Is setxattr not implemented by fs? */ > > unsigned no_setxattr:1; > > > > + /** Does file server support setxattr_v2 */ > > + unsigned setxattr_v2:1; > > + > > Minor (pedantic!) comment: most of the fields here start with 'no_*', so > maybe it's worth setting the logic to use 'no_setxattr_v2' instead? Hi Luis, "setxattr_v2" kind of makes more sense to me because it is disabled by default untile and unless client opts in. If I use no_setxattr_v2, then it means by default I will have to initialize it to 1. Right now, following automatically takes care of it. fc = kzalloc(sizeof(struct fuse_conn), GFP_KERNEL); Also, there are other examples which don't use "no_" prefix. auto_inval_data, explicit_inval_data, do_readdirplus, readdirplus_auto, async_dio. and list goes on. Vivek
Re: [PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
On Thu, Mar 25, 2021 at 11:18:22AM -0400, Vivek Goyal wrote: > Fuse client needs to send additional information to file server when > it calls SETXATTR(system.posix_acl_access). Right now there is no extra > space in fuse_setxattr_in. So introduce a v2 of the structure which has > more space in it and can be used to send extra flags. > > "struct fuse_setxattr_in_v2" is only used if file server opts-in for it using > flag FUSE_SETXATTR_V2 during feature negotiations. > > Signed-off-by: Vivek Goyal > --- > fs/fuse/acl.c | 2 +- > fs/fuse/fuse_i.h | 5 - > fs/fuse/inode.c | 4 +++- > fs/fuse/xattr.c | 21 +++-- > include/uapi/linux/fuse.h | 10 ++ > 5 files changed, 33 insertions(+), 9 deletions(-) > > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > index e9c0f916349d..d31260a139d4 100644 > --- a/fs/fuse/acl.c > +++ b/fs/fuse/acl.c > @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct > inode *inode, > return ret; > } > > - ret = fuse_setxattr(inode, name, value, size, 0); > + ret = fuse_setxattr(inode, name, value, size, 0, 0); > kfree(value); > } else { > ret = fuse_removexattr(inode, name); > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index 63d97a15ffde..d00bf0b9a38c 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -668,6 +668,9 @@ struct fuse_conn { > /** Is setxattr not implemented by fs? */ > unsigned no_setxattr:1; > > + /** Does file server support setxattr_v2 */ > + unsigned setxattr_v2:1; > + > /** Is getxattr not implemented by fs? */ > unsigned no_getxattr:1; > > @@ -1170,7 +1173,7 @@ void fuse_unlock_inode(struct inode *inode, bool > locked); > bool fuse_lock_inode(struct inode *inode); > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > - size_t size, int flags); > + size_t size, int flags, unsigned extra_flags); > ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, > size_t size); > ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index b0e18b470e91..1c726df13f80 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount *fm, > struct fuse_args *args, > fc->handle_killpriv_v2 = 1; > fm->sb->s_flags |= SB_NOSEC; > } > + if (arg->flags & FUSE_SETXATTR_V2) > + fc->setxattr_v2 = 1; > } else { > ra_pages = fc->max_read / PAGE_SIZE; > fc->no_lock = 1; > @@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm) > FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | > FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | > FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | > - FUSE_HANDLE_KILLPRIV_V2; > + FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2; > #ifdef CONFIG_FUSE_DAX > if (fm->fc->dax) > ia->in.flags |= FUSE_MAP_ALIGNMENT; > diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c > index 1a7d7ace54e1..f2aae72653dc 100644 > --- a/fs/fuse/xattr.c > +++ b/fs/fuse/xattr.c > @@ -12,24 +12,33 @@ > #include > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > - size_t size, int flags) > + size_t size, int flags, unsigned extra_flags) > { > struct fuse_mount *fm = get_fuse_mount(inode); > FUSE_ARGS(args); > struct fuse_setxattr_in inarg; > + struct fuse_setxattr_in_v2 inarg_v2; > + bool setxattr_v2 = fm->fc->setxattr_v2; > int err; > > if (fm->fc->no_setxattr) > return -EOPNOTSUPP; > > memset(&inarg, 0, sizeof(inarg)); > - inarg.size = size; > - inarg.flags = flags; > + memset(&inarg_v2, 0, sizeof(inarg_v2)); > + if (setxattr_v2) { > + inarg_v2.size = size; > + inarg_v2.flags = flags; > + inarg_v2.setxattr_flags = extra_flags; > + } else { > + inarg.size = size; > + inarg.flags = flags; > + } > args.opcode = FUSE_SETXATTR; > args.nodeid = get_node_id(inode); > args.in_numargs = 3; > - args.in_args[0].size = sizeof(inarg); > - args.in_args[0].value = &inarg; > + args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) : sizeof(inarg); > + args.in_args[0].value = setxattr_v2 ? &inarg_v2 : (void *)&inarg; And yet another minor: It's a bit awkward to have to cast '&inarg' to 'void *' just because you're using the ternary operator. Why not use an 'if' statement instead for initializing .size an
Re: [PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
On Thu, Mar 25, 2021 at 11:18:22AM -0400, Vivek Goyal wrote: > Fuse client needs to send additional information to file server when > it calls SETXATTR(system.posix_acl_access). Right now there is no extra > space in fuse_setxattr_in. So introduce a v2 of the structure which has > more space in it and can be used to send extra flags. > > "struct fuse_setxattr_in_v2" is only used if file server opts-in for it using > flag FUSE_SETXATTR_V2 during feature negotiations. > > Signed-off-by: Vivek Goyal > --- > fs/fuse/acl.c | 2 +- > fs/fuse/fuse_i.h | 5 - > fs/fuse/inode.c | 4 +++- > fs/fuse/xattr.c | 21 +++-- > include/uapi/linux/fuse.h | 10 ++ > 5 files changed, 33 insertions(+), 9 deletions(-) > > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > index e9c0f916349d..d31260a139d4 100644 > --- a/fs/fuse/acl.c > +++ b/fs/fuse/acl.c > @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct > inode *inode, > return ret; > } > > - ret = fuse_setxattr(inode, name, value, size, 0); > + ret = fuse_setxattr(inode, name, value, size, 0, 0); > kfree(value); > } else { > ret = fuse_removexattr(inode, name); > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index 63d97a15ffde..d00bf0b9a38c 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -668,6 +668,9 @@ struct fuse_conn { > /** Is setxattr not implemented by fs? */ > unsigned no_setxattr:1; > > + /** Does file server support setxattr_v2 */ > + unsigned setxattr_v2:1; > + Minor (pedantic!) comment: most of the fields here start with 'no_*', so maybe it's worth setting the logic to use 'no_setxattr_v2' instead? Cheers, -- Luís > /** Is getxattr not implemented by fs? */ > unsigned no_getxattr:1; > > @@ -1170,7 +1173,7 @@ void fuse_unlock_inode(struct inode *inode, bool > locked); > bool fuse_lock_inode(struct inode *inode); > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > - size_t size, int flags); > + size_t size, int flags, unsigned extra_flags); > ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, > size_t size); > ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index b0e18b470e91..1c726df13f80 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount *fm, > struct fuse_args *args, > fc->handle_killpriv_v2 = 1; > fm->sb->s_flags |= SB_NOSEC; > } > + if (arg->flags & FUSE_SETXATTR_V2) > + fc->setxattr_v2 = 1; > } else { > ra_pages = fc->max_read / PAGE_SIZE; > fc->no_lock = 1; > @@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm) > FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | > FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | > FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | > - FUSE_HANDLE_KILLPRIV_V2; > + FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2; > #ifdef CONFIG_FUSE_DAX > if (fm->fc->dax) > ia->in.flags |= FUSE_MAP_ALIGNMENT; > diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c > index 1a7d7ace54e1..f2aae72653dc 100644 > --- a/fs/fuse/xattr.c > +++ b/fs/fuse/xattr.c > @@ -12,24 +12,33 @@ > #include > > int fuse_setxattr(struct inode *inode, const char *name, const void *value, > - size_t size, int flags) > + size_t size, int flags, unsigned extra_flags) > { > struct fuse_mount *fm = get_fuse_mount(inode); > FUSE_ARGS(args); > struct fuse_setxattr_in inarg; > + struct fuse_setxattr_in_v2 inarg_v2; > + bool setxattr_v2 = fm->fc->setxattr_v2; > int err; > > if (fm->fc->no_setxattr) > return -EOPNOTSUPP; > > memset(&inarg, 0, sizeof(inarg)); > - inarg.size = size; > - inarg.flags = flags; > + memset(&inarg_v2, 0, sizeof(inarg_v2)); > + if (setxattr_v2) { > + inarg_v2.size = size; > + inarg_v2.flags = flags; > + inarg_v2.setxattr_flags = extra_flags; > + } else { > + inarg.size = size; > + inarg.flags = flags; > + } > args.opcode = FUSE_SETXATTR; > args.nodeid = get_node_id(inode); > args.in_numargs = 3; > - args.in_args[0].size = sizeof(inarg); > - args.in_args[0].value = &inarg; > + args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) : sizeof(inarg); > + args.in_args[0].value = setxattr_v2 ? &inarg_v2 : (void *)&inarg; > args.in_args[1].size = s
[PATCH v2 1/2] fuse: Add support for FUSE_SETXATTR_V2
Fuse client needs to send additional information to file server when it calls SETXATTR(system.posix_acl_access). Right now there is no extra space in fuse_setxattr_in. So introduce a v2 of the structure which has more space in it and can be used to send extra flags. "struct fuse_setxattr_in_v2" is only used if file server opts-in for it using flag FUSE_SETXATTR_V2 during feature negotiations. Signed-off-by: Vivek Goyal --- fs/fuse/acl.c | 2 +- fs/fuse/fuse_i.h | 5 - fs/fuse/inode.c | 4 +++- fs/fuse/xattr.c | 21 +++-- include/uapi/linux/fuse.h | 10 ++ 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c index e9c0f916349d..d31260a139d4 100644 --- a/fs/fuse/acl.c +++ b/fs/fuse/acl.c @@ -94,7 +94,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct inode *inode, return ret; } - ret = fuse_setxattr(inode, name, value, size, 0); + ret = fuse_setxattr(inode, name, value, size, 0, 0); kfree(value); } else { ret = fuse_removexattr(inode, name); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 63d97a15ffde..d00bf0b9a38c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -668,6 +668,9 @@ struct fuse_conn { /** Is setxattr not implemented by fs? */ unsigned no_setxattr:1; + /** Does file server support setxattr_v2 */ + unsigned setxattr_v2:1; + /** Is getxattr not implemented by fs? */ unsigned no_getxattr:1; @@ -1170,7 +1173,7 @@ void fuse_unlock_inode(struct inode *inode, bool locked); bool fuse_lock_inode(struct inode *inode); int fuse_setxattr(struct inode *inode, const char *name, const void *value, - size_t size, int flags); + size_t size, int flags, unsigned extra_flags); ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value, size_t size); ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index b0e18b470e91..1c726df13f80 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1052,6 +1052,8 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, fc->handle_killpriv_v2 = 1; fm->sb->s_flags |= SB_NOSEC; } + if (arg->flags & FUSE_SETXATTR_V2) + fc->setxattr_v2 = 1; } else { ra_pages = fc->max_read / PAGE_SIZE; fc->no_lock = 1; @@ -1095,7 +1097,7 @@ void fuse_send_init(struct fuse_mount *fm) FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | - FUSE_HANDLE_KILLPRIV_V2; + FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2; #ifdef CONFIG_FUSE_DAX if (fm->fc->dax) ia->in.flags |= FUSE_MAP_ALIGNMENT; diff --git a/fs/fuse/xattr.c b/fs/fuse/xattr.c index 1a7d7ace54e1..f2aae72653dc 100644 --- a/fs/fuse/xattr.c +++ b/fs/fuse/xattr.c @@ -12,24 +12,33 @@ #include int fuse_setxattr(struct inode *inode, const char *name, const void *value, - size_t size, int flags) + size_t size, int flags, unsigned extra_flags) { struct fuse_mount *fm = get_fuse_mount(inode); FUSE_ARGS(args); struct fuse_setxattr_in inarg; + struct fuse_setxattr_in_v2 inarg_v2; + bool setxattr_v2 = fm->fc->setxattr_v2; int err; if (fm->fc->no_setxattr) return -EOPNOTSUPP; memset(&inarg, 0, sizeof(inarg)); - inarg.size = size; - inarg.flags = flags; + memset(&inarg_v2, 0, sizeof(inarg_v2)); + if (setxattr_v2) { + inarg_v2.size = size; + inarg_v2.flags = flags; + inarg_v2.setxattr_flags = extra_flags; + } else { + inarg.size = size; + inarg.flags = flags; + } args.opcode = FUSE_SETXATTR; args.nodeid = get_node_id(inode); args.in_numargs = 3; - args.in_args[0].size = sizeof(inarg); - args.in_args[0].value = &inarg; + args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) : sizeof(inarg); + args.in_args[0].value = setxattr_v2 ? &inarg_v2 : (void *)&inarg; args.in_args[1].size = strlen(name) + 1; args.in_args[1].value = name; args.in_args[2].size = size; @@ -199,7 +208,7 @@ static int fuse_xattr_set(const struct xattr_handler *handler, if (!value) return fuse_removexattr(inode, name); - return fuse_setxattr(inode, name, value, size, flags); + return fuse_setx