Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Copyright (C) 2007 Red Hat. All rights reserved.
4 : */
5 :
6 : #include <linux/fs.h>
7 : #include <linux/string.h>
8 : #include <linux/xattr.h>
9 : #include <linux/posix_acl_xattr.h>
10 : #include <linux/posix_acl.h>
11 : #include <linux/sched.h>
12 : #include <linux/sched/mm.h>
13 : #include <linux/slab.h>
14 : #include "ctree.h"
15 : #include "btrfs_inode.h"
16 : #include "xattr.h"
17 : #include "acl.h"
18 :
19 1377 : struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
20 : {
21 1377 : int size;
22 1377 : const char *name;
23 1377 : char *value = NULL;
24 1377 : struct posix_acl *acl;
25 :
26 1377 : if (rcu)
27 : return ERR_PTR(-ECHILD);
28 :
29 1377 : switch (type) {
30 : case ACL_TYPE_ACCESS:
31 : name = XATTR_NAME_POSIX_ACL_ACCESS;
32 : break;
33 1184 : case ACL_TYPE_DEFAULT:
34 1184 : name = XATTR_NAME_POSIX_ACL_DEFAULT;
35 1184 : break;
36 : default:
37 : return ERR_PTR(-EINVAL);
38 : }
39 :
40 1377 : size = btrfs_getxattr(inode, name, NULL, 0);
41 1377 : if (size > 0) {
42 3 : value = kzalloc(size, GFP_KERNEL);
43 3 : if (!value)
44 : return ERR_PTR(-ENOMEM);
45 3 : size = btrfs_getxattr(inode, name, value, size);
46 : }
47 1377 : if (size > 0)
48 3 : acl = posix_acl_from_xattr(&init_user_ns, value, size);
49 1374 : else if (size == -ENODATA || size == 0)
50 : acl = NULL;
51 : else
52 0 : acl = ERR_PTR(size);
53 1377 : kfree(value);
54 :
55 1377 : return acl;
56 : }
57 :
58 956626 : int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
59 : struct posix_acl *acl, int type)
60 : {
61 956626 : int ret, size = 0;
62 956626 : const char *name;
63 956626 : char *value = NULL;
64 :
65 956626 : switch (type) {
66 : case ACL_TYPE_ACCESS:
67 : name = XATTR_NAME_POSIX_ACL_ACCESS;
68 : break;
69 15533 : case ACL_TYPE_DEFAULT:
70 15533 : if (!S_ISDIR(inode->i_mode))
71 0 : return acl ? -EINVAL : 0;
72 : name = XATTR_NAME_POSIX_ACL_DEFAULT;
73 : break;
74 : default:
75 : return -EINVAL;
76 : }
77 :
78 956626 : if (acl) {
79 34701 : unsigned int nofs_flag;
80 :
81 34701 : size = posix_acl_xattr_size(acl->a_count);
82 : /*
83 : * We're holding a transaction handle, so use a NOFS memory
84 : * allocation context to avoid deadlock if reclaim happens.
85 : */
86 34701 : nofs_flag = memalloc_nofs_save();
87 34701 : value = kmalloc(size, GFP_KERNEL);
88 34701 : memalloc_nofs_restore(nofs_flag);
89 34701 : if (!value) {
90 0 : ret = -ENOMEM;
91 0 : goto out;
92 : }
93 :
94 34701 : ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
95 32462 : if (ret < 0)
96 0 : goto out;
97 : }
98 :
99 954387 : if (trans)
100 34671 : ret = btrfs_setxattr(trans, inode, name, value, size, 0);
101 : else
102 919716 : ret = btrfs_setxattr_trans(inode, name, value, size, 0);
103 :
104 965710 : out:
105 965710 : kfree(value);
106 :
107 965691 : if (!ret)
108 965691 : set_cached_acl(inode, type, acl);
109 :
110 : return ret;
111 : }
112 :
113 922593 : int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
114 : struct posix_acl *acl, int type)
115 : {
116 922593 : int ret;
117 922593 : struct inode *inode = d_inode(dentry);
118 922593 : umode_t old_mode = inode->i_mode;
119 :
120 922593 : if (type == ACL_TYPE_ACCESS && acl) {
121 905092 : ret = posix_acl_update_mode(idmap, inode,
122 : &inode->i_mode, &acl);
123 907292 : if (ret)
124 : return ret;
125 : }
126 924793 : ret = __btrfs_set_acl(NULL, inode, acl, type);
127 931003 : if (ret)
128 1 : inode->i_mode = old_mode;
129 : return ret;
130 : }
|