1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Extended attribute handling for AFS. We use xattrs to get and set metadata
3 * instead of providing pioctl().
5 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
6 * Written by David Howells (dhowells@redhat.com)
9 #include <linux/slab.h>
11 #include <linux/xattr.h>
14 static const char afs_xattr_list
[] =
20 "afs.yfs.acl_inherited\0"
21 "afs.yfs.acl_num_cleaned\0"
25 * Retrieve a list of the supported xattrs.
27 ssize_t
afs_listxattr(struct dentry
*dentry
, char *buffer
, size_t size
)
30 return sizeof(afs_xattr_list
);
31 if (size
< sizeof(afs_xattr_list
))
33 memcpy(buffer
, afs_xattr_list
, sizeof(afs_xattr_list
));
34 return sizeof(afs_xattr_list
);
40 static int afs_xattr_get_acl(const struct xattr_handler
*handler
,
41 struct dentry
*dentry
,
42 struct inode
*inode
, const char *name
,
43 void *buffer
, size_t size
)
45 struct afs_fs_cursor fc
;
46 struct afs_status_cb
*scb
;
47 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
48 struct afs_acl
*acl
= NULL
;
52 scb
= kzalloc(sizeof(struct afs_status_cb
), GFP_NOFS
);
56 key
= afs_request_key(vnode
->volume
->cell
);
63 if (afs_begin_vnode_operation(&fc
, vnode
, key
, true)) {
64 afs_dataversion_t data_version
= vnode
->status
.data_version
;
66 while (afs_select_fileserver(&fc
)) {
67 fc
.cb_break
= afs_calc_vnode_cb_break(vnode
);
68 acl
= afs_fs_fetch_acl(&fc
, scb
);
71 afs_check_for_remote_deletion(&fc
, fc
.vnode
);
72 afs_vnode_commit_status(&fc
, vnode
, fc
.cb_break
,
74 ret
= afs_end_vnode_operation(&fc
);
80 if (acl
->size
<= size
)
81 memcpy(buffer
, acl
->data
, acl
->size
);
96 * Set a file's AFS3 ACL.
98 static int afs_xattr_set_acl(const struct xattr_handler
*handler
,
99 struct dentry
*dentry
,
100 struct inode
*inode
, const char *name
,
101 const void *buffer
, size_t size
, int flags
)
103 struct afs_fs_cursor fc
;
104 struct afs_status_cb
*scb
;
105 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
106 struct afs_acl
*acl
= NULL
;
110 if (flags
== XATTR_CREATE
)
113 scb
= kzalloc(sizeof(struct afs_status_cb
), GFP_NOFS
);
117 acl
= kmalloc(sizeof(*acl
) + size
, GFP_KERNEL
);
121 key
= afs_request_key(vnode
->volume
->cell
);
128 memcpy(acl
->data
, buffer
, size
);
131 if (afs_begin_vnode_operation(&fc
, vnode
, key
, true)) {
132 afs_dataversion_t data_version
= vnode
->status
.data_version
;
134 while (afs_select_fileserver(&fc
)) {
135 fc
.cb_break
= afs_calc_vnode_cb_break(vnode
);
136 afs_fs_store_acl(&fc
, acl
, scb
);
139 afs_check_for_remote_deletion(&fc
, fc
.vnode
);
140 afs_vnode_commit_status(&fc
, vnode
, fc
.cb_break
,
142 ret
= afs_end_vnode_operation(&fc
);
154 static const struct xattr_handler afs_xattr_afs_acl_handler
= {
156 .get
= afs_xattr_get_acl
,
157 .set
= afs_xattr_set_acl
,
161 * Get a file's YFS ACL.
163 static int afs_xattr_get_yfs(const struct xattr_handler
*handler
,
164 struct dentry
*dentry
,
165 struct inode
*inode
, const char *name
,
166 void *buffer
, size_t size
)
168 struct afs_fs_cursor fc
;
169 struct afs_status_cb
*scb
;
170 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
171 struct yfs_acl
*yacl
= NULL
;
174 int which
= 0, dsize
, ret
= -ENOMEM
;
176 if (strcmp(name
, "acl") == 0)
178 else if (strcmp(name
, "acl_inherited") == 0)
180 else if (strcmp(name
, "acl_num_cleaned") == 0)
182 else if (strcmp(name
, "vol_acl") == 0)
187 yacl
= kzalloc(sizeof(struct yfs_acl
), GFP_KERNEL
);
192 yacl
->flags
|= YFS_ACL_WANT_ACL
;
194 yacl
->flags
|= YFS_ACL_WANT_VOL_ACL
;
196 scb
= kzalloc(sizeof(struct afs_status_cb
), GFP_NOFS
);
200 key
= afs_request_key(vnode
->volume
->cell
);
207 if (afs_begin_vnode_operation(&fc
, vnode
, key
, true)) {
208 afs_dataversion_t data_version
= vnode
->status
.data_version
;
210 while (afs_select_fileserver(&fc
)) {
211 fc
.cb_break
= afs_calc_vnode_cb_break(vnode
);
212 yfs_fs_fetch_opaque_acl(&fc
, yacl
, scb
);
215 afs_check_for_remote_deletion(&fc
, fc
.vnode
);
216 afs_vnode_commit_status(&fc
, vnode
, fc
.cb_break
,
218 ret
= afs_end_vnode_operation(&fc
);
226 data
= yacl
->acl
->data
;
227 dsize
= yacl
->acl
->size
;
231 dsize
= scnprintf(buf
, sizeof(buf
), "%u", yacl
->inherit_flag
);
235 dsize
= scnprintf(buf
, sizeof(buf
), "%u", yacl
->num_cleaned
);
238 data
= yacl
->vol_acl
->data
;
239 dsize
= yacl
->vol_acl
->size
;
252 memcpy(buffer
, data
, dsize
);
260 yfs_free_opaque_acl(yacl
);
266 * Set a file's YFS ACL.
268 static int afs_xattr_set_yfs(const struct xattr_handler
*handler
,
269 struct dentry
*dentry
,
270 struct inode
*inode
, const char *name
,
271 const void *buffer
, size_t size
, int flags
)
273 struct afs_fs_cursor fc
;
274 struct afs_status_cb
*scb
;
275 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
276 struct afs_acl
*acl
= NULL
;
280 if (flags
== XATTR_CREATE
||
281 strcmp(name
, "acl") != 0)
284 scb
= kzalloc(sizeof(struct afs_status_cb
), GFP_NOFS
);
288 acl
= kmalloc(sizeof(*acl
) + size
, GFP_KERNEL
);
293 memcpy(acl
->data
, buffer
, size
);
295 key
= afs_request_key(vnode
->volume
->cell
);
302 if (afs_begin_vnode_operation(&fc
, vnode
, key
, true)) {
303 afs_dataversion_t data_version
= vnode
->status
.data_version
;
305 while (afs_select_fileserver(&fc
)) {
306 fc
.cb_break
= afs_calc_vnode_cb_break(vnode
);
307 yfs_fs_store_opaque_acl2(&fc
, acl
, scb
);
310 afs_check_for_remote_deletion(&fc
, fc
.vnode
);
311 afs_vnode_commit_status(&fc
, vnode
, fc
.cb_break
,
313 ret
= afs_end_vnode_operation(&fc
);
325 static const struct xattr_handler afs_xattr_yfs_handler
= {
326 .prefix
= "afs.yfs.",
327 .get
= afs_xattr_get_yfs
,
328 .set
= afs_xattr_set_yfs
,
332 * Get the name of the cell on which a file resides.
334 static int afs_xattr_get_cell(const struct xattr_handler
*handler
,
335 struct dentry
*dentry
,
336 struct inode
*inode
, const char *name
,
337 void *buffer
, size_t size
)
339 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
340 struct afs_cell
*cell
= vnode
->volume
->cell
;
343 namelen
= cell
->name_len
;
348 memcpy(buffer
, cell
->name
, namelen
);
352 static const struct xattr_handler afs_xattr_afs_cell_handler
= {
354 .get
= afs_xattr_get_cell
,
358 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
359 * hex numbers separated by colons.
361 static int afs_xattr_get_fid(const struct xattr_handler
*handler
,
362 struct dentry
*dentry
,
363 struct inode
*inode
, const char *name
,
364 void *buffer
, size_t size
)
366 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
367 char text
[16 + 1 + 24 + 1 + 8 + 1];
370 /* The volume ID is 64-bit, the vnode ID is 96-bit and the
371 * uniquifier is 32-bit.
373 len
= scnprintf(text
, sizeof(text
), "%llx:", vnode
->fid
.vid
);
374 if (vnode
->fid
.vnode_hi
)
375 len
+= scnprintf(text
+ len
, sizeof(text
) - len
, "%x%016llx",
376 vnode
->fid
.vnode_hi
, vnode
->fid
.vnode
);
378 len
+= scnprintf(text
+ len
, sizeof(text
) - len
, "%llx",
380 len
+= scnprintf(text
+ len
, sizeof(text
) - len
, ":%x",
387 memcpy(buffer
, text
, len
);
391 static const struct xattr_handler afs_xattr_afs_fid_handler
= {
393 .get
= afs_xattr_get_fid
,
397 * Get the name of the volume on which a file resides.
399 static int afs_xattr_get_volume(const struct xattr_handler
*handler
,
400 struct dentry
*dentry
,
401 struct inode
*inode
, const char *name
,
402 void *buffer
, size_t size
)
404 struct afs_vnode
*vnode
= AFS_FS_I(inode
);
405 const char *volname
= vnode
->volume
->name
;
408 namelen
= strlen(volname
);
413 memcpy(buffer
, volname
, namelen
);
417 static const struct xattr_handler afs_xattr_afs_volume_handler
= {
418 .name
= "afs.volume",
419 .get
= afs_xattr_get_volume
,
422 const struct xattr_handler
*afs_xattr_handlers
[] = {
423 &afs_xattr_afs_acl_handler
,
424 &afs_xattr_afs_cell_handler
,
425 &afs_xattr_afs_fid_handler
,
426 &afs_xattr_afs_volume_handler
,
427 &afs_xattr_yfs_handler
, /* afs.yfs. prefix */