1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/ceph/ceph_debug.h> 3 #include <linux/ceph/pagelist.h> 4 5 #include "super.h" 6 #include "mds_client.h" 7 8 #include <linux/ceph/decode.h> 9 10 #include <linux/xattr.h> 11 #include <linux/security.h> 12 #include <linux/posix_acl_xattr.h> 13 #include <linux/slab.h> 14 15 #define XATTR_CEPH_PREFIX "ceph." 16 #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) 17 18 static int __remove_xattr(struct ceph_inode_info *ci, 19 struct ceph_inode_xattr *xattr); 20 21 static bool ceph_is_valid_xattr(const char *name) 22 { 23 return !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || 24 !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || 25 !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || 26 !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 27 } 28 29 /* 30 * These define virtual xattrs exposing the recursive directory 31 * statistics and layout metadata. 32 */ 33 struct ceph_vxattr { 34 char *name; 35 size_t name_size; /* strlen(name) + 1 (for '\0') */ 36 ssize_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val, 37 size_t size); 38 bool (*exists_cb)(struct ceph_inode_info *ci); 39 unsigned int flags; 40 }; 41 42 #define VXATTR_FLAG_READONLY (1<<0) 43 #define VXATTR_FLAG_HIDDEN (1<<1) 44 #define VXATTR_FLAG_RSTAT (1<<2) 45 46 /* layouts */ 47 48 static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci) 49 { 50 struct ceph_file_layout *fl = &ci->i_layout; 51 return (fl->stripe_unit > 0 || fl->stripe_count > 0 || 52 fl->object_size > 0 || fl->pool_id >= 0 || 53 rcu_dereference_raw(fl->pool_ns) != NULL); 54 } 55 56 static ssize_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val, 57 size_t size) 58 { 59 struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); 60 struct ceph_osd_client *osdc = &fsc->client->osdc; 61 struct ceph_string *pool_ns; 62 s64 pool = ci->i_layout.pool_id; 63 const char *pool_name; 64 const char *ns_field = " pool_namespace="; 65 char buf[128]; 66 size_t len, total_len = 0; 67 ssize_t ret; 68 69 pool_ns = ceph_try_get_string(ci->i_layout.pool_ns); 70 71 dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode); 72 down_read(&osdc->lock); 73 pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 74 if (pool_name) { 75 len = snprintf(buf, sizeof(buf), 76 "stripe_unit=%u stripe_count=%u object_size=%u pool=", 77 ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 78 ci->i_layout.object_size); 79 total_len = len + strlen(pool_name); 80 } else { 81 len = snprintf(buf, sizeof(buf), 82 "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld", 83 ci->i_layout.stripe_unit, ci->i_layout.stripe_count, 84 ci->i_layout.object_size, pool); 85 total_len = len; 86 } 87 88 if (pool_ns) 89 total_len += strlen(ns_field) + pool_ns->len; 90 91 ret = total_len; 92 if (size >= total_len) { 93 memcpy(val, buf, len); 94 ret = len; 95 if (pool_name) { 96 len = strlen(pool_name); 97 memcpy(val + ret, pool_name, len); 98 ret += len; 99 } 100 if (pool_ns) { 101 len = strlen(ns_field); 102 memcpy(val + ret, ns_field, len); 103 ret += len; 104 memcpy(val + ret, pool_ns->str, pool_ns->len); 105 ret += pool_ns->len; 106 } 107 } 108 up_read(&osdc->lock); 109 ceph_put_string(pool_ns); 110 return ret; 111 } 112 113 /* 114 * The convention with strings in xattrs is that they should not be NULL 115 * terminated, since we're returning the length with them. snprintf always 116 * NULL terminates however, so call it on a temporary buffer and then memcpy 117 * the result into place. 118 */ 119 static __printf(3, 4) 120 int ceph_fmt_xattr(char *val, size_t size, const char *fmt, ...) 121 { 122 int ret; 123 va_list args; 124 char buf[96]; /* NB: reevaluate size if new vxattrs are added */ 125 126 va_start(args, fmt); 127 ret = vsnprintf(buf, size ? sizeof(buf) : 0, fmt, args); 128 va_end(args); 129 130 /* Sanity check */ 131 if (size && ret + 1 > sizeof(buf)) { 132 WARN_ONCE(true, "Returned length too big (%d)", ret); 133 return -E2BIG; 134 } 135 136 if (ret <= size) 137 memcpy(val, buf, ret); 138 return ret; 139 } 140 141 static ssize_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci, 142 char *val, size_t size) 143 { 144 return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_unit); 145 } 146 147 static ssize_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci, 148 char *val, size_t size) 149 { 150 return ceph_fmt_xattr(val, size, "%u", ci->i_layout.stripe_count); 151 } 152 153 static ssize_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci, 154 char *val, size_t size) 155 { 156 return ceph_fmt_xattr(val, size, "%u", ci->i_layout.object_size); 157 } 158 159 static ssize_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci, 160 char *val, size_t size) 161 { 162 ssize_t ret; 163 struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb); 164 struct ceph_osd_client *osdc = &fsc->client->osdc; 165 s64 pool = ci->i_layout.pool_id; 166 const char *pool_name; 167 168 down_read(&osdc->lock); 169 pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool); 170 if (pool_name) { 171 ret = strlen(pool_name); 172 if (ret <= size) 173 memcpy(val, pool_name, ret); 174 } else { 175 ret = ceph_fmt_xattr(val, size, "%lld", pool); 176 } 177 up_read(&osdc->lock); 178 return ret; 179 } 180 181 static ssize_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci, 182 char *val, size_t size) 183 { 184 ssize_t ret = 0; 185 struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns); 186 187 if (ns) { 188 ret = ns->len; 189 if (ret <= size) 190 memcpy(val, ns->str, ret); 191 ceph_put_string(ns); 192 } 193 return ret; 194 } 195 196 /* directories */ 197 198 static ssize_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val, 199 size_t size) 200 { 201 return ceph_fmt_xattr(val, size, "%lld", ci->i_files + ci->i_subdirs); 202 } 203 204 static ssize_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val, 205 size_t size) 206 { 207 return ceph_fmt_xattr(val, size, "%lld", ci->i_files); 208 } 209 210 static ssize_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val, 211 size_t size) 212 { 213 return ceph_fmt_xattr(val, size, "%lld", ci->i_subdirs); 214 } 215 216 static ssize_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val, 217 size_t size) 218 { 219 return ceph_fmt_xattr(val, size, "%lld", 220 ci->i_rfiles + ci->i_rsubdirs); 221 } 222 223 static ssize_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val, 224 size_t size) 225 { 226 return ceph_fmt_xattr(val, size, "%lld", ci->i_rfiles); 227 } 228 229 static ssize_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val, 230 size_t size) 231 { 232 return ceph_fmt_xattr(val, size, "%lld", ci->i_rsubdirs); 233 } 234 235 static ssize_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val, 236 size_t size) 237 { 238 return ceph_fmt_xattr(val, size, "%lld", ci->i_rbytes); 239 } 240 241 static ssize_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val, 242 size_t size) 243 { 244 return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_rctime.tv_sec, 245 ci->i_rctime.tv_nsec); 246 } 247 248 /* dir pin */ 249 static bool ceph_vxattrcb_dir_pin_exists(struct ceph_inode_info *ci) 250 { 251 return ci->i_dir_pin != -ENODATA; 252 } 253 254 static ssize_t ceph_vxattrcb_dir_pin(struct ceph_inode_info *ci, char *val, 255 size_t size) 256 { 257 return ceph_fmt_xattr(val, size, "%d", (int)ci->i_dir_pin); 258 } 259 260 /* quotas */ 261 static bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci) 262 { 263 bool ret = false; 264 spin_lock(&ci->i_ceph_lock); 265 if ((ci->i_max_files || ci->i_max_bytes) && 266 ci->i_vino.snap == CEPH_NOSNAP && 267 ci->i_snap_realm && 268 ci->i_snap_realm->ino == ci->i_vino.ino) 269 ret = true; 270 spin_unlock(&ci->i_ceph_lock); 271 return ret; 272 } 273 274 static ssize_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val, 275 size_t size) 276 { 277 return ceph_fmt_xattr(val, size, "max_bytes=%llu max_files=%llu", 278 ci->i_max_bytes, ci->i_max_files); 279 } 280 281 static ssize_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci, 282 char *val, size_t size) 283 { 284 return ceph_fmt_xattr(val, size, "%llu", ci->i_max_bytes); 285 } 286 287 static ssize_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci, 288 char *val, size_t size) 289 { 290 return ceph_fmt_xattr(val, size, "%llu", ci->i_max_files); 291 } 292 293 /* snapshots */ 294 static bool ceph_vxattrcb_snap_btime_exists(struct ceph_inode_info *ci) 295 { 296 return (ci->i_snap_btime.tv_sec != 0 || ci->i_snap_btime.tv_nsec != 0); 297 } 298 299 static ssize_t ceph_vxattrcb_snap_btime(struct ceph_inode_info *ci, char *val, 300 size_t size) 301 { 302 return ceph_fmt_xattr(val, size, "%lld.%09ld", ci->i_snap_btime.tv_sec, 303 ci->i_snap_btime.tv_nsec); 304 } 305 306 #define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name 307 #define CEPH_XATTR_NAME2(_type, _name, _name2) \ 308 XATTR_CEPH_PREFIX #_type "." #_name "." #_name2 309 310 #define XATTR_NAME_CEPH(_type, _name, _flags) \ 311 { \ 312 .name = CEPH_XATTR_NAME(_type, _name), \ 313 .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \ 314 .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 315 .exists_cb = NULL, \ 316 .flags = (VXATTR_FLAG_READONLY | _flags), \ 317 } 318 #define XATTR_RSTAT_FIELD(_type, _name) \ 319 XATTR_NAME_CEPH(_type, _name, VXATTR_FLAG_RSTAT) 320 #define XATTR_LAYOUT_FIELD(_type, _name, _field) \ 321 { \ 322 .name = CEPH_XATTR_NAME2(_type, _name, _field), \ 323 .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \ 324 .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \ 325 .exists_cb = ceph_vxattrcb_layout_exists, \ 326 .flags = VXATTR_FLAG_HIDDEN, \ 327 } 328 #define XATTR_QUOTA_FIELD(_type, _name) \ 329 { \ 330 .name = CEPH_XATTR_NAME(_type, _name), \ 331 .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)), \ 332 .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \ 333 .exists_cb = ceph_vxattrcb_quota_exists, \ 334 .flags = VXATTR_FLAG_HIDDEN, \ 335 } 336 337 static struct ceph_vxattr ceph_dir_vxattrs[] = { 338 { 339 .name = "ceph.dir.layout", 340 .name_size = sizeof("ceph.dir.layout"), 341 .getxattr_cb = ceph_vxattrcb_layout, 342 .exists_cb = ceph_vxattrcb_layout_exists, 343 .flags = VXATTR_FLAG_HIDDEN, 344 }, 345 XATTR_LAYOUT_FIELD(dir, layout, stripe_unit), 346 XATTR_LAYOUT_FIELD(dir, layout, stripe_count), 347 XATTR_LAYOUT_FIELD(dir, layout, object_size), 348 XATTR_LAYOUT_FIELD(dir, layout, pool), 349 XATTR_LAYOUT_FIELD(dir, layout, pool_namespace), 350 XATTR_NAME_CEPH(dir, entries, 0), 351 XATTR_NAME_CEPH(dir, files, 0), 352 XATTR_NAME_CEPH(dir, subdirs, 0), 353 XATTR_RSTAT_FIELD(dir, rentries), 354 XATTR_RSTAT_FIELD(dir, rfiles), 355 XATTR_RSTAT_FIELD(dir, rsubdirs), 356 XATTR_RSTAT_FIELD(dir, rbytes), 357 XATTR_RSTAT_FIELD(dir, rctime), 358 { 359 .name = "ceph.dir.pin", 360 .name_size = sizeof("ceph.dir.pin"), 361 .getxattr_cb = ceph_vxattrcb_dir_pin, 362 .exists_cb = ceph_vxattrcb_dir_pin_exists, 363 .flags = VXATTR_FLAG_HIDDEN, 364 }, 365 { 366 .name = "ceph.quota", 367 .name_size = sizeof("ceph.quota"), 368 .getxattr_cb = ceph_vxattrcb_quota, 369 .exists_cb = ceph_vxattrcb_quota_exists, 370 .flags = VXATTR_FLAG_HIDDEN, 371 }, 372 XATTR_QUOTA_FIELD(quota, max_bytes), 373 XATTR_QUOTA_FIELD(quota, max_files), 374 { 375 .name = "ceph.snap.btime", 376 .name_size = sizeof("ceph.snap.btime"), 377 .getxattr_cb = ceph_vxattrcb_snap_btime, 378 .exists_cb = ceph_vxattrcb_snap_btime_exists, 379 .flags = VXATTR_FLAG_READONLY, 380 }, 381 { .name = NULL, 0 } /* Required table terminator */ 382 }; 383 384 /* files */ 385 386 static struct ceph_vxattr ceph_file_vxattrs[] = { 387 { 388 .name = "ceph.file.layout", 389 .name_size = sizeof("ceph.file.layout"), 390 .getxattr_cb = ceph_vxattrcb_layout, 391 .exists_cb = ceph_vxattrcb_layout_exists, 392 .flags = VXATTR_FLAG_HIDDEN, 393 }, 394 XATTR_LAYOUT_FIELD(file, layout, stripe_unit), 395 XATTR_LAYOUT_FIELD(file, layout, stripe_count), 396 XATTR_LAYOUT_FIELD(file, layout, object_size), 397 XATTR_LAYOUT_FIELD(file, layout, pool), 398 XATTR_LAYOUT_FIELD(file, layout, pool_namespace), 399 { 400 .name = "ceph.snap.btime", 401 .name_size = sizeof("ceph.snap.btime"), 402 .getxattr_cb = ceph_vxattrcb_snap_btime, 403 .exists_cb = ceph_vxattrcb_snap_btime_exists, 404 .flags = VXATTR_FLAG_READONLY, 405 }, 406 { .name = NULL, 0 } /* Required table terminator */ 407 }; 408 409 static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode) 410 { 411 if (S_ISDIR(inode->i_mode)) 412 return ceph_dir_vxattrs; 413 else if (S_ISREG(inode->i_mode)) 414 return ceph_file_vxattrs; 415 return NULL; 416 } 417 418 static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, 419 const char *name) 420 { 421 struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode); 422 423 if (vxattr) { 424 while (vxattr->name) { 425 if (!strcmp(vxattr->name, name)) 426 return vxattr; 427 vxattr++; 428 } 429 } 430 431 return NULL; 432 } 433 434 static int __set_xattr(struct ceph_inode_info *ci, 435 const char *name, int name_len, 436 const char *val, int val_len, 437 int flags, int update_xattr, 438 struct ceph_inode_xattr **newxattr) 439 { 440 struct rb_node **p; 441 struct rb_node *parent = NULL; 442 struct ceph_inode_xattr *xattr = NULL; 443 int c; 444 int new = 0; 445 446 p = &ci->i_xattrs.index.rb_node; 447 while (*p) { 448 parent = *p; 449 xattr = rb_entry(parent, struct ceph_inode_xattr, node); 450 c = strncmp(name, xattr->name, min(name_len, xattr->name_len)); 451 if (c < 0) 452 p = &(*p)->rb_left; 453 else if (c > 0) 454 p = &(*p)->rb_right; 455 else { 456 if (name_len == xattr->name_len) 457 break; 458 else if (name_len < xattr->name_len) 459 p = &(*p)->rb_left; 460 else 461 p = &(*p)->rb_right; 462 } 463 xattr = NULL; 464 } 465 466 if (update_xattr) { 467 int err = 0; 468 469 if (xattr && (flags & XATTR_CREATE)) 470 err = -EEXIST; 471 else if (!xattr && (flags & XATTR_REPLACE)) 472 err = -ENODATA; 473 if (err) { 474 kfree(name); 475 kfree(val); 476 kfree(*newxattr); 477 return err; 478 } 479 if (update_xattr < 0) { 480 if (xattr) 481 __remove_xattr(ci, xattr); 482 kfree(name); 483 kfree(*newxattr); 484 return 0; 485 } 486 } 487 488 if (!xattr) { 489 new = 1; 490 xattr = *newxattr; 491 xattr->name = name; 492 xattr->name_len = name_len; 493 xattr->should_free_name = update_xattr; 494 495 ci->i_xattrs.count++; 496 dout("__set_xattr count=%d\n", ci->i_xattrs.count); 497 } else { 498 kfree(*newxattr); 499 *newxattr = NULL; 500 if (xattr->should_free_val) 501 kfree(xattr->val); 502 503 if (update_xattr) { 504 kfree(name); 505 name = xattr->name; 506 } 507 ci->i_xattrs.names_size -= xattr->name_len; 508 ci->i_xattrs.vals_size -= xattr->val_len; 509 } 510 ci->i_xattrs.names_size += name_len; 511 ci->i_xattrs.vals_size += val_len; 512 if (val) 513 xattr->val = val; 514 else 515 xattr->val = ""; 516 517 xattr->val_len = val_len; 518 xattr->dirty = update_xattr; 519 xattr->should_free_val = (val && update_xattr); 520 521 if (new) { 522 rb_link_node(&xattr->node, parent, p); 523 rb_insert_color(&xattr->node, &ci->i_xattrs.index); 524 dout("__set_xattr_val p=%p\n", p); 525 } 526 527 dout("__set_xattr_val added %llx.%llx xattr %p %.*s=%.*s\n", 528 ceph_vinop(&ci->vfs_inode), xattr, name_len, name, val_len, val); 529 530 return 0; 531 } 532 533 static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci, 534 const char *name) 535 { 536 struct rb_node **p; 537 struct rb_node *parent = NULL; 538 struct ceph_inode_xattr *xattr = NULL; 539 int name_len = strlen(name); 540 int c; 541 542 p = &ci->i_xattrs.index.rb_node; 543 while (*p) { 544 parent = *p; 545 xattr = rb_entry(parent, struct ceph_inode_xattr, node); 546 c = strncmp(name, xattr->name, xattr->name_len); 547 if (c == 0 && name_len > xattr->name_len) 548 c = 1; 549 if (c < 0) 550 p = &(*p)->rb_left; 551 else if (c > 0) 552 p = &(*p)->rb_right; 553 else { 554 dout("__get_xattr %s: found %.*s\n", name, 555 xattr->val_len, xattr->val); 556 return xattr; 557 } 558 } 559 560 dout("__get_xattr %s: not found\n", name); 561 562 return NULL; 563 } 564 565 static void __free_xattr(struct ceph_inode_xattr *xattr) 566 { 567 BUG_ON(!xattr); 568 569 if (xattr->should_free_name) 570 kfree(xattr->name); 571 if (xattr->should_free_val) 572 kfree(xattr->val); 573 574 kfree(xattr); 575 } 576 577 static int __remove_xattr(struct ceph_inode_info *ci, 578 struct ceph_inode_xattr *xattr) 579 { 580 if (!xattr) 581 return -ENODATA; 582 583 rb_erase(&xattr->node, &ci->i_xattrs.index); 584 585 if (xattr->should_free_name) 586 kfree(xattr->name); 587 if (xattr->should_free_val) 588 kfree(xattr->val); 589 590 ci->i_xattrs.names_size -= xattr->name_len; 591 ci->i_xattrs.vals_size -= xattr->val_len; 592 ci->i_xattrs.count--; 593 kfree(xattr); 594 595 return 0; 596 } 597 598 static char *__copy_xattr_names(struct ceph_inode_info *ci, 599 char *dest) 600 { 601 struct rb_node *p; 602 struct ceph_inode_xattr *xattr = NULL; 603 604 p = rb_first(&ci->i_xattrs.index); 605 dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count); 606 607 while (p) { 608 xattr = rb_entry(p, struct ceph_inode_xattr, node); 609 memcpy(dest, xattr->name, xattr->name_len); 610 dest[xattr->name_len] = '\0'; 611 612 dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name, 613 xattr->name_len, ci->i_xattrs.names_size); 614 615 dest += xattr->name_len + 1; 616 p = rb_next(p); 617 } 618 619 return dest; 620 } 621 622 void __ceph_destroy_xattrs(struct ceph_inode_info *ci) 623 { 624 struct rb_node *p, *tmp; 625 struct ceph_inode_xattr *xattr = NULL; 626 627 p = rb_first(&ci->i_xattrs.index); 628 629 dout("__ceph_destroy_xattrs p=%p\n", p); 630 631 while (p) { 632 xattr = rb_entry(p, struct ceph_inode_xattr, node); 633 tmp = p; 634 p = rb_next(tmp); 635 dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p, 636 xattr->name_len, xattr->name); 637 rb_erase(tmp, &ci->i_xattrs.index); 638 639 __free_xattr(xattr); 640 } 641 642 ci->i_xattrs.names_size = 0; 643 ci->i_xattrs.vals_size = 0; 644 ci->i_xattrs.index_version = 0; 645 ci->i_xattrs.count = 0; 646 ci->i_xattrs.index = RB_ROOT; 647 } 648 649 static int __build_xattrs(struct inode *inode) 650 __releases(ci->i_ceph_lock) 651 __acquires(ci->i_ceph_lock) 652 { 653 u32 namelen; 654 u32 numattr = 0; 655 void *p, *end; 656 u32 len; 657 const char *name, *val; 658 struct ceph_inode_info *ci = ceph_inode(inode); 659 u64 xattr_version; 660 struct ceph_inode_xattr **xattrs = NULL; 661 int err = 0; 662 int i; 663 664 dout("__build_xattrs() len=%d\n", 665 ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0); 666 667 if (ci->i_xattrs.index_version >= ci->i_xattrs.version) 668 return 0; /* already built */ 669 670 __ceph_destroy_xattrs(ci); 671 672 start: 673 /* updated internal xattr rb tree */ 674 if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) { 675 p = ci->i_xattrs.blob->vec.iov_base; 676 end = p + ci->i_xattrs.blob->vec.iov_len; 677 ceph_decode_32_safe(&p, end, numattr, bad); 678 xattr_version = ci->i_xattrs.version; 679 spin_unlock(&ci->i_ceph_lock); 680 681 xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *), 682 GFP_NOFS); 683 err = -ENOMEM; 684 if (!xattrs) 685 goto bad_lock; 686 687 for (i = 0; i < numattr; i++) { 688 xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr), 689 GFP_NOFS); 690 if (!xattrs[i]) 691 goto bad_lock; 692 } 693 694 spin_lock(&ci->i_ceph_lock); 695 if (ci->i_xattrs.version != xattr_version) { 696 /* lost a race, retry */ 697 for (i = 0; i < numattr; i++) 698 kfree(xattrs[i]); 699 kfree(xattrs); 700 xattrs = NULL; 701 goto start; 702 } 703 err = -EIO; 704 while (numattr--) { 705 ceph_decode_32_safe(&p, end, len, bad); 706 namelen = len; 707 name = p; 708 p += len; 709 ceph_decode_32_safe(&p, end, len, bad); 710 val = p; 711 p += len; 712 713 err = __set_xattr(ci, name, namelen, val, len, 714 0, 0, &xattrs[numattr]); 715 716 if (err < 0) 717 goto bad; 718 } 719 kfree(xattrs); 720 } 721 ci->i_xattrs.index_version = ci->i_xattrs.version; 722 ci->i_xattrs.dirty = false; 723 724 return err; 725 bad_lock: 726 spin_lock(&ci->i_ceph_lock); 727 bad: 728 if (xattrs) { 729 for (i = 0; i < numattr; i++) 730 kfree(xattrs[i]); 731 kfree(xattrs); 732 } 733 ci->i_xattrs.names_size = 0; 734 return err; 735 } 736 737 static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size, 738 int val_size) 739 { 740 /* 741 * 4 bytes for the length, and additional 4 bytes per each xattr name, 742 * 4 bytes per each value 743 */ 744 int size = 4 + ci->i_xattrs.count*(4 + 4) + 745 ci->i_xattrs.names_size + 746 ci->i_xattrs.vals_size; 747 dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n", 748 ci->i_xattrs.count, ci->i_xattrs.names_size, 749 ci->i_xattrs.vals_size); 750 751 if (name_size) 752 size += 4 + 4 + name_size + val_size; 753 754 return size; 755 } 756 757 /* 758 * If there are dirty xattrs, reencode xattrs into the prealloc_blob 759 * and swap into place. It returns the old i_xattrs.blob (or NULL) so 760 * that it can be freed by the caller as the i_ceph_lock is likely to be 761 * held. 762 */ 763 struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci) 764 { 765 struct rb_node *p; 766 struct ceph_inode_xattr *xattr = NULL; 767 struct ceph_buffer *old_blob = NULL; 768 void *dest; 769 770 dout("__build_xattrs_blob %p\n", &ci->vfs_inode); 771 if (ci->i_xattrs.dirty) { 772 int need = __get_required_blob_size(ci, 0, 0); 773 774 BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len); 775 776 p = rb_first(&ci->i_xattrs.index); 777 dest = ci->i_xattrs.prealloc_blob->vec.iov_base; 778 779 ceph_encode_32(&dest, ci->i_xattrs.count); 780 while (p) { 781 xattr = rb_entry(p, struct ceph_inode_xattr, node); 782 783 ceph_encode_32(&dest, xattr->name_len); 784 memcpy(dest, xattr->name, xattr->name_len); 785 dest += xattr->name_len; 786 ceph_encode_32(&dest, xattr->val_len); 787 memcpy(dest, xattr->val, xattr->val_len); 788 dest += xattr->val_len; 789 790 p = rb_next(p); 791 } 792 793 /* adjust buffer len; it may be larger than we need */ 794 ci->i_xattrs.prealloc_blob->vec.iov_len = 795 dest - ci->i_xattrs.prealloc_blob->vec.iov_base; 796 797 if (ci->i_xattrs.blob) 798 old_blob = ci->i_xattrs.blob; 799 ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; 800 ci->i_xattrs.prealloc_blob = NULL; 801 ci->i_xattrs.dirty = false; 802 ci->i_xattrs.version++; 803 } 804 805 return old_blob; 806 } 807 808 static inline int __get_request_mask(struct inode *in) { 809 struct ceph_mds_request *req = current->journal_info; 810 int mask = 0; 811 if (req && req->r_target_inode == in) { 812 if (req->r_op == CEPH_MDS_OP_LOOKUP || 813 req->r_op == CEPH_MDS_OP_LOOKUPINO || 814 req->r_op == CEPH_MDS_OP_LOOKUPPARENT || 815 req->r_op == CEPH_MDS_OP_GETATTR) { 816 mask = le32_to_cpu(req->r_args.getattr.mask); 817 } else if (req->r_op == CEPH_MDS_OP_OPEN || 818 req->r_op == CEPH_MDS_OP_CREATE) { 819 mask = le32_to_cpu(req->r_args.open.mask); 820 } 821 } 822 return mask; 823 } 824 825 ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, 826 size_t size) 827 { 828 struct ceph_inode_info *ci = ceph_inode(inode); 829 struct ceph_inode_xattr *xattr; 830 struct ceph_vxattr *vxattr = NULL; 831 int req_mask; 832 ssize_t err; 833 834 /* let's see if a virtual xattr was requested */ 835 vxattr = ceph_match_vxattr(inode, name); 836 if (vxattr) { 837 int mask = 0; 838 if (vxattr->flags & VXATTR_FLAG_RSTAT) 839 mask |= CEPH_STAT_RSTAT; 840 err = ceph_do_getattr(inode, mask, true); 841 if (err) 842 return err; 843 err = -ENODATA; 844 if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) { 845 err = vxattr->getxattr_cb(ci, value, size); 846 if (size && size < err) 847 err = -ERANGE; 848 } 849 return err; 850 } 851 852 req_mask = __get_request_mask(inode); 853 854 spin_lock(&ci->i_ceph_lock); 855 dout("getxattr %p name '%s' ver=%lld index_ver=%lld\n", inode, name, 856 ci->i_xattrs.version, ci->i_xattrs.index_version); 857 858 if (ci->i_xattrs.version == 0 || 859 !((req_mask & CEPH_CAP_XATTR_SHARED) || 860 __ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 1))) { 861 spin_unlock(&ci->i_ceph_lock); 862 863 /* security module gets xattr while filling trace */ 864 if (current->journal_info) { 865 pr_warn_ratelimited("sync getxattr %p " 866 "during filling trace\n", inode); 867 return -EBUSY; 868 } 869 870 /* get xattrs from mds (if we don't already have them) */ 871 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 872 if (err) 873 return err; 874 spin_lock(&ci->i_ceph_lock); 875 } 876 877 err = __build_xattrs(inode); 878 if (err < 0) 879 goto out; 880 881 err = -ENODATA; /* == ENOATTR */ 882 xattr = __get_xattr(ci, name); 883 if (!xattr) 884 goto out; 885 886 err = -ERANGE; 887 if (size && size < xattr->val_len) 888 goto out; 889 890 err = xattr->val_len; 891 if (size == 0) 892 goto out; 893 894 memcpy(value, xattr->val, xattr->val_len); 895 896 if (current->journal_info && 897 !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && 898 security_ismaclabel(name + XATTR_SECURITY_PREFIX_LEN)) 899 ci->i_ceph_flags |= CEPH_I_SEC_INITED; 900 out: 901 spin_unlock(&ci->i_ceph_lock); 902 return err; 903 } 904 905 ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) 906 { 907 struct inode *inode = d_inode(dentry); 908 struct ceph_inode_info *ci = ceph_inode(inode); 909 bool len_only = (size == 0); 910 u32 namelen; 911 int err; 912 913 spin_lock(&ci->i_ceph_lock); 914 dout("listxattr %p ver=%lld index_ver=%lld\n", inode, 915 ci->i_xattrs.version, ci->i_xattrs.index_version); 916 917 if (ci->i_xattrs.version == 0 || 918 !__ceph_caps_issued_mask_metric(ci, CEPH_CAP_XATTR_SHARED, 1)) { 919 spin_unlock(&ci->i_ceph_lock); 920 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true); 921 if (err) 922 return err; 923 spin_lock(&ci->i_ceph_lock); 924 } 925 926 err = __build_xattrs(inode); 927 if (err < 0) 928 goto out; 929 930 /* add 1 byte for each xattr due to the null termination */ 931 namelen = ci->i_xattrs.names_size + ci->i_xattrs.count; 932 if (!len_only) { 933 if (namelen > size) { 934 err = -ERANGE; 935 goto out; 936 } 937 names = __copy_xattr_names(ci, names); 938 size -= namelen; 939 } 940 err = namelen; 941 out: 942 spin_unlock(&ci->i_ceph_lock); 943 return err; 944 } 945 946 static int ceph_sync_setxattr(struct inode *inode, const char *name, 947 const char *value, size_t size, int flags) 948 { 949 struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); 950 struct ceph_inode_info *ci = ceph_inode(inode); 951 struct ceph_mds_request *req; 952 struct ceph_mds_client *mdsc = fsc->mdsc; 953 struct ceph_pagelist *pagelist = NULL; 954 int op = CEPH_MDS_OP_SETXATTR; 955 int err; 956 957 if (size > 0) { 958 /* copy value into pagelist */ 959 pagelist = ceph_pagelist_alloc(GFP_NOFS); 960 if (!pagelist) 961 return -ENOMEM; 962 963 err = ceph_pagelist_append(pagelist, value, size); 964 if (err) 965 goto out; 966 } else if (!value) { 967 if (flags & CEPH_XATTR_REPLACE) 968 op = CEPH_MDS_OP_RMXATTR; 969 else 970 flags |= CEPH_XATTR_REMOVE; 971 } 972 973 dout("setxattr value=%.*s\n", (int)size, value); 974 975 /* do request */ 976 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS); 977 if (IS_ERR(req)) { 978 err = PTR_ERR(req); 979 goto out; 980 } 981 982 req->r_path2 = kstrdup(name, GFP_NOFS); 983 if (!req->r_path2) { 984 ceph_mdsc_put_request(req); 985 err = -ENOMEM; 986 goto out; 987 } 988 989 if (op == CEPH_MDS_OP_SETXATTR) { 990 req->r_args.setxattr.flags = cpu_to_le32(flags); 991 req->r_pagelist = pagelist; 992 pagelist = NULL; 993 } 994 995 req->r_inode = inode; 996 ihold(inode); 997 req->r_num_caps = 1; 998 req->r_inode_drop = CEPH_CAP_XATTR_SHARED; 999 1000 dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); 1001 err = ceph_mdsc_do_request(mdsc, NULL, req); 1002 ceph_mdsc_put_request(req); 1003 dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); 1004 1005 out: 1006 if (pagelist) 1007 ceph_pagelist_release(pagelist); 1008 return err; 1009 } 1010 1011 int __ceph_setxattr(struct inode *inode, const char *name, 1012 const void *value, size_t size, int flags) 1013 { 1014 struct ceph_vxattr *vxattr; 1015 struct ceph_inode_info *ci = ceph_inode(inode); 1016 struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; 1017 struct ceph_cap_flush *prealloc_cf = NULL; 1018 struct ceph_buffer *old_blob = NULL; 1019 int issued; 1020 int err; 1021 int dirty = 0; 1022 int name_len = strlen(name); 1023 int val_len = size; 1024 char *newname = NULL; 1025 char *newval = NULL; 1026 struct ceph_inode_xattr *xattr = NULL; 1027 int required_blob_size; 1028 bool check_realm = false; 1029 bool lock_snap_rwsem = false; 1030 1031 if (ceph_snap(inode) != CEPH_NOSNAP) 1032 return -EROFS; 1033 1034 vxattr = ceph_match_vxattr(inode, name); 1035 if (vxattr) { 1036 if (vxattr->flags & VXATTR_FLAG_READONLY) 1037 return -EOPNOTSUPP; 1038 if (value && !strncmp(vxattr->name, "ceph.quota", 10)) 1039 check_realm = true; 1040 } 1041 1042 /* pass any unhandled ceph.* xattrs through to the MDS */ 1043 if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) 1044 goto do_sync_unlocked; 1045 1046 /* preallocate memory for xattr name, value, index node */ 1047 err = -ENOMEM; 1048 newname = kmemdup(name, name_len + 1, GFP_NOFS); 1049 if (!newname) 1050 goto out; 1051 1052 if (val_len) { 1053 newval = kmemdup(value, val_len, GFP_NOFS); 1054 if (!newval) 1055 goto out; 1056 } 1057 1058 xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS); 1059 if (!xattr) 1060 goto out; 1061 1062 prealloc_cf = ceph_alloc_cap_flush(); 1063 if (!prealloc_cf) 1064 goto out; 1065 1066 spin_lock(&ci->i_ceph_lock); 1067 retry: 1068 issued = __ceph_caps_issued(ci, NULL); 1069 if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) 1070 goto do_sync; 1071 1072 if (!lock_snap_rwsem && !ci->i_head_snapc) { 1073 lock_snap_rwsem = true; 1074 if (!down_read_trylock(&mdsc->snap_rwsem)) { 1075 spin_unlock(&ci->i_ceph_lock); 1076 down_read(&mdsc->snap_rwsem); 1077 spin_lock(&ci->i_ceph_lock); 1078 goto retry; 1079 } 1080 } 1081 1082 dout("setxattr %p name '%s' issued %s\n", inode, name, 1083 ceph_cap_string(issued)); 1084 __build_xattrs(inode); 1085 1086 required_blob_size = __get_required_blob_size(ci, name_len, val_len); 1087 1088 if (!ci->i_xattrs.prealloc_blob || 1089 required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { 1090 struct ceph_buffer *blob; 1091 1092 spin_unlock(&ci->i_ceph_lock); 1093 ceph_buffer_put(old_blob); /* Shouldn't be required */ 1094 dout(" pre-allocating new blob size=%d\n", required_blob_size); 1095 blob = ceph_buffer_new(required_blob_size, GFP_NOFS); 1096 if (!blob) 1097 goto do_sync_unlocked; 1098 spin_lock(&ci->i_ceph_lock); 1099 /* prealloc_blob can't be released while holding i_ceph_lock */ 1100 if (ci->i_xattrs.prealloc_blob) 1101 old_blob = ci->i_xattrs.prealloc_blob; 1102 ci->i_xattrs.prealloc_blob = blob; 1103 goto retry; 1104 } 1105 1106 err = __set_xattr(ci, newname, name_len, newval, val_len, 1107 flags, value ? 1 : -1, &xattr); 1108 1109 if (!err) { 1110 dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, 1111 &prealloc_cf); 1112 ci->i_xattrs.dirty = true; 1113 inode->i_ctime = current_time(inode); 1114 } 1115 1116 spin_unlock(&ci->i_ceph_lock); 1117 ceph_buffer_put(old_blob); 1118 if (lock_snap_rwsem) 1119 up_read(&mdsc->snap_rwsem); 1120 if (dirty) 1121 __mark_inode_dirty(inode, dirty); 1122 ceph_free_cap_flush(prealloc_cf); 1123 return err; 1124 1125 do_sync: 1126 spin_unlock(&ci->i_ceph_lock); 1127 do_sync_unlocked: 1128 if (lock_snap_rwsem) 1129 up_read(&mdsc->snap_rwsem); 1130 1131 /* security module set xattr while filling trace */ 1132 if (current->journal_info) { 1133 pr_warn_ratelimited("sync setxattr %p " 1134 "during filling trace\n", inode); 1135 err = -EBUSY; 1136 } else { 1137 err = ceph_sync_setxattr(inode, name, value, size, flags); 1138 if (err >= 0 && check_realm) { 1139 /* check if snaprealm was created for quota inode */ 1140 spin_lock(&ci->i_ceph_lock); 1141 if ((ci->i_max_files || ci->i_max_bytes) && 1142 !(ci->i_snap_realm && 1143 ci->i_snap_realm->ino == ci->i_vino.ino)) 1144 err = -EOPNOTSUPP; 1145 spin_unlock(&ci->i_ceph_lock); 1146 } 1147 } 1148 out: 1149 ceph_free_cap_flush(prealloc_cf); 1150 kfree(newname); 1151 kfree(newval); 1152 kfree(xattr); 1153 return err; 1154 } 1155 1156 static int ceph_get_xattr_handler(const struct xattr_handler *handler, 1157 struct dentry *dentry, struct inode *inode, 1158 const char *name, void *value, size_t size) 1159 { 1160 if (!ceph_is_valid_xattr(name)) 1161 return -EOPNOTSUPP; 1162 return __ceph_getxattr(inode, name, value, size); 1163 } 1164 1165 static int ceph_set_xattr_handler(const struct xattr_handler *handler, 1166 struct dentry *unused, struct inode *inode, 1167 const char *name, const void *value, 1168 size_t size, int flags) 1169 { 1170 if (!ceph_is_valid_xattr(name)) 1171 return -EOPNOTSUPP; 1172 return __ceph_setxattr(inode, name, value, size, flags); 1173 } 1174 1175 static const struct xattr_handler ceph_other_xattr_handler = { 1176 .prefix = "", /* match any name => handlers called with full name */ 1177 .get = ceph_get_xattr_handler, 1178 .set = ceph_set_xattr_handler, 1179 }; 1180 1181 #ifdef CONFIG_SECURITY 1182 bool ceph_security_xattr_wanted(struct inode *in) 1183 { 1184 return in->i_security != NULL; 1185 } 1186 1187 bool ceph_security_xattr_deadlock(struct inode *in) 1188 { 1189 struct ceph_inode_info *ci; 1190 bool ret; 1191 if (!in->i_security) 1192 return false; 1193 ci = ceph_inode(in); 1194 spin_lock(&ci->i_ceph_lock); 1195 ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) && 1196 !(ci->i_xattrs.version > 0 && 1197 __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)); 1198 spin_unlock(&ci->i_ceph_lock); 1199 return ret; 1200 } 1201 1202 #ifdef CONFIG_CEPH_FS_SECURITY_LABEL 1203 int ceph_security_init_secctx(struct dentry *dentry, umode_t mode, 1204 struct ceph_acl_sec_ctx *as_ctx) 1205 { 1206 struct ceph_pagelist *pagelist = as_ctx->pagelist; 1207 const char *name; 1208 size_t name_len; 1209 int err; 1210 1211 err = security_dentry_init_security(dentry, mode, &dentry->d_name, 1212 &as_ctx->sec_ctx, 1213 &as_ctx->sec_ctxlen); 1214 if (err < 0) { 1215 WARN_ON_ONCE(err != -EOPNOTSUPP); 1216 err = 0; /* do nothing */ 1217 goto out; 1218 } 1219 1220 err = -ENOMEM; 1221 if (!pagelist) { 1222 pagelist = ceph_pagelist_alloc(GFP_KERNEL); 1223 if (!pagelist) 1224 goto out; 1225 err = ceph_pagelist_reserve(pagelist, PAGE_SIZE); 1226 if (err) 1227 goto out; 1228 ceph_pagelist_encode_32(pagelist, 1); 1229 } 1230 1231 /* 1232 * FIXME: Make security_dentry_init_security() generic. Currently 1233 * It only supports single security module and only selinux has 1234 * dentry_init_security hook. 1235 */ 1236 name = XATTR_NAME_SELINUX; 1237 name_len = strlen(name); 1238 err = ceph_pagelist_reserve(pagelist, 1239 4 * 2 + name_len + as_ctx->sec_ctxlen); 1240 if (err) 1241 goto out; 1242 1243 if (as_ctx->pagelist) { 1244 /* update count of KV pairs */ 1245 BUG_ON(pagelist->length <= sizeof(__le32)); 1246 if (list_is_singular(&pagelist->head)) { 1247 le32_add_cpu((__le32*)pagelist->mapped_tail, 1); 1248 } else { 1249 struct page *page = list_first_entry(&pagelist->head, 1250 struct page, lru); 1251 void *addr = kmap_atomic(page); 1252 le32_add_cpu((__le32*)addr, 1); 1253 kunmap_atomic(addr); 1254 } 1255 } else { 1256 as_ctx->pagelist = pagelist; 1257 } 1258 1259 ceph_pagelist_encode_32(pagelist, name_len); 1260 ceph_pagelist_append(pagelist, name, name_len); 1261 1262 ceph_pagelist_encode_32(pagelist, as_ctx->sec_ctxlen); 1263 ceph_pagelist_append(pagelist, as_ctx->sec_ctx, as_ctx->sec_ctxlen); 1264 1265 err = 0; 1266 out: 1267 if (pagelist && !as_ctx->pagelist) 1268 ceph_pagelist_release(pagelist); 1269 return err; 1270 } 1271 #endif /* CONFIG_CEPH_FS_SECURITY_LABEL */ 1272 #endif /* CONFIG_SECURITY */ 1273 1274 void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx) 1275 { 1276 #ifdef CONFIG_CEPH_FS_POSIX_ACL 1277 posix_acl_release(as_ctx->acl); 1278 posix_acl_release(as_ctx->default_acl); 1279 #endif 1280 #ifdef CONFIG_CEPH_FS_SECURITY_LABEL 1281 security_release_secctx(as_ctx->sec_ctx, as_ctx->sec_ctxlen); 1282 #endif 1283 if (as_ctx->pagelist) 1284 ceph_pagelist_release(as_ctx->pagelist); 1285 } 1286 1287 /* 1288 * List of handlers for synthetic system.* attributes. Other 1289 * attributes are handled directly. 1290 */ 1291 const struct xattr_handler *ceph_xattr_handlers[] = { 1292 #ifdef CONFIG_CEPH_FS_POSIX_ACL 1293 &posix_acl_access_xattr_handler, 1294 &posix_acl_default_xattr_handler, 1295 #endif 1296 &ceph_other_xattr_handler, 1297 NULL, 1298 }; 1299