1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
25103e947SJosef Bacik /*
35103e947SJosef Bacik * Copyright (C) 2007 Red Hat. All rights reserved.
45103e947SJosef Bacik */
55103e947SJosef Bacik
65103e947SJosef Bacik #include <linux/fs.h>
75103e947SJosef Bacik #include <linux/string.h>
85103e947SJosef Bacik #include <linux/xattr.h>
95103e947SJosef Bacik #include <linux/posix_acl_xattr.h>
1033268eafSJosef Bacik #include <linux/posix_acl.h>
11c1e32da6SChris Mason #include <linux/sched.h>
12a0873490SFilipe Manana #include <linux/sched/mm.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
145103e947SJosef Bacik #include "ctree.h"
1533268eafSJosef Bacik #include "btrfs_inode.h"
165103e947SJosef Bacik #include "xattr.h"
1733cf97a7SJosef Bacik #include "acl.h"
1833268eafSJosef Bacik
btrfs_get_acl(struct inode * inode,int type,bool rcu)190cad6246SMiklos Szeredi struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
2033268eafSJosef Bacik {
2195819c05SChristoph Hellwig int size;
2295819c05SChristoph Hellwig const char *name;
2333268eafSJosef Bacik char *value = NULL;
24073aaa1bSAl Viro struct posix_acl *acl;
25073aaa1bSAl Viro
260cad6246SMiklos Szeredi if (rcu)
270cad6246SMiklos Szeredi return ERR_PTR(-ECHILD);
280cad6246SMiklos Szeredi
2933268eafSJosef Bacik switch (type) {
3033268eafSJosef Bacik case ACL_TYPE_ACCESS:
3197d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_ACCESS;
3233268eafSJosef Bacik break;
3333268eafSJosef Bacik case ACL_TYPE_DEFAULT:
3497d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_DEFAULT;
3533268eafSJosef Bacik break;
3633268eafSJosef Bacik default:
37ab3629edSChengguang Xu return ERR_PTR(-EINVAL);
3833268eafSJosef Bacik }
3933268eafSJosef Bacik
407e35eab9SChengguang Xu size = btrfs_getxattr(inode, name, NULL, 0);
4133268eafSJosef Bacik if (size > 0) {
4239a27ec1SDavid Sterba value = kzalloc(size, GFP_KERNEL);
4333268eafSJosef Bacik if (!value)
4433268eafSJosef Bacik return ERR_PTR(-ENOMEM);
457852781dSDavid Sterba size = btrfs_getxattr(inode, name, value, size);
46cfbffc39STsutomu Itoh }
474de426cdSChengguang Xu if (size > 0)
485f3a4a28SEric W. Biederman acl = posix_acl_from_xattr(&init_user_ns, value, size);
494de426cdSChengguang Xu else if (size == -ENODATA || size == 0)
5033268eafSJosef Bacik acl = NULL;
514de426cdSChengguang Xu else
52dc7789efSChengguang Xu acl = ERR_PTR(size);
53cfbffc39STsutomu Itoh kfree(value);
54cfbffc39STsutomu Itoh
5533268eafSJosef Bacik return acl;
5633268eafSJosef Bacik }
5733268eafSJosef Bacik
__btrfs_set_acl(struct btrfs_trans_handle * trans,struct inode * inode,struct posix_acl * acl,int type)583538d68dSOmar Sandoval int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
593538d68dSOmar Sandoval struct posix_acl *acl, int type)
6033268eafSJosef Bacik {
6195819c05SChristoph Hellwig int ret, size = 0;
6295819c05SChristoph Hellwig const char *name;
6333268eafSJosef Bacik char *value = NULL;
6433268eafSJosef Bacik
6533268eafSJosef Bacik switch (type) {
6633268eafSJosef Bacik case ACL_TYPE_ACCESS:
6797d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_ACCESS;
6833268eafSJosef Bacik break;
6933268eafSJosef Bacik case ACL_TYPE_DEFAULT:
7033268eafSJosef Bacik if (!S_ISDIR(inode->i_mode))
7133268eafSJosef Bacik return acl ? -EINVAL : 0;
7297d79299SAndreas Gruenbacher name = XATTR_NAME_POSIX_ACL_DEFAULT;
7333268eafSJosef Bacik break;
7433268eafSJosef Bacik default:
7533268eafSJosef Bacik return -EINVAL;
7633268eafSJosef Bacik }
7733268eafSJosef Bacik
7833268eafSJosef Bacik if (acl) {
79a0873490SFilipe Manana unsigned int nofs_flag;
80a0873490SFilipe Manana
8133268eafSJosef Bacik size = posix_acl_xattr_size(acl->a_count);
82a0873490SFilipe Manana /*
83a0873490SFilipe Manana * We're holding a transaction handle, so use a NOFS memory
84a0873490SFilipe Manana * allocation context to avoid deadlock if reclaim happens.
85a0873490SFilipe Manana */
86a0873490SFilipe Manana nofs_flag = memalloc_nofs_save();
8739a27ec1SDavid Sterba value = kmalloc(size, GFP_KERNEL);
88a0873490SFilipe Manana memalloc_nofs_restore(nofs_flag);
8933268eafSJosef Bacik if (!value) {
9033268eafSJosef Bacik ret = -ENOMEM;
9133268eafSJosef Bacik goto out;
9233268eafSJosef Bacik }
9333268eafSJosef Bacik
945f3a4a28SEric W. Biederman ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
9533268eafSJosef Bacik if (ret < 0)
9633268eafSJosef Bacik goto out;
9733268eafSJosef Bacik }
9833268eafSJosef Bacik
9904e6863bSAnand Jain if (trans)
10004e6863bSAnand Jain ret = btrfs_setxattr(trans, inode, name, value, size, 0);
10104e6863bSAnand Jain else
102e3de9b15SAnand Jain ret = btrfs_setxattr_trans(inode, name, value, size, 0);
10304e6863bSAnand Jain
10433268eafSJosef Bacik out:
10533268eafSJosef Bacik kfree(value);
10633268eafSJosef Bacik
10733268eafSJosef Bacik if (!ret)
108073aaa1bSAl Viro set_cached_acl(inode, type, acl);
10933268eafSJosef Bacik
11033268eafSJosef Bacik return ret;
11133268eafSJosef Bacik }
112fb4bc1e0SYan
btrfs_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,struct posix_acl * acl,int type)11313e83a49SChristian Brauner int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
114549c7297SChristian Brauner struct posix_acl *acl, int type)
115744f52f9SYan {
116b7f8a09fSJan Kara int ret;
117138060baSChristian Brauner struct inode *inode = d_inode(dentry);
118d7d82496SErnesto A. Fernández umode_t old_mode = inode->i_mode;
119b7f8a09fSJan Kara
120b7f8a09fSJan Kara if (type == ACL_TYPE_ACCESS && acl) {
121*700b7940SChristian Brauner ret = posix_acl_update_mode(idmap, inode,
122e65ce2a5SChristian Brauner &inode->i_mode, &acl);
123b7f8a09fSJan Kara if (ret)
124b7f8a09fSJan Kara return ret;
125b7f8a09fSJan Kara }
12675b993cfSOmar Sandoval ret = __btrfs_set_acl(NULL, inode, acl, type);
127d7d82496SErnesto A. Fernández if (ret)
128d7d82496SErnesto A. Fernández inode->i_mode = old_mode;
129d7d82496SErnesto A. Fernández return ret;
130744f52f9SYan }
131