1 /* Extended attribute handling for AFS. We use xattrs to get and set metadata 2 * instead of providing pioctl(). 3 * 4 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 * 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. 11 */ 12 13 #include <linux/slab.h> 14 #include <linux/fs.h> 15 #include <linux/xattr.h> 16 #include "internal.h" 17 18 static const char afs_xattr_list[] = 19 "afs.acl\0" 20 "afs.cell\0" 21 "afs.fid\0" 22 "afs.volume\0" 23 "afs.yfs.acl\0" 24 "afs.yfs.acl_inherited\0" 25 "afs.yfs.acl_num_cleaned\0" 26 "afs.yfs.vol_acl"; 27 28 /* 29 * Retrieve a list of the supported xattrs. 30 */ 31 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) 32 { 33 if (size == 0) 34 return sizeof(afs_xattr_list); 35 if (size < sizeof(afs_xattr_list)) 36 return -ERANGE; 37 memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list)); 38 return sizeof(afs_xattr_list); 39 } 40 41 /* 42 * Get a file's ACL. 43 */ 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) 48 { 49 struct afs_fs_cursor fc; 50 struct afs_vnode *vnode = AFS_FS_I(inode); 51 struct afs_acl *acl = NULL; 52 struct key *key; 53 int ret; 54 55 key = afs_request_key(vnode->volume->cell); 56 if (IS_ERR(key)) 57 return PTR_ERR(key); 58 59 ret = -ERESTARTSYS; 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); 64 } 65 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); 69 } 70 71 if (ret == 0) { 72 ret = acl->size; 73 if (size > 0) { 74 ret = -ERANGE; 75 if (acl->size > size) 76 return -ERANGE; 77 memcpy(buffer, acl->data, acl->size); 78 ret = acl->size; 79 } 80 kfree(acl); 81 } 82 83 key_put(key); 84 return ret; 85 } 86 87 /* 88 * Set a file's AFS3 ACL. 89 */ 90 static int afs_xattr_set_acl(const struct xattr_handler *handler, 91 struct dentry *dentry, 92 struct inode *inode, const char *name, 93 const void *buffer, size_t size, int flags) 94 { 95 struct afs_fs_cursor fc; 96 struct afs_vnode *vnode = AFS_FS_I(inode); 97 struct afs_acl *acl = NULL; 98 struct key *key; 99 int ret; 100 101 if (flags == XATTR_CREATE) 102 return -EINVAL; 103 104 key = afs_request_key(vnode->volume->cell); 105 if (IS_ERR(key)) 106 return PTR_ERR(key); 107 108 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 109 if (!acl) { 110 key_put(key); 111 return -ENOMEM; 112 } 113 114 acl->size = size; 115 memcpy(acl->data, buffer, size); 116 117 ret = -ERESTARTSYS; 118 if (afs_begin_vnode_operation(&fc, vnode, key)) { 119 while (afs_select_fileserver(&fc)) { 120 fc.cb_break = afs_calc_vnode_cb_break(vnode); 121 afs_fs_store_acl(&fc, acl); 122 } 123 124 afs_check_for_remote_deletion(&fc, fc.vnode); 125 afs_vnode_commit_status(&fc, vnode, fc.cb_break); 126 ret = afs_end_vnode_operation(&fc); 127 } 128 129 kfree(acl); 130 key_put(key); 131 return ret; 132 } 133 134 static const struct xattr_handler afs_xattr_afs_acl_handler = { 135 .name = "afs.acl", 136 .get = afs_xattr_get_acl, 137 .set = afs_xattr_set_acl, 138 }; 139 140 /* 141 * Get a file's YFS ACL. 142 */ 143 static int afs_xattr_get_yfs(const struct xattr_handler *handler, 144 struct dentry *dentry, 145 struct inode *inode, const char *name, 146 void *buffer, size_t size) 147 { 148 struct afs_fs_cursor fc; 149 struct afs_vnode *vnode = AFS_FS_I(inode); 150 struct yfs_acl *yacl = NULL; 151 struct key *key; 152 unsigned int flags = 0; 153 char buf[16], *data; 154 int which = 0, dsize, ret; 155 156 if (strcmp(name, "acl") == 0) 157 which = 0; 158 else if (strcmp(name, "acl_inherited") == 0) 159 which = 1; 160 else if (strcmp(name, "acl_num_cleaned") == 0) 161 which = 2; 162 else if (strcmp(name, "vol_acl") == 0) 163 which = 3; 164 else 165 return -EOPNOTSUPP; 166 167 if (which == 0) 168 flags |= YFS_ACL_WANT_ACL; 169 else if (which == 3) 170 flags |= YFS_ACL_WANT_VOL_ACL; 171 172 key = afs_request_key(vnode->volume->cell); 173 if (IS_ERR(key)) 174 return PTR_ERR(key); 175 176 ret = -ERESTARTSYS; 177 if (afs_begin_vnode_operation(&fc, vnode, key)) { 178 while (afs_select_fileserver(&fc)) { 179 fc.cb_break = afs_calc_vnode_cb_break(vnode); 180 yacl = yfs_fs_fetch_opaque_acl(&fc, flags); 181 } 182 183 afs_check_for_remote_deletion(&fc, fc.vnode); 184 afs_vnode_commit_status(&fc, vnode, fc.cb_break); 185 ret = afs_end_vnode_operation(&fc); 186 } 187 188 if (ret == 0) { 189 switch (which) { 190 case 0: 191 data = yacl->acl->data; 192 dsize = yacl->acl->size; 193 break; 194 case 1: 195 data = buf; 196 dsize = snprintf(buf, sizeof(buf), "%u", 197 yacl->inherit_flag); 198 break; 199 case 2: 200 data = buf; 201 dsize = snprintf(buf, sizeof(buf), "%u", 202 yacl->num_cleaned); 203 break; 204 case 3: 205 data = yacl->vol_acl->data; 206 dsize = yacl->vol_acl->size; 207 break; 208 default: 209 ret = -EOPNOTSUPP; 210 goto out; 211 } 212 213 ret = dsize; 214 if (size > 0) { 215 if (dsize > size) { 216 ret = -ERANGE; 217 goto out; 218 } 219 memcpy(buffer, data, dsize); 220 } 221 } 222 223 out: 224 yfs_free_opaque_acl(yacl); 225 key_put(key); 226 return ret; 227 } 228 229 /* 230 * Set a file's YFS ACL. 231 */ 232 static int afs_xattr_set_yfs(const struct xattr_handler *handler, 233 struct dentry *dentry, 234 struct inode *inode, const char *name, 235 const void *buffer, size_t size, int flags) 236 { 237 struct afs_fs_cursor fc; 238 struct afs_vnode *vnode = AFS_FS_I(inode); 239 struct afs_acl *acl = NULL; 240 struct key *key; 241 int ret; 242 243 if (flags == XATTR_CREATE || 244 strcmp(name, "acl") != 0) 245 return -EINVAL; 246 247 key = afs_request_key(vnode->volume->cell); 248 if (IS_ERR(key)) 249 return PTR_ERR(key); 250 251 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 252 if (!acl) { 253 key_put(key); 254 return -ENOMEM; 255 } 256 257 acl->size = size; 258 memcpy(acl->data, buffer, size); 259 260 ret = -ERESTARTSYS; 261 if (afs_begin_vnode_operation(&fc, vnode, key)) { 262 while (afs_select_fileserver(&fc)) { 263 fc.cb_break = afs_calc_vnode_cb_break(vnode); 264 yfs_fs_store_opaque_acl2(&fc, acl); 265 } 266 267 afs_check_for_remote_deletion(&fc, fc.vnode); 268 afs_vnode_commit_status(&fc, vnode, fc.cb_break); 269 ret = afs_end_vnode_operation(&fc); 270 } 271 272 kfree(acl); 273 key_put(key); 274 return ret; 275 } 276 277 static const struct xattr_handler afs_xattr_yfs_handler = { 278 .prefix = "afs.yfs.", 279 .get = afs_xattr_get_yfs, 280 .set = afs_xattr_set_yfs, 281 }; 282 283 /* 284 * Get the name of the cell on which a file resides. 285 */ 286 static int afs_xattr_get_cell(const struct xattr_handler *handler, 287 struct dentry *dentry, 288 struct inode *inode, const char *name, 289 void *buffer, size_t size) 290 { 291 struct afs_vnode *vnode = AFS_FS_I(inode); 292 struct afs_cell *cell = vnode->volume->cell; 293 size_t namelen; 294 295 namelen = cell->name_len; 296 if (size == 0) 297 return namelen; 298 if (namelen > size) 299 return -ERANGE; 300 memcpy(buffer, cell->name, namelen); 301 return namelen; 302 } 303 304 static const struct xattr_handler afs_xattr_afs_cell_handler = { 305 .name = "afs.cell", 306 .get = afs_xattr_get_cell, 307 }; 308 309 /* 310 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of 311 * hex numbers separated by colons. 312 */ 313 static int afs_xattr_get_fid(const struct xattr_handler *handler, 314 struct dentry *dentry, 315 struct inode *inode, const char *name, 316 void *buffer, size_t size) 317 { 318 struct afs_vnode *vnode = AFS_FS_I(inode); 319 char text[16 + 1 + 24 + 1 + 8 + 1]; 320 size_t len; 321 322 /* The volume ID is 64-bit, the vnode ID is 96-bit and the 323 * uniquifier is 32-bit. 324 */ 325 len = sprintf(text, "%llx:", vnode->fid.vid); 326 if (vnode->fid.vnode_hi) 327 len += sprintf(text + len, "%x%016llx", 328 vnode->fid.vnode_hi, vnode->fid.vnode); 329 else 330 len += sprintf(text + len, "%llx", vnode->fid.vnode); 331 len += sprintf(text + len, ":%x", vnode->fid.unique); 332 333 if (size == 0) 334 return len; 335 if (len > size) 336 return -ERANGE; 337 memcpy(buffer, text, len); 338 return len; 339 } 340 341 static const struct xattr_handler afs_xattr_afs_fid_handler = { 342 .name = "afs.fid", 343 .get = afs_xattr_get_fid, 344 }; 345 346 /* 347 * Get the name of the volume on which a file resides. 348 */ 349 static int afs_xattr_get_volume(const struct xattr_handler *handler, 350 struct dentry *dentry, 351 struct inode *inode, const char *name, 352 void *buffer, size_t size) 353 { 354 struct afs_vnode *vnode = AFS_FS_I(inode); 355 const char *volname = vnode->volume->name; 356 size_t namelen; 357 358 namelen = strlen(volname); 359 if (size == 0) 360 return namelen; 361 if (namelen > size) 362 return -ERANGE; 363 memcpy(buffer, volname, namelen); 364 return namelen; 365 } 366 367 static const struct xattr_handler afs_xattr_afs_volume_handler = { 368 .name = "afs.volume", 369 .get = afs_xattr_get_volume, 370 }; 371 372 const struct xattr_handler *afs_xattr_handlers[] = { 373 &afs_xattr_afs_acl_handler, 374 &afs_xattr_afs_cell_handler, 375 &afs_xattr_afs_fid_handler, 376 &afs_xattr_afs_volume_handler, 377 &afs_xattr_yfs_handler, /* afs.yfs. prefix */ 378 NULL 379 }; 380