1d3e3b7eaSDavid Howells /* Extended attribute handling for AFS. We use xattrs to get and set metadata 2d3e3b7eaSDavid Howells * instead of providing pioctl(). 3d3e3b7eaSDavid Howells * 4d3e3b7eaSDavid Howells * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 5d3e3b7eaSDavid Howells * Written by David Howells (dhowells@redhat.com) 6d3e3b7eaSDavid Howells * 7d3e3b7eaSDavid Howells * This program is free software; you can redistribute it and/or 8d3e3b7eaSDavid Howells * modify it under the terms of the GNU General Public Licence 9d3e3b7eaSDavid Howells * as published by the Free Software Foundation; either version 10d3e3b7eaSDavid Howells * 2 of the Licence, or (at your option) any later version. 11d3e3b7eaSDavid Howells */ 12d3e3b7eaSDavid Howells 13d3e3b7eaSDavid Howells #include <linux/slab.h> 14d3e3b7eaSDavid Howells #include <linux/fs.h> 15d3e3b7eaSDavid Howells #include <linux/xattr.h> 16d3e3b7eaSDavid Howells #include "internal.h" 17d3e3b7eaSDavid Howells 18d3e3b7eaSDavid Howells static const char afs_xattr_list[] = 19260f082bSDavid Howells "afs.acl\0" 20d3e3b7eaSDavid Howells "afs.cell\0" 21d3e3b7eaSDavid Howells "afs.fid\0" 22d3e3b7eaSDavid Howells "afs.volume"; 23d3e3b7eaSDavid Howells 24d3e3b7eaSDavid Howells /* 25d3e3b7eaSDavid Howells * Retrieve a list of the supported xattrs. 26d3e3b7eaSDavid Howells */ 27d3e3b7eaSDavid Howells ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) 28d3e3b7eaSDavid Howells { 29d3e3b7eaSDavid Howells if (size == 0) 30d3e3b7eaSDavid Howells return sizeof(afs_xattr_list); 31d3e3b7eaSDavid Howells if (size < sizeof(afs_xattr_list)) 32d3e3b7eaSDavid Howells return -ERANGE; 33d3e3b7eaSDavid Howells memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list)); 34d3e3b7eaSDavid Howells return sizeof(afs_xattr_list); 35d3e3b7eaSDavid Howells } 36d3e3b7eaSDavid Howells 37d3e3b7eaSDavid Howells /* 38260f082bSDavid Howells * Get a file's ACL. 39260f082bSDavid Howells */ 40260f082bSDavid Howells static int afs_xattr_get_acl(const struct xattr_handler *handler, 41260f082bSDavid Howells struct dentry *dentry, 42260f082bSDavid Howells struct inode *inode, const char *name, 43260f082bSDavid Howells void *buffer, size_t size) 44260f082bSDavid Howells { 45260f082bSDavid Howells struct afs_fs_cursor fc; 46260f082bSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 47260f082bSDavid Howells struct afs_acl *acl = NULL; 48260f082bSDavid Howells struct key *key; 49260f082bSDavid Howells int ret; 50260f082bSDavid Howells 51260f082bSDavid Howells key = afs_request_key(vnode->volume->cell); 52260f082bSDavid Howells if (IS_ERR(key)) 53260f082bSDavid Howells return PTR_ERR(key); 54260f082bSDavid Howells 55260f082bSDavid Howells ret = -ERESTARTSYS; 56260f082bSDavid Howells if (afs_begin_vnode_operation(&fc, vnode, key)) { 57260f082bSDavid Howells while (afs_select_fileserver(&fc)) { 58260f082bSDavid Howells fc.cb_break = afs_calc_vnode_cb_break(vnode); 59260f082bSDavid Howells acl = afs_fs_fetch_acl(&fc); 60260f082bSDavid Howells } 61260f082bSDavid Howells 62260f082bSDavid Howells afs_check_for_remote_deletion(&fc, fc.vnode); 63260f082bSDavid Howells afs_vnode_commit_status(&fc, vnode, fc.cb_break); 64260f082bSDavid Howells ret = afs_end_vnode_operation(&fc); 65260f082bSDavid Howells } 66260f082bSDavid Howells 67260f082bSDavid Howells if (ret == 0) { 68260f082bSDavid Howells ret = acl->size; 69260f082bSDavid Howells if (size > 0) { 70260f082bSDavid Howells ret = -ERANGE; 71260f082bSDavid Howells if (acl->size > size) 72260f082bSDavid Howells return -ERANGE; 73260f082bSDavid Howells memcpy(buffer, acl->data, acl->size); 74260f082bSDavid Howells ret = acl->size; 75260f082bSDavid Howells } 76260f082bSDavid Howells kfree(acl); 77260f082bSDavid Howells } 78260f082bSDavid Howells 79260f082bSDavid Howells key_put(key); 80260f082bSDavid Howells return ret; 81260f082bSDavid Howells } 82260f082bSDavid Howells 83*b10494afSJoe Gorse /* 84*b10494afSJoe Gorse * Set a file's AFS3 ACL. 85*b10494afSJoe Gorse */ 86*b10494afSJoe Gorse static int afs_xattr_set_acl(const struct xattr_handler *handler, 87*b10494afSJoe Gorse struct dentry *dentry, 88*b10494afSJoe Gorse struct inode *inode, const char *name, 89*b10494afSJoe Gorse const void *buffer, size_t size, int flags) 90*b10494afSJoe Gorse { 91*b10494afSJoe Gorse struct afs_fs_cursor fc; 92*b10494afSJoe Gorse struct afs_vnode *vnode = AFS_FS_I(inode); 93*b10494afSJoe Gorse struct afs_acl *acl = NULL; 94*b10494afSJoe Gorse struct key *key; 95*b10494afSJoe Gorse int ret; 96*b10494afSJoe Gorse 97*b10494afSJoe Gorse if (flags == XATTR_CREATE) 98*b10494afSJoe Gorse return -EINVAL; 99*b10494afSJoe Gorse 100*b10494afSJoe Gorse key = afs_request_key(vnode->volume->cell); 101*b10494afSJoe Gorse if (IS_ERR(key)) 102*b10494afSJoe Gorse return PTR_ERR(key); 103*b10494afSJoe Gorse 104*b10494afSJoe Gorse acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 105*b10494afSJoe Gorse if (!acl) { 106*b10494afSJoe Gorse key_put(key); 107*b10494afSJoe Gorse return -ENOMEM; 108*b10494afSJoe Gorse } 109*b10494afSJoe Gorse 110*b10494afSJoe Gorse acl->size = size; 111*b10494afSJoe Gorse memcpy(acl->data, buffer, size); 112*b10494afSJoe Gorse 113*b10494afSJoe Gorse ret = -ERESTARTSYS; 114*b10494afSJoe Gorse if (afs_begin_vnode_operation(&fc, vnode, key)) { 115*b10494afSJoe Gorse while (afs_select_fileserver(&fc)) { 116*b10494afSJoe Gorse fc.cb_break = afs_calc_vnode_cb_break(vnode); 117*b10494afSJoe Gorse afs_fs_store_acl(&fc, acl); 118*b10494afSJoe Gorse } 119*b10494afSJoe Gorse 120*b10494afSJoe Gorse afs_check_for_remote_deletion(&fc, fc.vnode); 121*b10494afSJoe Gorse afs_vnode_commit_status(&fc, vnode, fc.cb_break); 122*b10494afSJoe Gorse ret = afs_end_vnode_operation(&fc); 123*b10494afSJoe Gorse } 124*b10494afSJoe Gorse 125*b10494afSJoe Gorse kfree(acl); 126*b10494afSJoe Gorse key_put(key); 127*b10494afSJoe Gorse return ret; 128*b10494afSJoe Gorse } 129*b10494afSJoe Gorse 130260f082bSDavid Howells static const struct xattr_handler afs_xattr_afs_acl_handler = { 131260f082bSDavid Howells .name = "afs.acl", 132260f082bSDavid Howells .get = afs_xattr_get_acl, 133*b10494afSJoe Gorse .set = afs_xattr_set_acl, 134260f082bSDavid Howells }; 135260f082bSDavid Howells 136260f082bSDavid Howells /* 137d3e3b7eaSDavid Howells * Get the name of the cell on which a file resides. 138d3e3b7eaSDavid Howells */ 139d3e3b7eaSDavid Howells static int afs_xattr_get_cell(const struct xattr_handler *handler, 140d3e3b7eaSDavid Howells struct dentry *dentry, 141d3e3b7eaSDavid Howells struct inode *inode, const char *name, 142d3e3b7eaSDavid Howells void *buffer, size_t size) 143d3e3b7eaSDavid Howells { 144d3e3b7eaSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 145d3e3b7eaSDavid Howells struct afs_cell *cell = vnode->volume->cell; 146d3e3b7eaSDavid Howells size_t namelen; 147d3e3b7eaSDavid Howells 148989782dcSDavid Howells namelen = cell->name_len; 149d3e3b7eaSDavid Howells if (size == 0) 150d3e3b7eaSDavid Howells return namelen; 151d3e3b7eaSDavid Howells if (namelen > size) 152d3e3b7eaSDavid Howells return -ERANGE; 153c73aa410SDavid Howells memcpy(buffer, cell->name, namelen); 154d3e3b7eaSDavid Howells return namelen; 155d3e3b7eaSDavid Howells } 156d3e3b7eaSDavid Howells 157d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_cell_handler = { 158d3e3b7eaSDavid Howells .name = "afs.cell", 159d3e3b7eaSDavid Howells .get = afs_xattr_get_cell, 160d3e3b7eaSDavid Howells }; 161d3e3b7eaSDavid Howells 162d3e3b7eaSDavid Howells /* 163d3e3b7eaSDavid Howells * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of 164d3e3b7eaSDavid Howells * hex numbers separated by colons. 165d3e3b7eaSDavid Howells */ 166d3e3b7eaSDavid Howells static int afs_xattr_get_fid(const struct xattr_handler *handler, 167d3e3b7eaSDavid Howells struct dentry *dentry, 168d3e3b7eaSDavid Howells struct inode *inode, const char *name, 169d3e3b7eaSDavid Howells void *buffer, size_t size) 170d3e3b7eaSDavid Howells { 171d3e3b7eaSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 172a2f611a3SDavid Howells char text[16 + 1 + 24 + 1 + 8 + 1]; 173d3e3b7eaSDavid Howells size_t len; 174d3e3b7eaSDavid Howells 175a2f611a3SDavid Howells /* The volume ID is 64-bit, the vnode ID is 96-bit and the 176a2f611a3SDavid Howells * uniquifier is 32-bit. 177a2f611a3SDavid Howells */ 178a2f611a3SDavid Howells len = sprintf(text, "%llx:", vnode->fid.vid); 179a2f611a3SDavid Howells if (vnode->fid.vnode_hi) 180a2f611a3SDavid Howells len += sprintf(text + len, "%x%016llx", 181a2f611a3SDavid Howells vnode->fid.vnode_hi, vnode->fid.vnode); 182a2f611a3SDavid Howells else 183a2f611a3SDavid Howells len += sprintf(text + len, "%llx", vnode->fid.vnode); 184a2f611a3SDavid Howells len += sprintf(text + len, ":%x", vnode->fid.unique); 185a2f611a3SDavid Howells 186d3e3b7eaSDavid Howells if (size == 0) 187d3e3b7eaSDavid Howells return len; 188d3e3b7eaSDavid Howells if (len > size) 189d3e3b7eaSDavid Howells return -ERANGE; 190d3e3b7eaSDavid Howells memcpy(buffer, text, len); 191d3e3b7eaSDavid Howells return len; 192d3e3b7eaSDavid Howells } 193d3e3b7eaSDavid Howells 194d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_fid_handler = { 195d3e3b7eaSDavid Howells .name = "afs.fid", 196d3e3b7eaSDavid Howells .get = afs_xattr_get_fid, 197d3e3b7eaSDavid Howells }; 198d3e3b7eaSDavid Howells 199d3e3b7eaSDavid Howells /* 200d3e3b7eaSDavid Howells * Get the name of the volume on which a file resides. 201d3e3b7eaSDavid Howells */ 202d3e3b7eaSDavid Howells static int afs_xattr_get_volume(const struct xattr_handler *handler, 203d3e3b7eaSDavid Howells struct dentry *dentry, 204d3e3b7eaSDavid Howells struct inode *inode, const char *name, 205d3e3b7eaSDavid Howells void *buffer, size_t size) 206d3e3b7eaSDavid Howells { 207d3e3b7eaSDavid Howells struct afs_vnode *vnode = AFS_FS_I(inode); 208d2ddc776SDavid Howells const char *volname = vnode->volume->name; 209d3e3b7eaSDavid Howells size_t namelen; 210d3e3b7eaSDavid Howells 211d3e3b7eaSDavid Howells namelen = strlen(volname); 212d3e3b7eaSDavid Howells if (size == 0) 213d3e3b7eaSDavid Howells return namelen; 214d3e3b7eaSDavid Howells if (namelen > size) 215d3e3b7eaSDavid Howells return -ERANGE; 216c73aa410SDavid Howells memcpy(buffer, volname, namelen); 217d3e3b7eaSDavid Howells return namelen; 218d3e3b7eaSDavid Howells } 219d3e3b7eaSDavid Howells 220d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_volume_handler = { 221d3e3b7eaSDavid Howells .name = "afs.volume", 222d3e3b7eaSDavid Howells .get = afs_xattr_get_volume, 223d3e3b7eaSDavid Howells }; 224d3e3b7eaSDavid Howells 225d3e3b7eaSDavid Howells const struct xattr_handler *afs_xattr_handlers[] = { 226260f082bSDavid Howells &afs_xattr_afs_acl_handler, 227d3e3b7eaSDavid Howells &afs_xattr_afs_cell_handler, 228d3e3b7eaSDavid Howells &afs_xattr_afs_fid_handler, 229d3e3b7eaSDavid Howells &afs_xattr_afs_volume_handler, 230d3e3b7eaSDavid Howells NULL 231d3e3b7eaSDavid Howells }; 232