1 /* Extended attribute handling for AFS. We use xattrs to get and set metadata
2 * instead of providing pioctl().
4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
13 #include <linux/slab.h>
15 #include <linux/xattr.h>
18 static const char afs_xattr_list[] =
24 "afs.yfs.acl_inherited\0"
25 "afs.yfs.acl_num_cleaned\0"
29 * Retrieve a list of the supported xattrs.
31 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
34 return sizeof(afs_xattr_list);
35 if (size < sizeof(afs_xattr_list))
37 memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
38 return sizeof(afs_xattr_list);
44 static int afs_xattr_get_acl(const struct xattr_handler *handler,
45 struct dentry *dentry,
46 struct inode *inode, const char *name,
47 void *buffer, size_t size)
49 struct afs_fs_cursor fc;
50 struct afs_vnode *vnode = AFS_FS_I(inode);
51 struct afs_acl *acl = NULL;
55 key = afs_request_key(vnode->volume->cell);
60 if (afs_begin_vnode_operation(&fc, vnode, key)) {
61 while (afs_select_fileserver(&fc)) {
62 fc.cb_break = afs_calc_vnode_cb_break(vnode);
63 acl = afs_fs_fetch_acl(&fc);
66 afs_check_for_remote_deletion(&fc, fc.vnode);
67 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
68 ret = afs_end_vnode_operation(&fc);
74 if (acl->size <= size)
75 memcpy(buffer, acl->data, acl->size);
87 * Set a file's AFS3 ACL.
89 static int afs_xattr_set_acl(const struct xattr_handler *handler,
90 struct dentry *dentry,
91 struct inode *inode, const char *name,
92 const void *buffer, size_t size, int flags)
94 struct afs_fs_cursor fc;
95 struct afs_vnode *vnode = AFS_FS_I(inode);
96 struct afs_acl *acl = NULL;
100 if (flags == XATTR_CREATE)
103 key = afs_request_key(vnode->volume->cell);
107 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
114 memcpy(acl->data, buffer, size);
117 if (afs_begin_vnode_operation(&fc, vnode, key)) {
118 while (afs_select_fileserver(&fc)) {
119 fc.cb_break = afs_calc_vnode_cb_break(vnode);
120 afs_fs_store_acl(&fc, acl);
123 afs_check_for_remote_deletion(&fc, fc.vnode);
124 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
125 ret = afs_end_vnode_operation(&fc);
133 static const struct xattr_handler afs_xattr_afs_acl_handler = {
135 .get = afs_xattr_get_acl,
136 .set = afs_xattr_set_acl,
140 * Get a file's YFS ACL.
142 static int afs_xattr_get_yfs(const struct xattr_handler *handler,
143 struct dentry *dentry,
144 struct inode *inode, const char *name,
145 void *buffer, size_t size)
147 struct afs_fs_cursor fc;
148 struct afs_vnode *vnode = AFS_FS_I(inode);
149 struct yfs_acl *yacl = NULL;
152 int which = 0, dsize, ret = -ENOMEM;
154 if (strcmp(name, "acl") == 0)
156 else if (strcmp(name, "acl_inherited") == 0)
158 else if (strcmp(name, "acl_num_cleaned") == 0)
160 else if (strcmp(name, "vol_acl") == 0)
165 yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
170 yacl->flags |= YFS_ACL_WANT_ACL;
172 yacl->flags |= YFS_ACL_WANT_VOL_ACL;
174 key = afs_request_key(vnode->volume->cell);
181 if (afs_begin_vnode_operation(&fc, vnode, key)) {
182 while (afs_select_fileserver(&fc)) {
183 fc.cb_break = afs_calc_vnode_cb_break(vnode);
184 yfs_fs_fetch_opaque_acl(&fc, yacl);
187 afs_check_for_remote_deletion(&fc, fc.vnode);
188 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
189 ret = afs_end_vnode_operation(&fc);
197 data = yacl->acl->data;
198 dsize = yacl->acl->size;
202 dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
206 dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
209 data = yacl->vol_acl->data;
210 dsize = yacl->vol_acl->size;
223 memcpy(buffer, data, dsize);
229 yfs_free_opaque_acl(yacl);
235 * Set a file's YFS ACL.
237 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
238 struct dentry *dentry,
239 struct inode *inode, const char *name,
240 const void *buffer, size_t size, int flags)
242 struct afs_fs_cursor fc;
243 struct afs_vnode *vnode = AFS_FS_I(inode);
244 struct afs_acl *acl = NULL;
248 if (flags == XATTR_CREATE ||
249 strcmp(name, "acl") != 0)
252 key = afs_request_key(vnode->volume->cell);
256 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
263 memcpy(acl->data, buffer, size);
266 if (afs_begin_vnode_operation(&fc, vnode, key)) {
267 while (afs_select_fileserver(&fc)) {
268 fc.cb_break = afs_calc_vnode_cb_break(vnode);
269 yfs_fs_store_opaque_acl2(&fc, acl);
272 afs_check_for_remote_deletion(&fc, fc.vnode);
273 afs_vnode_commit_status(&fc, vnode, fc.cb_break);
274 ret = afs_end_vnode_operation(&fc);
282 static const struct xattr_handler afs_xattr_yfs_handler = {
283 .prefix = "afs.yfs.",
284 .get = afs_xattr_get_yfs,
285 .set = afs_xattr_set_yfs,
289 * Get the name of the cell on which a file resides.
291 static int afs_xattr_get_cell(const struct xattr_handler *handler,
292 struct dentry *dentry,
293 struct inode *inode, const char *name,
294 void *buffer, size_t size)
296 struct afs_vnode *vnode = AFS_FS_I(inode);
297 struct afs_cell *cell = vnode->volume->cell;
300 namelen = cell->name_len;
305 memcpy(buffer, cell->name, namelen);
309 static const struct xattr_handler afs_xattr_afs_cell_handler = {
311 .get = afs_xattr_get_cell,
315 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
316 * hex numbers separated by colons.
318 static int afs_xattr_get_fid(const struct xattr_handler *handler,
319 struct dentry *dentry,
320 struct inode *inode, const char *name,
321 void *buffer, size_t size)
323 struct afs_vnode *vnode = AFS_FS_I(inode);
324 char text[16 + 1 + 24 + 1 + 8 + 1];
327 /* The volume ID is 64-bit, the vnode ID is 96-bit and the
328 * uniquifier is 32-bit.
330 len = sprintf(text, "%llx:", vnode->fid.vid);
331 if (vnode->fid.vnode_hi)
332 len += sprintf(text + len, "%x%016llx",
333 vnode->fid.vnode_hi, vnode->fid.vnode);
335 len += sprintf(text + len, "%llx", vnode->fid.vnode);
336 len += sprintf(text + len, ":%x", vnode->fid.unique);
342 memcpy(buffer, text, len);
346 static const struct xattr_handler afs_xattr_afs_fid_handler = {
348 .get = afs_xattr_get_fid,
352 * Get the name of the volume on which a file resides.
354 static int afs_xattr_get_volume(const struct xattr_handler *handler,
355 struct dentry *dentry,
356 struct inode *inode, const char *name,
357 void *buffer, size_t size)
359 struct afs_vnode *vnode = AFS_FS_I(inode);
360 const char *volname = vnode->volume->name;
363 namelen = strlen(volname);
368 memcpy(buffer, volname, namelen);
372 static const struct xattr_handler afs_xattr_afs_volume_handler = {
373 .name = "afs.volume",
374 .get = afs_xattr_get_volume,
377 const struct xattr_handler *afs_xattr_handlers[] = {
378 &afs_xattr_afs_acl_handler,
379 &afs_xattr_afs_cell_handler,
380 &afs_xattr_afs_fid_handler,
381 &afs_xattr_afs_volume_handler,
382 &afs_xattr_yfs_handler, /* afs.yfs. prefix */