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 = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
235 dsize = snprintf(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 = sprintf(text, "%llx:", vnode->fid.vid);
374 if (vnode->fid.vnode_hi)
375 len += sprintf(text + len, "%x%016llx",
376 vnode->fid.vnode_hi, vnode->fid.vnode);
378 len += sprintf(text + len, "%llx", vnode->fid.vnode);
379 len += sprintf(text + len, ":%x", vnode->fid.unique);
385 memcpy(buffer, text, len);
389 static const struct xattr_handler afs_xattr_afs_fid_handler = {
391 .get = afs_xattr_get_fid,
395 * Get the name of the volume on which a file resides.
397 static int afs_xattr_get_volume(const struct xattr_handler *handler,
398 struct dentry *dentry,
399 struct inode *inode, const char *name,
400 void *buffer, size_t size)
402 struct afs_vnode *vnode = AFS_FS_I(inode);
403 const char *volname = vnode->volume->name;
406 namelen = strlen(volname);
411 memcpy(buffer, volname, namelen);
415 static const struct xattr_handler afs_xattr_afs_volume_handler = {
416 .name = "afs.volume",
417 .get = afs_xattr_get_volume,
420 const struct xattr_handler *afs_xattr_handlers[] = {
421 &afs_xattr_afs_acl_handler,
422 &afs_xattr_afs_cell_handler,
423 &afs_xattr_afs_fid_handler,
424 &afs_xattr_afs_volume_handler,
425 &afs_xattr_yfs_handler, /* afs.yfs. prefix */