1 // SPDX-License-Identifier: LGPL-2.1
3 * Copyright IBM Corporation, 2010
4 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
7 #include <linux/module.h>
10 #include <net/9p/client.h>
11 #include <linux/slab.h>
12 #include <linux/sched.h>
13 #include <linux/posix_acl_xattr.h>
20 static struct posix_acl
*v9fs_fid_get_acl(struct p9_fid
*fid
, const char *name
)
24 struct posix_acl
*acl
= NULL
;
26 size
= v9fs_fid_xattr_get(fid
, name
, NULL
, 0);
30 return ERR_PTR(-ENODATA
);
32 value
= kzalloc(size
, GFP_NOFS
);
34 return ERR_PTR(-ENOMEM
);
36 size
= v9fs_fid_xattr_get(fid
, name
, value
, size
);
40 acl
= ERR_PTR(-ENODATA
);
42 acl
= posix_acl_from_xattr(&init_user_ns
, value
, size
);
47 static struct posix_acl
*v9fs_acl_get(struct dentry
*dentry
, const char *name
)
50 struct posix_acl
*acl
= NULL
;
52 fid
= v9fs_fid_lookup(dentry
);
56 acl
= v9fs_fid_get_acl(fid
, name
);
61 static struct posix_acl
*__v9fs_get_acl(struct p9_fid
*fid
, const char *name
)
64 struct posix_acl
*acl
= NULL
;
66 acl
= v9fs_fid_get_acl(fid
, name
);
70 retval
= PTR_ERR(acl
);
71 if (retval
== -ENODATA
|| retval
== -ENOSYS
|| retval
== -EOPNOTSUPP
)
74 /* map everything else to -EIO */
78 int v9fs_get_acl(struct inode
*inode
, struct p9_fid
*fid
)
81 struct posix_acl
*pacl
, *dacl
;
82 struct v9fs_session_info
*v9ses
;
84 v9ses
= v9fs_inode2v9ses(inode
);
85 if (((v9ses
->flags
& V9FS_ACCESS_MASK
) != V9FS_ACCESS_CLIENT
) ||
86 ((v9ses
->flags
& V9FS_ACL_MASK
) != V9FS_POSIX_ACL
)) {
87 set_cached_acl(inode
, ACL_TYPE_DEFAULT
, NULL
);
88 set_cached_acl(inode
, ACL_TYPE_ACCESS
, NULL
);
91 /* get the default/access acl values and cache them */
92 dacl
= __v9fs_get_acl(fid
, XATTR_NAME_POSIX_ACL_DEFAULT
);
93 pacl
= __v9fs_get_acl(fid
, XATTR_NAME_POSIX_ACL_ACCESS
);
95 if (!IS_ERR(dacl
) && !IS_ERR(pacl
)) {
96 set_cached_acl(inode
, ACL_TYPE_DEFAULT
, dacl
);
97 set_cached_acl(inode
, ACL_TYPE_ACCESS
, pacl
);
102 posix_acl_release(dacl
);
105 posix_acl_release(pacl
);
110 static struct posix_acl
*v9fs_get_cached_acl(struct inode
*inode
, int type
)
112 struct posix_acl
*acl
;
114 * 9p Always cache the acl value when
115 * instantiating the inode (v9fs_inode_from_fid)
117 acl
= get_cached_acl(inode
, type
);
118 BUG_ON(is_uncached_acl(acl
));
122 struct posix_acl
*v9fs_iop_get_inode_acl(struct inode
*inode
, int type
, bool rcu
)
124 struct v9fs_session_info
*v9ses
;
127 return ERR_PTR(-ECHILD
);
129 v9ses
= v9fs_inode2v9ses(inode
);
130 if (((v9ses
->flags
& V9FS_ACCESS_MASK
) != V9FS_ACCESS_CLIENT
) ||
131 ((v9ses
->flags
& V9FS_ACL_MASK
) != V9FS_POSIX_ACL
)) {
133 * On access = client and acl = on mode get the acl
134 * values from the server
138 return v9fs_get_cached_acl(inode
, type
);
142 struct posix_acl
*v9fs_iop_get_acl(struct mnt_idmap
*idmap
,
143 struct dentry
*dentry
, int type
)
145 struct v9fs_session_info
*v9ses
;
147 v9ses
= v9fs_dentry2v9ses(dentry
);
148 /* We allow set/get/list of acl when access=client is not specified. */
149 if ((v9ses
->flags
& V9FS_ACCESS_MASK
) != V9FS_ACCESS_CLIENT
)
150 return v9fs_acl_get(dentry
, posix_acl_xattr_name(type
));
151 return v9fs_get_cached_acl(d_inode(dentry
), type
);
154 int v9fs_iop_set_acl(struct mnt_idmap
*idmap
, struct dentry
*dentry
,
155 struct posix_acl
*acl
, int type
)
160 const char *acl_name
;
161 struct v9fs_session_info
*v9ses
;
162 struct inode
*inode
= d_inode(dentry
);
165 retval
= posix_acl_valid(inode
->i_sb
->s_user_ns
, acl
);
169 size
= posix_acl_xattr_size(acl
->a_count
);
171 value
= kzalloc(size
, GFP_NOFS
);
177 retval
= posix_acl_to_xattr(&init_user_ns
, acl
, value
, size
);
183 * set the attribute on the remote. Without even looking at the
184 * xattr value. We leave it to the server to validate
186 acl_name
= posix_acl_xattr_name(type
);
187 v9ses
= v9fs_dentry2v9ses(dentry
);
188 if ((v9ses
->flags
& V9FS_ACCESS_MASK
) != V9FS_ACCESS_CLIENT
) {
189 retval
= v9fs_xattr_set(dentry
, acl_name
, value
, size
, 0);
193 if (S_ISLNK(inode
->i_mode
)) {
194 retval
= -EOPNOTSUPP
;
198 if (!inode_owner_or_capable(&nop_mnt_idmap
, inode
)) {
204 case ACL_TYPE_ACCESS
:
206 struct iattr iattr
= {};
207 struct posix_acl
*acl_mode
= acl
;
209 retval
= posix_acl_update_mode(&nop_mnt_idmap
, inode
,
216 * ACL can be represented by the mode bits.
217 * So don't update ACL below.
223 iattr
.ia_valid
= ATTR_MODE
;
225 * FIXME should we update ctime ?
226 * What is the following setxattr update the mode ?
228 v9fs_vfs_setattr_dotl(&nop_mnt_idmap
, dentry
, &iattr
);
231 case ACL_TYPE_DEFAULT
:
232 if (!S_ISDIR(inode
->i_mode
)) {
233 retval
= acl
? -EINVAL
: 0;
239 retval
= v9fs_xattr_set(dentry
, acl_name
, value
, size
, 0);
241 set_cached_acl(inode
, type
, acl
);
248 static int v9fs_set_acl(struct p9_fid
*fid
, int type
, struct posix_acl
*acl
)
258 /* Set a setxattr request to server */
259 size
= posix_acl_xattr_size(acl
->a_count
);
260 buffer
= kmalloc(size
, GFP_KERNEL
);
263 retval
= posix_acl_to_xattr(&init_user_ns
, acl
, buffer
, size
);
267 case ACL_TYPE_ACCESS
:
268 name
= XATTR_NAME_POSIX_ACL_ACCESS
;
270 case ACL_TYPE_DEFAULT
:
271 name
= XATTR_NAME_POSIX_ACL_DEFAULT
;
276 retval
= v9fs_fid_xattr_set(fid
, name
, buffer
, size
, 0);
282 int v9fs_acl_chmod(struct inode
*inode
, struct p9_fid
*fid
)
285 struct posix_acl
*acl
;
287 if (S_ISLNK(inode
->i_mode
))
289 acl
= v9fs_get_cached_acl(inode
, ACL_TYPE_ACCESS
);
291 retval
= __posix_acl_chmod(&acl
, GFP_KERNEL
, inode
->i_mode
);
294 set_cached_acl(inode
, ACL_TYPE_ACCESS
, acl
);
295 retval
= v9fs_set_acl(fid
, ACL_TYPE_ACCESS
, acl
);
296 posix_acl_release(acl
);
301 int v9fs_set_create_acl(struct inode
*inode
, struct p9_fid
*fid
,
302 struct posix_acl
*dacl
, struct posix_acl
*acl
)
304 set_cached_acl(inode
, ACL_TYPE_DEFAULT
, dacl
);
305 set_cached_acl(inode
, ACL_TYPE_ACCESS
, acl
);
306 v9fs_set_acl(fid
, ACL_TYPE_DEFAULT
, dacl
);
307 v9fs_set_acl(fid
, ACL_TYPE_ACCESS
, acl
);
311 void v9fs_put_acl(struct posix_acl
*dacl
,
312 struct posix_acl
*acl
)
314 posix_acl_release(dacl
);
315 posix_acl_release(acl
);
318 int v9fs_acl_mode(struct inode
*dir
, umode_t
*modep
,
319 struct posix_acl
**dpacl
, struct posix_acl
**pacl
)
322 umode_t mode
= *modep
;
323 struct posix_acl
*acl
= NULL
;
325 if (!S_ISLNK(mode
)) {
326 acl
= v9fs_get_cached_acl(dir
, ACL_TYPE_DEFAULT
);
330 mode
&= ~current_umask();
334 *dpacl
= posix_acl_dup(acl
);
335 retval
= __posix_acl_create(&acl
, GFP_NOFS
, &mode
);
341 posix_acl_release(acl
);