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>
17 static int afs_xattr_get_acl(const struct xattr_handler *handler,
18 struct dentry *dentry,
19 struct inode *inode, const char *name,
20 void *buffer, size_t size)
22 struct afs_fs_cursor fc;
23 struct afs_status_cb *scb;
24 struct afs_vnode *vnode = AFS_FS_I(inode);
25 struct afs_acl *acl = NULL;
29 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
33 key = afs_request_key(vnode->volume->cell);
40 if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
41 afs_dataversion_t data_version = vnode->status.data_version;
43 while (afs_select_fileserver(&fc)) {
44 fc.cb_break = afs_calc_vnode_cb_break(vnode);
45 acl = afs_fs_fetch_acl(&fc, scb);
48 afs_check_for_remote_deletion(&fc, fc.vnode);
49 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
51 ret = afs_end_vnode_operation(&fc);
57 if (acl->size <= size)
58 memcpy(buffer, acl->data, acl->size);
73 * Set a file's AFS3 ACL.
75 static int afs_xattr_set_acl(const struct xattr_handler *handler,
76 struct dentry *dentry,
77 struct inode *inode, const char *name,
78 const void *buffer, size_t size, int flags)
80 struct afs_fs_cursor fc;
81 struct afs_status_cb *scb;
82 struct afs_vnode *vnode = AFS_FS_I(inode);
83 struct afs_acl *acl = NULL;
87 if (flags == XATTR_CREATE)
90 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
94 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
98 key = afs_request_key(vnode->volume->cell);
105 memcpy(acl->data, buffer, size);
108 if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
109 afs_dataversion_t data_version = vnode->status.data_version;
111 while (afs_select_fileserver(&fc)) {
112 fc.cb_break = afs_calc_vnode_cb_break(vnode);
113 afs_fs_store_acl(&fc, acl, scb);
116 afs_check_for_remote_deletion(&fc, fc.vnode);
117 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
119 ret = afs_end_vnode_operation(&fc);
131 static const struct xattr_handler afs_xattr_afs_acl_handler = {
133 .get = afs_xattr_get_acl,
134 .set = afs_xattr_set_acl,
138 * Get a file's YFS ACL.
140 static int afs_xattr_get_yfs(const struct xattr_handler *handler,
141 struct dentry *dentry,
142 struct inode *inode, const char *name,
143 void *buffer, size_t size)
145 struct afs_fs_cursor fc;
146 struct afs_status_cb *scb;
147 struct afs_vnode *vnode = AFS_FS_I(inode);
148 struct yfs_acl *yacl = NULL;
151 int which = 0, dsize, ret = -ENOMEM;
153 if (strcmp(name, "acl") == 0)
155 else if (strcmp(name, "acl_inherited") == 0)
157 else if (strcmp(name, "acl_num_cleaned") == 0)
159 else if (strcmp(name, "vol_acl") == 0)
164 yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
169 yacl->flags |= YFS_ACL_WANT_ACL;
171 yacl->flags |= YFS_ACL_WANT_VOL_ACL;
173 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
177 key = afs_request_key(vnode->volume->cell);
184 if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
185 afs_dataversion_t data_version = vnode->status.data_version;
187 while (afs_select_fileserver(&fc)) {
188 fc.cb_break = afs_calc_vnode_cb_break(vnode);
189 yfs_fs_fetch_opaque_acl(&fc, yacl, scb);
192 afs_check_for_remote_deletion(&fc, fc.vnode);
193 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
195 ret = afs_end_vnode_operation(&fc);
203 data = yacl->acl->data;
204 dsize = yacl->acl->size;
208 dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
212 dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
215 data = yacl->vol_acl->data;
216 dsize = yacl->vol_acl->size;
229 memcpy(buffer, data, dsize);
237 yfs_free_opaque_acl(yacl);
243 * Set a file's YFS ACL.
245 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
246 struct dentry *dentry,
247 struct inode *inode, const char *name,
248 const void *buffer, size_t size, int flags)
250 struct afs_fs_cursor fc;
251 struct afs_status_cb *scb;
252 struct afs_vnode *vnode = AFS_FS_I(inode);
253 struct afs_acl *acl = NULL;
257 if (flags == XATTR_CREATE ||
258 strcmp(name, "acl") != 0)
261 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
265 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
270 memcpy(acl->data, buffer, size);
272 key = afs_request_key(vnode->volume->cell);
279 if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
280 afs_dataversion_t data_version = vnode->status.data_version;
282 while (afs_select_fileserver(&fc)) {
283 fc.cb_break = afs_calc_vnode_cb_break(vnode);
284 yfs_fs_store_opaque_acl2(&fc, acl, scb);
287 afs_check_for_remote_deletion(&fc, fc.vnode);
288 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
290 ret = afs_end_vnode_operation(&fc);
302 static const struct xattr_handler afs_xattr_yfs_handler = {
303 .prefix = "afs.yfs.",
304 .get = afs_xattr_get_yfs,
305 .set = afs_xattr_set_yfs,
309 * Get the name of the cell on which a file resides.
311 static int afs_xattr_get_cell(const struct xattr_handler *handler,
312 struct dentry *dentry,
313 struct inode *inode, const char *name,
314 void *buffer, size_t size)
316 struct afs_vnode *vnode = AFS_FS_I(inode);
317 struct afs_cell *cell = vnode->volume->cell;
320 namelen = cell->name_len;
325 memcpy(buffer, cell->name, namelen);
329 static const struct xattr_handler afs_xattr_afs_cell_handler = {
331 .get = afs_xattr_get_cell,
335 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
336 * hex numbers separated by colons.
338 static int afs_xattr_get_fid(const struct xattr_handler *handler,
339 struct dentry *dentry,
340 struct inode *inode, const char *name,
341 void *buffer, size_t size)
343 struct afs_vnode *vnode = AFS_FS_I(inode);
344 char text[16 + 1 + 24 + 1 + 8 + 1];
347 /* The volume ID is 64-bit, the vnode ID is 96-bit and the
348 * uniquifier is 32-bit.
350 len = sprintf(text, "%llx:", vnode->fid.vid);
351 if (vnode->fid.vnode_hi)
352 len += sprintf(text + len, "%x%016llx",
353 vnode->fid.vnode_hi, vnode->fid.vnode);
355 len += sprintf(text + len, "%llx", vnode->fid.vnode);
356 len += sprintf(text + len, ":%x", vnode->fid.unique);
362 memcpy(buffer, text, len);
366 static const struct xattr_handler afs_xattr_afs_fid_handler = {
368 .get = afs_xattr_get_fid,
372 * Get the name of the volume on which a file resides.
374 static int afs_xattr_get_volume(const struct xattr_handler *handler,
375 struct dentry *dentry,
376 struct inode *inode, const char *name,
377 void *buffer, size_t size)
379 struct afs_vnode *vnode = AFS_FS_I(inode);
380 const char *volname = vnode->volume->name;
383 namelen = strlen(volname);
388 memcpy(buffer, volname, namelen);
392 static const struct xattr_handler afs_xattr_afs_volume_handler = {
393 .name = "afs.volume",
394 .get = afs_xattr_get_volume,
397 const struct xattr_handler *afs_xattr_handlers[] = {
398 &afs_xattr_afs_acl_handler,
399 &afs_xattr_afs_cell_handler,
400 &afs_xattr_afs_fid_handler,
401 &afs_xattr_afs_volume_handler,
402 &afs_xattr_yfs_handler, /* afs.yfs. prefix */