* 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
* [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