Merge tag 'acpi-5.15-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-microblaze.git] / fs / orangefs / acl.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) 2001 Clemson University and The University of Chicago
4  *
5  * See COPYING in top-level directory.
6  */
7
8 #include "protocol.h"
9 #include "orangefs-kernel.h"
10 #include "orangefs-bufmap.h"
11 #include <linux/posix_acl_xattr.h>
12
13 struct posix_acl *orangefs_get_acl(struct inode *inode, int type, bool rcu)
14 {
15         struct posix_acl *acl;
16         int ret;
17         char *key = NULL, *value = NULL;
18
19         if (rcu)
20                 return ERR_PTR(-ECHILD);
21
22         switch (type) {
23         case ACL_TYPE_ACCESS:
24                 key = XATTR_NAME_POSIX_ACL_ACCESS;
25                 break;
26         case ACL_TYPE_DEFAULT:
27                 key = XATTR_NAME_POSIX_ACL_DEFAULT;
28                 break;
29         default:
30                 gossip_err("orangefs_get_acl: bogus value of type %d\n", type);
31                 return ERR_PTR(-EINVAL);
32         }
33         /*
34          * Rather than incurring a network call just to determine the exact
35          * length of the attribute, I just allocate a max length to save on
36          * the network call. Conceivably, we could pass NULL to
37          * orangefs_inode_getxattr() to probe the length of the value, but
38          * I don't do that for now.
39          */
40         value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
41         if (!value)
42                 return ERR_PTR(-ENOMEM);
43
44         gossip_debug(GOSSIP_ACL_DEBUG,
45                      "inode %pU, key %s, type %d\n",
46                      get_khandle_from_ino(inode),
47                      key,
48                      type);
49         ret = orangefs_inode_getxattr(inode, key, value,
50                                       ORANGEFS_MAX_XATTR_VALUELEN);
51         /* if the key exists, convert it to an in-memory rep */
52         if (ret > 0) {
53                 acl = posix_acl_from_xattr(&init_user_ns, value, ret);
54         } else if (ret == -ENODATA || ret == -ENOSYS) {
55                 acl = NULL;
56         } else {
57                 gossip_err("inode %pU retrieving acl's failed with error %d\n",
58                            get_khandle_from_ino(inode),
59                            ret);
60                 acl = ERR_PTR(ret);
61         }
62         /* kfree(NULL) is safe, so don't worry if value ever got used */
63         kfree(value);
64         return acl;
65 }
66
67 static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
68                               int type)
69 {
70         int error = 0;
71         void *value = NULL;
72         size_t size = 0;
73         const char *name = NULL;
74
75         switch (type) {
76         case ACL_TYPE_ACCESS:
77                 name = XATTR_NAME_POSIX_ACL_ACCESS;
78                 break;
79         case ACL_TYPE_DEFAULT:
80                 name = XATTR_NAME_POSIX_ACL_DEFAULT;
81                 break;
82         default:
83                 gossip_err("%s: invalid type %d!\n", __func__, type);
84                 return -EINVAL;
85         }
86
87         gossip_debug(GOSSIP_ACL_DEBUG,
88                      "%s: inode %pU, key %s type %d\n",
89                      __func__, get_khandle_from_ino(inode),
90                      name,
91                      type);
92
93         if (acl) {
94                 size = posix_acl_xattr_size(acl->a_count);
95                 value = kmalloc(size, GFP_KERNEL);
96                 if (!value)
97                         return -ENOMEM;
98
99                 error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
100                 if (error < 0)
101                         goto out;
102         }
103
104         gossip_debug(GOSSIP_ACL_DEBUG,
105                      "%s: name %s, value %p, size %zd, acl %p\n",
106                      __func__, name, value, size, acl);
107         /*
108          * Go ahead and set the extended attribute now. NOTE: Suppose acl
109          * was NULL, then value will be NULL and size will be 0 and that
110          * will xlate to a removexattr. However, we don't want removexattr
111          * complain if attributes does not exist.
112          */
113         error = orangefs_inode_setxattr(inode, name, value, size, 0);
114
115 out:
116         kfree(value);
117         if (!error)
118                 set_cached_acl(inode, type, acl);
119         return error;
120 }
121
122 int orangefs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
123                      struct posix_acl *acl, int type)
124 {
125         int error;
126         struct iattr iattr;
127         int rc;
128
129         memset(&iattr, 0, sizeof iattr);
130
131         if (type == ACL_TYPE_ACCESS && acl) {
132                 /*
133                  * posix_acl_update_mode checks to see if the permissions
134                  * described by the ACL can be encoded into the
135                  * object's mode. If so, it sets "acl" to NULL
136                  * and "mode" to the new desired value. It is up to
137                  * us to propagate the new mode back to the server...
138                  */
139                 error = posix_acl_update_mode(&init_user_ns, inode,
140                                               &iattr.ia_mode, &acl);
141                 if (error) {
142                         gossip_err("%s: posix_acl_update_mode err: %d\n",
143                                    __func__,
144                                    error);
145                         return error;
146                 }
147
148                 if (inode->i_mode != iattr.ia_mode)
149                         iattr.ia_valid = ATTR_MODE;
150
151         }
152
153         rc = __orangefs_set_acl(inode, acl, type);
154
155         if (!rc && (iattr.ia_valid == ATTR_MODE))
156                 rc = __orangefs_setattr(inode, &iattr);
157
158         return rc;
159 }
160
161 int orangefs_init_acl(struct inode *inode, struct inode *dir)
162 {
163         struct posix_acl *default_acl, *acl;
164         umode_t mode = inode->i_mode;
165         struct iattr iattr;
166         int error = 0;
167
168         error = posix_acl_create(dir, &mode, &default_acl, &acl);
169         if (error)
170                 return error;
171
172         if (default_acl) {
173                 error = __orangefs_set_acl(inode, default_acl,
174                                            ACL_TYPE_DEFAULT);
175                 posix_acl_release(default_acl);
176         } else {
177                 inode->i_default_acl = NULL;
178         }
179
180         if (acl) {
181                 if (!error)
182                         error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
183                 posix_acl_release(acl);
184         } else {
185                 inode->i_acl = NULL;
186         }
187
188         /* If mode of the inode was changed, then do a forcible ->setattr */
189         if (mode != inode->i_mode) {
190                 memset(&iattr, 0, sizeof iattr);
191                 inode->i_mode = mode;
192                 iattr.ia_mode = mode;
193                 iattr.ia_valid |= ATTR_MODE;
194                 __orangefs_setattr(inode, &iattr);
195         }
196
197         return error;
198 }