f2fs: Provide a splice-read wrapper
[linux-block.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 int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
68 {
69         int error = 0;
70         void *value = NULL;
71         size_t size = 0;
72         const char *name = NULL;
73
74         switch (type) {
75         case ACL_TYPE_ACCESS:
76                 name = XATTR_NAME_POSIX_ACL_ACCESS;
77                 break;
78         case ACL_TYPE_DEFAULT:
79                 name = XATTR_NAME_POSIX_ACL_DEFAULT;
80                 break;
81         default:
82                 gossip_err("%s: invalid type %d!\n", __func__, type);
83                 return -EINVAL;
84         }
85
86         gossip_debug(GOSSIP_ACL_DEBUG,
87                      "%s: inode %pU, key %s type %d\n",
88                      __func__, get_khandle_from_ino(inode),
89                      name,
90                      type);
91
92         if (acl) {
93                 size = posix_acl_xattr_size(acl->a_count);
94                 value = kmalloc(size, GFP_KERNEL);
95                 if (!value)
96                         return -ENOMEM;
97
98                 error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
99                 if (error < 0)
100                         goto out;
101         }
102
103         gossip_debug(GOSSIP_ACL_DEBUG,
104                      "%s: name %s, value %p, size %zd, acl %p\n",
105                      __func__, name, value, size, acl);
106         /*
107          * Go ahead and set the extended attribute now. NOTE: Suppose acl
108          * was NULL, then value will be NULL and size will be 0 and that
109          * will xlate to a removexattr. However, we don't want removexattr
110          * complain if attributes does not exist.
111          */
112         error = orangefs_inode_setxattr(inode, name, value, size, 0);
113
114 out:
115         kfree(value);
116         if (!error)
117                 set_cached_acl(inode, type, acl);
118         return error;
119 }
120
121 int orangefs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
122                      struct posix_acl *acl, int type)
123 {
124         int error;
125         struct iattr iattr;
126         int rc;
127         struct inode *inode = d_inode(dentry);
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(&nop_mnt_idmap, 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_mode(dentry, &iattr);
157
158         return rc;
159 }