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_status_cb *scb; 51 struct afs_vnode *vnode = AFS_FS_I(inode); 52 struct afs_acl *acl = NULL; 53 struct key *key; 54 int ret = -ENOMEM; 55 56 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); 57 if (!scb) 58 goto error; 59 60 key = afs_request_key(vnode->volume->cell); 61 if (IS_ERR(key)) { 62 ret = PTR_ERR(key); 63 goto error_scb; 64 } 65 66 ret = -ERESTARTSYS; 67 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 68 afs_dataversion_t data_version = vnode->status.data_version; 69 70 while (afs_select_fileserver(&fc)) { 71 fc.cb_break = afs_calc_vnode_cb_break(vnode); 72 acl = afs_fs_fetch_acl(&fc, scb); 73 } 74 75 afs_check_for_remote_deletion(&fc, fc.vnode); 76 afs_vnode_commit_status(&fc, vnode, fc.cb_break, 77 &data_version, scb); 78 ret = afs_end_vnode_operation(&fc); 79 } 80 81 if (ret == 0) { 82 ret = acl->size; 83 if (size > 0) { 84 if (acl->size <= size) 85 memcpy(buffer, acl->data, acl->size); 86 else 87 ret = -ERANGE; 88 } 89 kfree(acl); 90 } 91 92 key_put(key); 93 error_scb: 94 kfree(scb); 95 error: 96 return ret; 97 } 98 99 /* 100 * Set a file's AFS3 ACL. 101 */ 102 static int afs_xattr_set_acl(const struct xattr_handler *handler, 103 struct dentry *dentry, 104 struct inode *inode, const char *name, 105 const void *buffer, size_t size, int flags) 106 { 107 struct afs_fs_cursor fc; 108 struct afs_status_cb *scb; 109 struct afs_vnode *vnode = AFS_FS_I(inode); 110 struct afs_acl *acl = NULL; 111 struct key *key; 112 int ret = -ENOMEM; 113 114 if (flags == XATTR_CREATE) 115 return -EINVAL; 116 117 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); 118 if (!scb) 119 goto error; 120 121 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 122 if (!acl) 123 goto error_scb; 124 125 key = afs_request_key(vnode->volume->cell); 126 if (IS_ERR(key)) { 127 ret = PTR_ERR(key); 128 goto error_acl; 129 } 130 131 acl->size = size; 132 memcpy(acl->data, buffer, size); 133 134 ret = -ERESTARTSYS; 135 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 136 afs_dataversion_t data_version = vnode->status.data_version; 137 138 while (afs_select_fileserver(&fc)) { 139 fc.cb_break = afs_calc_vnode_cb_break(vnode); 140 afs_fs_store_acl(&fc, acl, scb); 141 } 142 143 afs_check_for_remote_deletion(&fc, fc.vnode); 144 afs_vnode_commit_status(&fc, vnode, fc.cb_break, 145 &data_version, scb); 146 ret = afs_end_vnode_operation(&fc); 147 } 148 149 key_put(key); 150 error_acl: 151 kfree(acl); 152 error_scb: 153 kfree(scb); 154 error: 155 return ret; 156 } 157 158 static const struct xattr_handler afs_xattr_afs_acl_handler = { 159 .name = "afs.acl", 160 .get = afs_xattr_get_acl, 161 .set = afs_xattr_set_acl, 162 }; 163 164 /* 165 * Get a file's YFS ACL. 166 */ 167 static int afs_xattr_get_yfs(const struct xattr_handler *handler, 168 struct dentry *dentry, 169 struct inode *inode, const char *name, 170 void *buffer, size_t size) 171 { 172 struct afs_fs_cursor fc; 173 struct afs_status_cb *scb; 174 struct afs_vnode *vnode = AFS_FS_I(inode); 175 struct yfs_acl *yacl = NULL; 176 struct key *key; 177 char buf[16], *data; 178 int which = 0, dsize, ret = -ENOMEM; 179 180 if (strcmp(name, "acl") == 0) 181 which = 0; 182 else if (strcmp(name, "acl_inherited") == 0) 183 which = 1; 184 else if (strcmp(name, "acl_num_cleaned") == 0) 185 which = 2; 186 else if (strcmp(name, "vol_acl") == 0) 187 which = 3; 188 else 189 return -EOPNOTSUPP; 190 191 yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL); 192 if (!yacl) 193 goto error; 194 195 if (which == 0) 196 yacl->flags |= YFS_ACL_WANT_ACL; 197 else if (which == 3) 198 yacl->flags |= YFS_ACL_WANT_VOL_ACL; 199 200 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); 201 if (!scb) 202 goto error_yacl; 203 204 key = afs_request_key(vnode->volume->cell); 205 if (IS_ERR(key)) { 206 ret = PTR_ERR(key); 207 goto error_scb; 208 } 209 210 ret = -ERESTARTSYS; 211 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 212 afs_dataversion_t data_version = vnode->status.data_version; 213 214 while (afs_select_fileserver(&fc)) { 215 fc.cb_break = afs_calc_vnode_cb_break(vnode); 216 yfs_fs_fetch_opaque_acl(&fc, yacl, scb); 217 } 218 219 afs_check_for_remote_deletion(&fc, fc.vnode); 220 afs_vnode_commit_status(&fc, vnode, fc.cb_break, 221 &data_version, scb); 222 ret = afs_end_vnode_operation(&fc); 223 } 224 225 if (ret < 0) 226 goto error_key; 227 228 switch (which) { 229 case 0: 230 data = yacl->acl->data; 231 dsize = yacl->acl->size; 232 break; 233 case 1: 234 data = buf; 235 dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag); 236 break; 237 case 2: 238 data = buf; 239 dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned); 240 break; 241 case 3: 242 data = yacl->vol_acl->data; 243 dsize = yacl->vol_acl->size; 244 break; 245 default: 246 ret = -EOPNOTSUPP; 247 goto error_key; 248 } 249 250 ret = dsize; 251 if (size > 0) { 252 if (dsize > size) { 253 ret = -ERANGE; 254 goto error_key; 255 } 256 memcpy(buffer, data, dsize); 257 } 258 259 error_key: 260 key_put(key); 261 error_scb: 262 kfree(scb); 263 error_yacl: 264 yfs_free_opaque_acl(yacl); 265 error: 266 return ret; 267 } 268 269 /* 270 * Set a file's YFS ACL. 271 */ 272 static int afs_xattr_set_yfs(const struct xattr_handler *handler, 273 struct dentry *dentry, 274 struct inode *inode, const char *name, 275 const void *buffer, size_t size, int flags) 276 { 277 struct afs_fs_cursor fc; 278 struct afs_status_cb *scb; 279 struct afs_vnode *vnode = AFS_FS_I(inode); 280 struct afs_acl *acl = NULL; 281 struct key *key; 282 int ret = -ENOMEM; 283 284 if (flags == XATTR_CREATE || 285 strcmp(name, "acl") != 0) 286 return -EINVAL; 287 288 scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); 289 if (!scb) 290 goto error; 291 292 acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); 293 if (!acl) 294 goto error_scb; 295 296 acl->size = size; 297 memcpy(acl->data, buffer, size); 298 299 key = afs_request_key(vnode->volume->cell); 300 if (IS_ERR(key)) { 301 ret = PTR_ERR(key); 302 goto error_acl; 303 } 304 305 ret = -ERESTARTSYS; 306 if (afs_begin_vnode_operation(&fc, vnode, key, true)) { 307 afs_dataversion_t data_version = vnode->status.data_version; 308 309 while (afs_select_fileserver(&fc)) { 310 fc.cb_break = afs_calc_vnode_cb_break(vnode); 311 yfs_fs_store_opaque_acl2(&fc, acl, scb); 312 } 313 314 afs_check_for_remote_deletion(&fc, fc.vnode); 315 afs_vnode_commit_status(&fc, vnode, fc.cb_break, 316 &data_version, scb); 317 ret = afs_end_vnode_operation(&fc); 318 } 319 320 error_acl: 321 kfree(acl); 322 key_put(key); 323 error_scb: 324 kfree(scb); 325 error: 326 return ret; 327 } 328 329 static const struct xattr_handler afs_xattr_yfs_handler = { 330 .prefix = "afs.yfs.", 331 .get = afs_xattr_get_yfs, 332 .set = afs_xattr_set_yfs, 333 }; 334 335 /* 336 * Get the name of the cell on which a file resides. 337 */ 338 static int afs_xattr_get_cell(const struct xattr_handler *handler, 339 struct dentry *dentry, 340 struct inode *inode, const char *name, 341 void *buffer, size_t size) 342 { 343 struct afs_vnode *vnode = AFS_FS_I(inode); 344 struct afs_cell *cell = vnode->volume->cell; 345 size_t namelen; 346 347 namelen = cell->name_len; 348 if (size == 0) 349 return namelen; 350 if (namelen > size) 351 return -ERANGE; 352 memcpy(buffer, cell->name, namelen); 353 return namelen; 354 } 355 356 static const struct xattr_handler afs_xattr_afs_cell_handler = { 357 .name = "afs.cell", 358 .get = afs_xattr_get_cell, 359 }; 360 361 /* 362 * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of 363 * hex numbers separated by colons. 364 */ 365 static int afs_xattr_get_fid(const struct xattr_handler *handler, 366 struct dentry *dentry, 367 struct inode *inode, const char *name, 368 void *buffer, size_t size) 369 { 370 struct afs_vnode *vnode = AFS_FS_I(inode); 371 char text[16 + 1 + 24 + 1 + 8 + 1]; 372 size_t len; 373 374 /* The volume ID is 64-bit, the vnode ID is 96-bit and the 375 * uniquifier is 32-bit. 376 */ 377 len = sprintf(text, "%llx:", vnode->fid.vid); 378 if (vnode->fid.vnode_hi) 379 len += sprintf(text + len, "%x%016llx", 380 vnode->fid.vnode_hi, vnode->fid.vnode); 381 else 382 len += sprintf(text + len, "%llx", vnode->fid.vnode); 383 len += sprintf(text + len, ":%x", vnode->fid.unique); 384 385 if (size == 0) 386 return len; 387 if (len > size) 388 return -ERANGE; 389 memcpy(buffer, text, len); 390 return len; 391 } 392 393 static const struct xattr_handler afs_xattr_afs_fid_handler = { 394 .name = "afs.fid", 395 .get = afs_xattr_get_fid, 396 }; 397 398 /* 399 * Get the name of the volume on which a file resides. 400 */ 401 static int afs_xattr_get_volume(const struct xattr_handler *handler, 402 struct dentry *dentry, 403 struct inode *inode, const char *name, 404 void *buffer, size_t size) 405 { 406 struct afs_vnode *vnode = AFS_FS_I(inode); 407 const char *volname = vnode->volume->name; 408 size_t namelen; 409 410 namelen = strlen(volname); 411 if (size == 0) 412 return namelen; 413 if (namelen > size) 414 return -ERANGE; 415 memcpy(buffer, volname, namelen); 416 return namelen; 417 } 418 419 static const struct xattr_handler afs_xattr_afs_volume_handler = { 420 .name = "afs.volume", 421 .get = afs_xattr_get_volume, 422 }; 423 424 const struct xattr_handler *afs_xattr_handlers[] = { 425 &afs_xattr_afs_acl_handler, 426 &afs_xattr_afs_cell_handler, 427 &afs_xattr_afs_fid_handler, 428 &afs_xattr_afs_volume_handler, 429 &afs_xattr_yfs_handler, /* afs.yfs. prefix */ 430 NULL 431 }; 432