* Re: [PATCH 5/5] fuse: propagate default and file acls on creation [not found] ` <176169809360.1424347.15464466375351097387.stgit@frogsfrogsfrogs> @ 2026-02-05 19:32 ` Chris Mason 2026-02-05 23:28 ` Darrick J. Wong 0 siblings, 1 reply; 3+ messages in thread From: Chris Mason @ 2026-02-05 19:32 UTC (permalink / raw) To: Darrick J. Wong Cc: miklos, joannelkoong, bernd, neal, linux-ext4, linux-fsdevel "Darrick J. Wong" <djwong@kernel.org> wrote: > From: Darrick J. Wong <djwong@kernel.org> > > For local filesystems, propagate the default and file access ACLs to new > children when creating them, just like the other in-kernel local > filesystems. > Hi everyone, I'm trying out my AI review prompts on a few more trees, and I ran it on the fuse-iomap-cache branch: https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/log/?h=fuse-iomap-cache This was the latest email lore could find, apologies if I grabbed the wrong one. Hopefully the review below is useful, please let me know if there are places it has gone wildly wrong. I kept the header to make it obvious exactly which commit I'd run through: commit 72f7e38b8ab1d52b7e44818ba7db9335bc499476 Author: Darrick J. Wong <djwong@kernel.org> fuse: propagate default and file acls on creation For local filesystems, propagate the default and file access ACLs to new children when creating them, just like the other in-kernel local filesystems. > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > index 72bb4c94079b7..f2cb7e8db4cad 100644 > --- a/fs/fuse/acl.c > +++ b/fs/fuse/acl.c [ ... ] > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index b2dd3b189246e..3af81a063cc50 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -821,26 +821,28 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > struct fuse_entry_out outentry; > struct fuse_inode *fi; > struct fuse_file *ff; > + struct posix_acl *default_acl = NULL, *acl = NULL; > int epoch, err; > bool trunc = flags & O_TRUNC; > > /* Userspace expects S_IFREG in create mode */ > BUG_ON((mode & S_IFMT) != S_IFREG); > > + err = fuse_acl_create(dir, &mode, &default_acl, &acl); > + if (err) > + return err; > + > epoch = atomic_read(&fm->fc->epoch); > forget = fuse_alloc_forget(); > err = -ENOMEM; > if (!forget) > - goto out_err; > + goto out_acl_release; > > err = -ENOMEM; > ff = fuse_file_alloc(fm, true); > if (!ff) > goto out_put_forget_req; > > - if (!fm->fc->dont_mask) > - mode &= ~current_umask(); > - > flags &= ~O_NOCTTY; > memset(&inarg, 0, sizeof(inarg)); > memset(&outentry, 0, sizeof(outentry)); > @@ -892,12 +894,16 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > fuse_sync_release(NULL, ff, flags); > fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); > err = -ENOMEM; > - goto out_err; > + goto out_acl_release; > } > kfree(forget); > d_instantiate(entry, inode); > entry->d_time = epoch; > fuse_change_entry_timeout(entry, &outentry); > + > + err = fuse_init_acls(inode, default_acl, acl); > + if (err) > + goto out_acl_release; > fuse_dir_changed(dir); > err = generic_file_open(inode, file); > if (!err) { > @@ -919,7 +925,9 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > fuse_file_free(ff); > out_put_forget_req: > kfree(forget); > -out_err: > +out_acl_release: > + posix_acl_release(default_acl); > + posix_acl_release(acl); > return err; > } Does this leak the ACL pointers on the success path? When fuse_acl_create() allocates non-NULL ACLs (occurs when IS_POSIXACL(dir) && fuse_inode_has_local_acls(dir) and the parent directory has default ACLs), and the file creation succeeds, the function returns directly at 'return err;' without releasing the ACLs via posix_acl_release(). The cleanup at out_acl_release is only reached on error paths. This would leak the posix_acl structures on every successful file creation when local ACLs are enabled. Compare with create_new_entry() which correctly calls posix_acl_release() on both success and error paths (lines 1056-1057 and 1065-1066). > @@ -979,14 +989,18 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > struct fuse_forget_link *forget; > int epoch, err; > > - if (fuse_is_bad(dir)) > - return ERR_PTR(-EIO); > + if (fuse_is_bad(dir)) { > + err = -EIO; > + goto out_acl_release; > + } > > epoch = atomic_read(&fm->fc->epoch); > > forget = fuse_alloc_forget(); > - if (!forget) > - return ERR_PTR(-ENOMEM); > + if (!forget) { > + err = -ENOMEM; > + goto out_acl_release; > + } > > memset(&outarg, 0, sizeof(outarg)); > args->nodeid = get_node_id(dir); > @@ -1016,7 +1030,8 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); > if (!inode) { > fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); > - return ERR_PTR(-ENOMEM); > + err = -ENOMEM; > + goto out_acl_release; > } > kfree(forget); > > @@ -1032,19 +1047,31 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > entry->d_time = epoch; > fuse_change_entry_timeout(entry, &outarg); > } > + > + err = fuse_init_acls(inode, default_acl, acl); > + if (err) > + goto out_acl_release; > fuse_dir_changed(dir); > + > + posix_acl_release(default_acl); > + posix_acl_release(acl); > return d; > > out_put_forget_req: > if (err == -EEXIST) > fuse_invalidate_entry(entry); > kfree(forget); > + out_acl_release: > + posix_acl_release(default_acl); > + posix_acl_release(acl); > return ERR_PTR(err); > } Chen Linxuan raised a concern in v5 about pairing fuse_acl_create and posix_acl_release together. While the author's response explained the design choice to have create_new_entry consume the ACL arguments, there is a memory leak when d_splice_alias returns an error: > d = d_splice_alias(inode, entry); > if (IS_ERR(d)) > return d; The function returns ERR_PTR without releasing the ACL pointers. The normal path (lines 1056-1057) and error path (lines 1065-1066) both release ACLs, but the IS_ERR(d) path at line 1041 does not. https://lore.kernel.org/all/CAC1kPDOv4sy3NPexFtdoROFi18b98W+PbP+9t8y4Jd5fQqCxCg@mail.gmail.com/ [ ... ] ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 5/5] fuse: propagate default and file acls on creation 2026-02-05 19:32 ` [PATCH 5/5] fuse: propagate default and file acls on creation Chris Mason @ 2026-02-05 23:28 ` Darrick J. Wong 0 siblings, 0 replies; 3+ messages in thread From: Darrick J. Wong @ 2026-02-05 23:28 UTC (permalink / raw) To: Chris Mason; +Cc: miklos, joannelkoong, bernd, neal, linux-ext4, linux-fsdevel On Thu, Feb 05, 2026 at 11:32:58AM -0800, Chris Mason wrote: > "Darrick J. Wong" <djwong@kernel.org> wrote: > > From: Darrick J. Wong <djwong@kernel.org> > > > > For local filesystems, propagate the default and file access ACLs to new > > children when creating them, just like the other in-kernel local > > filesystems. > > > > Hi everyone, > > I'm trying out my AI review prompts on a few more trees, and I ran it > on the fuse-iomap-cache branch: > > https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/log/?h=fuse-iomap-cache Yessss some detailed review! For the first time in my Linux career I'm getting patch feedback before the patches are even posted! So, thank you! :D > This was the latest email lore could find, apologies if I grabbed the wrong one. > > Hopefully the review below is useful, please let me know if there are places it > has gone wildly wrong. I kept the header to make it obvious exactly which > commit I'd run through: > > commit 72f7e38b8ab1d52b7e44818ba7db9335bc499476 > Author: Darrick J. Wong <djwong@kernel.org> > > fuse: propagate default and file acls on creation > > For local filesystems, propagate the default and file access ACLs to new > children when creating them, just like the other in-kernel local > filesystems. > > > diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c > > index 72bb4c94079b7..f2cb7e8db4cad 100644 > > --- a/fs/fuse/acl.c > > +++ b/fs/fuse/acl.c > > [ ... ] > > > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > > index b2dd3b189246e..3af81a063cc50 100644 > > --- a/fs/fuse/dir.c > > +++ b/fs/fuse/dir.c > > @@ -821,26 +821,28 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > > struct fuse_entry_out outentry; > > struct fuse_inode *fi; > > struct fuse_file *ff; > > + struct posix_acl *default_acl = NULL, *acl = NULL; > > int epoch, err; > > bool trunc = flags & O_TRUNC; > > > > /* Userspace expects S_IFREG in create mode */ > > BUG_ON((mode & S_IFMT) != S_IFREG); > > > > + err = fuse_acl_create(dir, &mode, &default_acl, &acl); > > + if (err) > > + return err; > > + > > epoch = atomic_read(&fm->fc->epoch); > > forget = fuse_alloc_forget(); > > err = -ENOMEM; > > if (!forget) > > - goto out_err; > > + goto out_acl_release; > > > > err = -ENOMEM; > > ff = fuse_file_alloc(fm, true); > > if (!ff) > > goto out_put_forget_req; > > > > - if (!fm->fc->dont_mask) > > - mode &= ~current_umask(); > > - > > flags &= ~O_NOCTTY; > > memset(&inarg, 0, sizeof(inarg)); > > memset(&outentry, 0, sizeof(outentry)); > > @@ -892,12 +894,16 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > > fuse_sync_release(NULL, ff, flags); > > fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); > > err = -ENOMEM; > > - goto out_err; > > + goto out_acl_release; > > } > > kfree(forget); > > d_instantiate(entry, inode); > > entry->d_time = epoch; > > fuse_change_entry_timeout(entry, &outentry); > > + > > + err = fuse_init_acls(inode, default_acl, acl); > > + if (err) > > + goto out_acl_release; > > fuse_dir_changed(dir); > > err = generic_file_open(inode, file); > > if (!err) { > > @@ -919,7 +925,9 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, > > fuse_file_free(ff); > > out_put_forget_req: > > kfree(forget); > > -out_err: > > +out_acl_release: > > + posix_acl_release(default_acl); > > + posix_acl_release(acl); > > return err; > > } > > Does this leak the ACL pointers on the success path? When fuse_acl_create() > allocates non-NULL ACLs (occurs when IS_POSIXACL(dir) && > fuse_inode_has_local_acls(dir) and the parent directory has default ACLs), > and the file creation succeeds, the function returns directly at 'return > err;' without releasing the ACLs via posix_acl_release(). > > The cleanup at out_acl_release is only reached on error paths. This would > leak the posix_acl structures on every successful file creation when local > ACLs are enabled. > > Compare with create_new_entry() which correctly calls posix_acl_release() > on both success and error paths (lines 1056-1057 and 1065-1066). Oh, yeah, that is a pretty stupid memory leak, thanks for catching it. > > @@ -979,14 +989,18 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > > struct fuse_forget_link *forget; > > int epoch, err; > > > > - if (fuse_is_bad(dir)) > > - return ERR_PTR(-EIO); > > + if (fuse_is_bad(dir)) { > > + err = -EIO; > > + goto out_acl_release; > > + } > > > > epoch = atomic_read(&fm->fc->epoch); > > > > forget = fuse_alloc_forget(); > > - if (!forget) > > - return ERR_PTR(-ENOMEM); > > + if (!forget) { > > + err = -ENOMEM; > > + goto out_acl_release; > > + } > > > > memset(&outarg, 0, sizeof(outarg)); > > args->nodeid = get_node_id(dir); > > @@ -1016,7 +1030,8 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > > &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); > > if (!inode) { > > fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); > > - return ERR_PTR(-ENOMEM); > > + err = -ENOMEM; > > + goto out_acl_release; > > } > > kfree(forget); > > > > @@ -1032,19 +1047,31 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun > > entry->d_time = epoch; > > fuse_change_entry_timeout(entry, &outarg); > > } > > + > > + err = fuse_init_acls(inode, default_acl, acl); > > + if (err) > > + goto out_acl_release; > > fuse_dir_changed(dir); > > + > > + posix_acl_release(default_acl); > > + posix_acl_release(acl); > > return d; > > > > out_put_forget_req: > > if (err == -EEXIST) > > fuse_invalidate_entry(entry); > > kfree(forget); > > + out_acl_release: > > + posix_acl_release(default_acl); > > + posix_acl_release(acl); > > return ERR_PTR(err); > > } > > Chen Linxuan raised a concern in v5 about pairing fuse_acl_create and > posix_acl_release together. While the author's response explained the > design choice to have create_new_entry consume the ACL arguments, there is > a memory leak when d_splice_alias returns an error: > > > d = d_splice_alias(inode, entry); > > if (IS_ERR(d)) > > return d; > > The function returns ERR_PTR without releasing the ACL pointers. The > normal path (lines 1056-1057) and error path (lines 1065-1066) both > release ACLs, but the IS_ERR(d) path at line 1041 does not. > > https://lore.kernel.org/all/CAC1kPDOv4sy3NPexFtdoROFi18b98W+PbP+9t8y4Jd5fQqCxCg@mail.gmail.com/ Whoops. Also a good catch; I'll change that to: d = d_splice_alias(inode, entry); if (IS_ERR(d)) { err = PTR_ERR(d); goto out_acl_release; } --D > [ ... ] > > ^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCHSET v7 1/9] fuse: general bug fixes @ 2026-02-23 23:00 Darrick J. Wong 2026-02-23 23:07 ` [PATCH 5/5] fuse: propagate default and file acls on creation Darrick J. Wong 0 siblings, 1 reply; 3+ messages in thread From: Darrick J. Wong @ 2026-02-23 23:00 UTC (permalink / raw) To: miklos, djwong Cc: joannelkoong, stable, joannelkoong, bpf, bernd, neal, linux-fsdevel, linux-ext4 Hi all, Here's a collection of fixes that I *think* are bugs in fuse, along with some scattered improvements. If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below. With a bit of luck, this should all go splendidly. Comments and questions are, as always, welcome. --D kernel git tree: https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=fuse-fixes --- Commits in this patchset: * fuse: flush pending FUSE_RELEASE requests before sending FUSE_DESTROY * fuse: quiet down complaints in fuse_conn_limit_write * fuse: implement file attributes mask for statx * fuse: update file mode when updating acls * fuse: propagate default and file acls on creation --- fs/fuse/fuse_i.h | 48 ++++++++++++++++++++++++ fs/fuse/acl.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/fuse/control.c | 4 +- fs/fuse/dev.c | 19 ++++++++++ fs/fuse/dir.c | 105 ++++++++++++++++++++++++++++++++++++++++------------- fs/fuse/inode.c | 16 ++++++++ 6 files changed, 267 insertions(+), 30 deletions(-) ^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 5/5] fuse: propagate default and file acls on creation 2026-02-23 23:00 [PATCHSET v7 1/9] fuse: general bug fixes Darrick J. Wong @ 2026-02-23 23:07 ` Darrick J. Wong 0 siblings, 0 replies; 3+ messages in thread From: Darrick J. Wong @ 2026-02-23 23:07 UTC (permalink / raw) To: miklos, djwong; +Cc: joannelkoong, bpf, bernd, neal, linux-fsdevel, linux-ext4 From: Darrick J. Wong <djwong@kernel.org> For local filesystems, propagate the default and file access ACLs to new children when creating them, just like the other in-kernel local filesystems. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> --- fs/fuse/fuse_i.h | 4 ++ fs/fuse/acl.c | 62 +++++++++++++++++++++++++++++++++ fs/fuse/dir.c | 101 +++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 142 insertions(+), 25 deletions(-) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index a1880599455c0a..77b581ecf48a16 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1533,6 +1533,10 @@ struct posix_acl *fuse_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, int type); int fuse_set_acl(struct mnt_idmap *, struct dentry *dentry, struct posix_acl *acl, int type); +int fuse_acl_create(struct inode *dir, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl); +int fuse_init_acls(struct inode *inode, const struct posix_acl *default_acl, + const struct posix_acl *acl); /* readdir.c */ int fuse_readdir(struct file *file, struct dir_context *ctx); diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c index f2b959efd67490..483ddf195d40a6 100644 --- a/fs/fuse/acl.c +++ b/fs/fuse/acl.c @@ -10,6 +10,7 @@ #include <linux/posix_acl.h> #include <linux/posix_acl_xattr.h> +#include <linux/fs_struct.h> /* * If this fuse server behaves like a local filesystem, we can implement the @@ -202,3 +203,64 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, return ret; } + +int fuse_acl_create(struct inode *dir, umode_t *mode, + struct posix_acl **default_acl, struct posix_acl **acl) +{ + struct fuse_conn *fc = get_fuse_conn(dir); + + if (fuse_is_bad(dir)) + return -EIO; + + if (IS_POSIXACL(dir) && fuse_inode_has_local_acls(dir)) + return posix_acl_create(dir, mode, default_acl, acl); + + if (!fc->dont_mask) + *mode &= ~current_umask(); + + *default_acl = NULL; + *acl = NULL; + return 0; +} + +static int __fuse_set_acl(struct inode *inode, const char *name, + const struct posix_acl *acl) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + size_t size; + void *value = posix_acl_to_xattr(fc->user_ns, acl, &size, GFP_KERNEL); + int ret; + + if (!value) + return -ENOMEM; + + if (size > PAGE_SIZE) { + kfree(value); + return -E2BIG; + } + + ret = fuse_setxattr(inode, name, value, size, 0, 0); + kfree(value); + return ret; +} + +int fuse_init_acls(struct inode *inode, const struct posix_acl *default_acl, + const struct posix_acl *acl) +{ + int ret; + + if (default_acl) { + ret = __fuse_set_acl(inode, XATTR_NAME_POSIX_ACL_DEFAULT, + default_acl); + if (ret) + return ret; + } + + if (acl) { + ret = __fuse_set_acl(inode, XATTR_NAME_POSIX_ACL_ACCESS, acl); + if (ret) + return ret; + } + + return 0; +} diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 10fa47e969292f..9abec6f072ac73 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -821,26 +821,28 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, struct fuse_entry_out outentry; struct fuse_inode *fi; struct fuse_file *ff; + struct posix_acl *default_acl = NULL, *acl = NULL; int epoch, err; bool trunc = flags & O_TRUNC; /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) != S_IFREG); + err = fuse_acl_create(dir, &mode, &default_acl, &acl); + if (err) + return err; + epoch = atomic_read(&fm->fc->epoch); forget = fuse_alloc_forget(); err = -ENOMEM; if (!forget) - goto out_err; + goto out_acl_release; err = -ENOMEM; ff = fuse_file_alloc(fm, true); if (!ff) goto out_put_forget_req; - if (!fm->fc->dont_mask) - mode &= ~current_umask(); - flags &= ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); memset(&outentry, 0, sizeof(outentry)); @@ -892,12 +894,17 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, fuse_sync_release(NULL, ff, flags); fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); err = -ENOMEM; - goto out_err; + goto out_acl_release; } kfree(forget); d_instantiate(entry, inode); entry->d_time = epoch; fuse_change_entry_timeout(entry, &outentry); + + err = fuse_init_acls(inode, default_acl, acl); + if (err) + goto out_acl_release; + fuse_dir_changed(dir); err = generic_file_open(inode, file); if (!err) { @@ -913,13 +920,17 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) invalidate_inode_pages2(inode->i_mapping); } + posix_acl_release(default_acl); + posix_acl_release(acl); return err; out_free_ff: fuse_file_free(ff); out_put_forget_req: kfree(forget); -out_err: +out_acl_release: + posix_acl_release(default_acl); + posix_acl_release(acl); return err; } @@ -971,7 +982,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, */ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, struct fuse_args *args, struct inode *dir, - struct dentry *entry, umode_t mode) + struct dentry *entry, umode_t mode, + struct posix_acl *default_acl, + struct posix_acl *acl) { struct fuse_entry_out outarg; struct inode *inode; @@ -979,14 +992,18 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun struct fuse_forget_link *forget; int epoch, err; - if (fuse_is_bad(dir)) - return ERR_PTR(-EIO); + if (fuse_is_bad(dir)) { + err = -EIO; + goto out_acl_release; + } epoch = atomic_read(&fm->fc->epoch); forget = fuse_alloc_forget(); - if (!forget) - return ERR_PTR(-ENOMEM); + if (!forget) { + err = -ENOMEM; + goto out_acl_release; + } memset(&outarg, 0, sizeof(outarg)); args->nodeid = get_node_id(dir); @@ -1016,14 +1033,17 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); if (!inode) { fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); - return ERR_PTR(-ENOMEM); + err = -ENOMEM; + goto out_acl_release; } kfree(forget); d_drop(entry); d = d_splice_alias(inode, entry); - if (IS_ERR(d)) - return d; + if (IS_ERR(d)) { + err = PTR_ERR(d); + goto out_acl_release; + } if (d) { d->d_time = epoch; @@ -1032,19 +1052,31 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun entry->d_time = epoch; fuse_change_entry_timeout(entry, &outarg); } + + err = fuse_init_acls(inode, default_acl, acl); + if (err) + goto out_acl_release; fuse_dir_changed(dir); + + posix_acl_release(default_acl); + posix_acl_release(acl); return d; out_put_forget_req: if (err == -EEXIST) fuse_invalidate_entry(entry); kfree(forget); + out_acl_release: + posix_acl_release(default_acl); + posix_acl_release(acl); return ERR_PTR(err); } static int create_new_nondir(struct mnt_idmap *idmap, struct fuse_mount *fm, struct fuse_args *args, struct inode *dir, - struct dentry *entry, umode_t mode) + struct dentry *entry, umode_t mode, + struct posix_acl *default_acl, + struct posix_acl *acl) { /* * Note that when creating anything other than a directory we @@ -1055,7 +1087,8 @@ static int create_new_nondir(struct mnt_idmap *idmap, struct fuse_mount *fm, */ WARN_ON_ONCE(S_ISDIR(mode)); - return PTR_ERR(create_new_entry(idmap, fm, args, dir, entry, mode)); + return PTR_ERR(create_new_entry(idmap, fm, args, dir, entry, mode, + default_acl, acl)); } static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, @@ -1063,10 +1096,13 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, { struct fuse_mknod_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); + struct posix_acl *default_acl, *acl; FUSE_ARGS(args); + int err; - if (!fm->fc->dont_mask) - mode &= ~current_umask(); + err = fuse_acl_create(dir, &mode, &default_acl, &acl); + if (err) + return err; memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; @@ -1078,7 +1114,8 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_nondir(idmap, fm, &args, dir, entry, mode); + return create_new_nondir(idmap, fm, &args, dir, entry, mode, + default_acl, acl); } static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, @@ -1110,13 +1147,17 @@ static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, { struct fuse_mkdir_in inarg; struct fuse_mount *fm = get_fuse_mount(dir); + struct posix_acl *default_acl, *acl; FUSE_ARGS(args); + int err; - if (!fm->fc->dont_mask) - mode &= ~current_umask(); + mode |= S_IFDIR; /* vfs doesn't set S_IFDIR for us */ + err = fuse_acl_create(dir, &mode, &default_acl, &acl); + if (err) + return ERR_PTR(err); memset(&inarg, 0, sizeof(inarg)); - inarg.mode = mode; + inarg.mode = mode & ~S_IFDIR; inarg.umask = current_umask(); args.opcode = FUSE_MKDIR; args.in_numargs = 2; @@ -1124,7 +1165,8 @@ static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); + return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR, + default_acl, acl); } static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, @@ -1132,7 +1174,14 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, { struct fuse_mount *fm = get_fuse_mount(dir); unsigned len = strlen(link) + 1; + struct posix_acl *default_acl, *acl; + umode_t mode = S_IFLNK | 0777; FUSE_ARGS(args); + int err; + + err = fuse_acl_create(dir, &mode, &default_acl, &acl); + if (err) + return err; args.opcode = FUSE_SYMLINK; args.in_numargs = 3; @@ -1141,7 +1190,8 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, args.in_args[1].value = entry->d_name.name; args.in_args[2].size = len; args.in_args[2].value = link; - return create_new_nondir(idmap, fm, &args, dir, entry, S_IFLNK); + return create_new_nondir(idmap, fm, &args, dir, entry, S_IFLNK, + default_acl, acl); } void fuse_flush_time_update(struct inode *inode) @@ -1341,7 +1391,8 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, args.in_args[0].value = &inarg; args.in_args[1].size = newent->d_name.len + 1; args.in_args[1].value = newent->d_name.name; - err = create_new_nondir(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); + err = create_new_nondir(&invalid_mnt_idmap, fm, &args, newdir, newent, + inode->i_mode, NULL, NULL); if (!err) fuse_update_ctime_in_cache(inode); else if (err == -EINTR) ^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-02-23 23:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <176169809222.1424347.16562281526870178424.stgit@frogsfrogsfrogs>
[not found] ` <176169809360.1424347.15464466375351097387.stgit@frogsfrogsfrogs>
2026-02-05 19:32 ` [PATCH 5/5] fuse: propagate default and file acls on creation Chris Mason
2026-02-05 23:28 ` Darrick J. Wong
2026-02-23 23:00 [PATCHSET v7 1/9] fuse: general bug fixes Darrick J. Wong
2026-02-23 23:07 ` [PATCH 5/5] fuse: propagate default and file acls on creation Darrick J. Wong
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox