1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/isa_defs.h> 28 #include <sys/types.h> 29 #include <sys/sysmacros.h> 30 #include <sys/cred.h> 31 #include <sys/systm.h> 32 #include <sys/errno.h> 33 #include <sys/fcntl.h> 34 #include <sys/pathname.h> 35 #include <sys/stat.h> 36 #include <sys/vfs.h> 37 #include <sys/acl.h> 38 #include <sys/file.h> 39 #include <sys/sunddi.h> 40 #include <sys/debug.h> 41 #include <sys/cmn_err.h> 42 #include <sys/vnode.h> 43 #include <sys/mode.h> 44 #include <sys/nvpair.h> 45 #include <sys/attr.h> 46 #include <sys/gfs.h> 47 #include <sys/mutex.h> 48 #include <fs/fs_subr.h> 49 #include <sys/kidmap.h> 50 51 typedef struct { 52 gfs_file_t gfs_private; 53 xattr_view_t xattr_view; 54 } xattr_file_t; 55 56 /* ARGSUSED */ 57 static int 58 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 59 { 60 xattr_file_t *np = (*vpp)->v_data; 61 62 if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE)) 63 return (EACCES); 64 65 return (0); 66 } 67 68 /* ARGSUSED */ 69 static int 70 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr, 71 caller_context_t *ct) 72 { 73 xattr_file_t *np = vp->v_data; 74 75 if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE)) 76 return (EACCES); 77 78 return (0); 79 } 80 81 /* ARGSUSED */ 82 static int 83 xattr_file_close(vnode_t *vp, int flags, int count, offset_t off, 84 cred_t *cr, caller_context_t *ct) 85 { 86 cleanlocks(vp, ddi_get_pid(), 0); 87 cleanshares(vp, ddi_get_pid()); 88 return (0); 89 } 90 91 static int 92 xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct) 93 { 94 xattr_fid_t *xfidp; 95 vnode_t *pvp, *savevp; 96 int error; 97 uint16_t orig_len; 98 99 if (fidp->fid_len < XATTR_FIDSZ) { 100 fidp->fid_len = XATTR_FIDSZ; 101 return (ENOSPC); 102 } 103 104 savevp = pvp = gfs_file_parent(vp); 105 mutex_enter(&savevp->v_lock); 106 if (pvp->v_flag & V_XATTRDIR) { 107 pvp = gfs_file_parent(pvp); 108 } 109 mutex_exit(&savevp->v_lock); 110 111 xfidp = (xattr_fid_t *)fidp; 112 orig_len = fidp->fid_len; 113 fidp->fid_len = sizeof (xfidp->parent_fid); 114 115 error = VOP_FID(pvp, fidp, ct); 116 if (error) { 117 fidp->fid_len = orig_len; 118 return (error); 119 } 120 121 xfidp->parent_len = fidp->fid_len; 122 fidp->fid_len = XATTR_FIDSZ; 123 xfidp->dir_offset = gfs_file_inode(vp); 124 125 return (0); 126 } 127 128 /* ARGSUSED */ 129 static int 130 xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp, 131 cred_t *cr, caller_context_t *ct) 132 { 133 int error; 134 f_attr_t attr; 135 uint64_t fsid; 136 xvattr_t xvattr; 137 xoptattr_t *xoap; /* Pointer to optional attributes */ 138 vnode_t *ppvp; 139 const char *domain; 140 uint32_t rid; 141 142 xva_init(&xvattr); 143 144 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) 145 return (EINVAL); 146 147 /* 148 * For detecting ephemeral uid/gid 149 */ 150 xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID); 151 152 /* 153 * We need to access the real fs object. 154 * vp points to a GFS file; ppvp points to the real object. 155 */ 156 ppvp = gfs_file_parent(gfs_file_parent(vp)); 157 158 /* 159 * Iterate through the attrs associated with this view 160 */ 161 162 for (attr = 0; attr < F_ATTR_ALL; attr++) { 163 if (xattr_view != attr_to_xattr_view(attr)) { 164 continue; 165 } 166 167 switch (attr) { 168 case F_SYSTEM: 169 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 170 break; 171 case F_READONLY: 172 XVA_SET_REQ(&xvattr, XAT_READONLY); 173 break; 174 case F_HIDDEN: 175 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 176 break; 177 case F_ARCHIVE: 178 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 179 break; 180 case F_IMMUTABLE: 181 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 182 break; 183 case F_APPENDONLY: 184 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 185 break; 186 case F_NOUNLINK: 187 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 188 break; 189 case F_OPAQUE: 190 XVA_SET_REQ(&xvattr, XAT_OPAQUE); 191 break; 192 case F_NODUMP: 193 XVA_SET_REQ(&xvattr, XAT_NODUMP); 194 break; 195 case F_AV_QUARANTINED: 196 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 197 break; 198 case F_AV_MODIFIED: 199 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 200 break; 201 case F_AV_SCANSTAMP: 202 if (ppvp->v_type == VREG) 203 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 204 break; 205 case F_CRTIME: 206 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 207 break; 208 case F_FSID: 209 fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) | 210 (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] & 211 0xffffffff)); 212 VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr), 213 fsid) == 0); 214 break; 215 default: 216 break; 217 } 218 } 219 220 error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 221 if (error) 222 return (error); 223 224 /* 225 * Process all the optional attributes together here. Notice that 226 * xoap was set when the optional attribute bits were set above. 227 */ 228 if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) { 229 if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) { 230 VERIFY(nvlist_add_boolean_value(nvlp, 231 attr_to_name(F_READONLY), 232 xoap->xoa_readonly) == 0); 233 } 234 if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) { 235 VERIFY(nvlist_add_boolean_value(nvlp, 236 attr_to_name(F_HIDDEN), 237 xoap->xoa_hidden) == 0); 238 } 239 if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) { 240 VERIFY(nvlist_add_boolean_value(nvlp, 241 attr_to_name(F_SYSTEM), 242 xoap->xoa_system) == 0); 243 } 244 if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) { 245 VERIFY(nvlist_add_boolean_value(nvlp, 246 attr_to_name(F_ARCHIVE), 247 xoap->xoa_archive) == 0); 248 } 249 if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) { 250 VERIFY(nvlist_add_boolean_value(nvlp, 251 attr_to_name(F_IMMUTABLE), 252 xoap->xoa_immutable) == 0); 253 } 254 if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) { 255 VERIFY(nvlist_add_boolean_value(nvlp, 256 attr_to_name(F_NOUNLINK), 257 xoap->xoa_nounlink) == 0); 258 } 259 if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) { 260 VERIFY(nvlist_add_boolean_value(nvlp, 261 attr_to_name(F_APPENDONLY), 262 xoap->xoa_appendonly) == 0); 263 } 264 if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) { 265 VERIFY(nvlist_add_boolean_value(nvlp, 266 attr_to_name(F_NODUMP), 267 xoap->xoa_nodump) == 0); 268 } 269 if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) { 270 VERIFY(nvlist_add_boolean_value(nvlp, 271 attr_to_name(F_OPAQUE), 272 xoap->xoa_opaque) == 0); 273 } 274 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) { 275 VERIFY(nvlist_add_boolean_value(nvlp, 276 attr_to_name(F_AV_QUARANTINED), 277 xoap->xoa_av_quarantined) == 0); 278 } 279 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) { 280 VERIFY(nvlist_add_boolean_value(nvlp, 281 attr_to_name(F_AV_MODIFIED), 282 xoap->xoa_av_modified) == 0); 283 } 284 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) { 285 VERIFY(nvlist_add_uint8_array(nvlp, 286 attr_to_name(F_AV_SCANSTAMP), 287 xoap->xoa_av_scanstamp, 288 sizeof (xoap->xoa_av_scanstamp)) == 0); 289 } 290 if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) { 291 VERIFY(nvlist_add_uint64_array(nvlp, 292 attr_to_name(F_CRTIME), 293 (uint64_t *)&(xoap->xoa_createtime), 294 sizeof (xoap->xoa_createtime) / 295 sizeof (uint64_t)) == 0); 296 } 297 } 298 /* 299 * Check for optional ownersid/groupsid 300 */ 301 302 if (xvattr.xva_vattr.va_uid > MAXUID) { 303 nvlist_t *nvl_sid; 304 305 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 306 return (ENOMEM); 307 308 if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid, 309 &domain, &rid) == 0) { 310 VERIFY(nvlist_add_string(nvl_sid, 311 SID_DOMAIN, domain) == 0); 312 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 313 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID), 314 nvl_sid) == 0); 315 } 316 nvlist_free(nvl_sid); 317 } 318 if (xvattr.xva_vattr.va_gid > MAXUID) { 319 nvlist_t *nvl_sid; 320 321 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP)) 322 return (ENOMEM); 323 324 if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid, 325 &domain, &rid) == 0) { 326 VERIFY(nvlist_add_string(nvl_sid, 327 SID_DOMAIN, domain) == 0); 328 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0); 329 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID), 330 nvl_sid) == 0); 331 } 332 nvlist_free(nvl_sid); 333 } 334 335 return (0); 336 } 337 338 /* 339 * The size of a sysattr file is the size of the nvlist that will be 340 * returned by xattr_file_read(). A call to xattr_file_write() could 341 * change the size of that nvlist. That size is not stored persistently 342 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated. 343 */ 344 static int 345 xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size, 346 cred_t *cr, caller_context_t *ct) 347 { 348 nvlist_t *nvl; 349 350 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) { 351 return (ENOMEM); 352 } 353 354 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 355 nvlist_free(nvl); 356 return (EFAULT); 357 } 358 359 VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0); 360 nvlist_free(nvl); 361 return (0); 362 } 363 364 /* ARGSUSED */ 365 static int 366 xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 367 caller_context_t *ct) 368 { 369 xattr_file_t *np = vp->v_data; 370 timestruc_t now; 371 size_t size; 372 int error; 373 vnode_t *pvp; 374 vattr_t pvattr; 375 376 vap->va_type = VREG; 377 vap->va_mode = MAKEIMODE(vap->va_type, 378 (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644)); 379 vap->va_nodeid = gfs_file_inode(vp); 380 vap->va_nlink = 1; 381 pvp = gfs_file_parent(vp); 382 (void) memset(&pvattr, 0, sizeof (pvattr)); 383 pvattr.va_mask = AT_CTIME|AT_MTIME; 384 error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct); 385 if (error) { 386 return (error); 387 } 388 vap->va_ctime = pvattr.va_ctime; 389 vap->va_mtime = pvattr.va_mtime; 390 gethrestime(&now); 391 vap->va_atime = now; 392 vap->va_uid = 0; 393 vap->va_gid = 0; 394 vap->va_rdev = 0; 395 vap->va_blksize = DEV_BSIZE; 396 vap->va_seq = 0; 397 vap->va_fsid = vp->v_vfsp->vfs_dev; 398 error = xattr_file_size(vp, np->xattr_view, &size, cr, ct); 399 vap->va_size = size; 400 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize); 401 return (error); 402 } 403 404 /* ARGSUSED */ 405 static int 406 xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 407 caller_context_t *ct) 408 { 409 xattr_file_t *np = vp->v_data; 410 xattr_view_t xattr_view = np->xattr_view; 411 char *buf; 412 size_t filesize; 413 nvlist_t *nvl; 414 int error; 415 416 /* 417 * Validate file offset and fasttrack empty reads 418 */ 419 if (uiop->uio_loffset < (offset_t)0) 420 return (EINVAL); 421 422 if (uiop->uio_resid == 0) 423 return (0); 424 425 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) 426 return (ENOMEM); 427 428 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) { 429 nvlist_free(nvl); 430 return (EFAULT); 431 } 432 433 VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0); 434 435 if (uiop->uio_loffset >= filesize) { 436 nvlist_free(nvl); 437 return (0); 438 } 439 440 buf = kmem_alloc(filesize, KM_SLEEP); 441 VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR, 442 KM_SLEEP) == 0); 443 444 error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop); 445 kmem_free(buf, filesize); 446 nvlist_free(nvl); 447 return (error); 448 } 449 450 /* ARGSUSED */ 451 static int 452 xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 453 caller_context_t *ct) 454 { 455 int error = 0; 456 char *buf; 457 char *domain; 458 uint32_t rid; 459 ssize_t size = uiop->uio_resid; 460 nvlist_t *nvp; 461 nvpair_t *pair = NULL; 462 vnode_t *ppvp; 463 xvattr_t xvattr; 464 xoptattr_t *xoap = NULL; /* Pointer to optional attributes */ 465 466 if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0) 467 return (EINVAL); 468 469 /* 470 * Validate file offset and size. 471 */ 472 if (uiop->uio_loffset < (offset_t)0) 473 return (EINVAL); 474 475 if (size == 0) 476 return (EINVAL); 477 478 xva_init(&xvattr); 479 480 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) { 481 return (EINVAL); 482 } 483 484 /* 485 * Copy and unpack the nvlist 486 */ 487 buf = kmem_alloc(size, KM_SLEEP); 488 if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) { 489 return (EFAULT); 490 } 491 492 if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) { 493 kmem_free(buf, size); 494 uiop->uio_resid = size; 495 return (EINVAL); 496 } 497 kmem_free(buf, size); 498 499 /* 500 * Fasttrack empty writes (nvlist with no nvpairs) 501 */ 502 if (nvlist_next_nvpair(nvp, NULL) == 0) 503 return (0); 504 505 ppvp = gfs_file_parent(gfs_file_parent(vp)); 506 507 while (pair = nvlist_next_nvpair(nvp, pair)) { 508 data_type_t type; 509 f_attr_t attr; 510 boolean_t value; 511 uint64_t *time, *times; 512 uint_t elem, nelems; 513 nvlist_t *nvp_sid; 514 uint8_t *scanstamp; 515 516 /* 517 * Validate the name and type of each attribute. 518 * Log any unknown names and continue. This will 519 * help if additional attributes are added later. 520 */ 521 type = nvpair_type(pair); 522 if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) { 523 cmn_err(CE_WARN, "Unknown attribute %s", 524 nvpair_name(pair)); 525 continue; 526 } 527 528 /* 529 * Verify nvlist type matches required type and view is OK 530 */ 531 532 if (type != attr_to_data_type(attr) || 533 (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) { 534 nvlist_free(nvp); 535 return (EINVAL); 536 } 537 538 /* 539 * For OWNERSID/GROUPSID make sure the target 540 * file system support ephemeral ID's 541 */ 542 if ((attr == F_OWNERSID || attr == F_GROUPSID) && 543 (!(vp->v_vfsp->vfs_flag & VFS_XID))) { 544 nvlist_free(nvp); 545 return (EINVAL); 546 } 547 548 /* 549 * Retrieve data from nvpair 550 */ 551 switch (type) { 552 case DATA_TYPE_BOOLEAN_VALUE: 553 if (nvpair_value_boolean_value(pair, &value)) { 554 nvlist_free(nvp); 555 return (EINVAL); 556 } 557 break; 558 case DATA_TYPE_UINT64_ARRAY: 559 if (nvpair_value_uint64_array(pair, ×, &nelems)) { 560 nvlist_free(nvp); 561 return (EINVAL); 562 } 563 break; 564 case DATA_TYPE_NVLIST: 565 if (nvpair_value_nvlist(pair, &nvp_sid)) { 566 nvlist_free(nvp); 567 return (EINVAL); 568 } 569 break; 570 case DATA_TYPE_UINT8_ARRAY: 571 if (nvpair_value_uint8_array(pair, 572 &scanstamp, &nelems)) { 573 nvlist_free(nvp); 574 return (EINVAL); 575 } 576 break; 577 default: 578 nvlist_free(nvp); 579 return (EINVAL); 580 } 581 582 switch (attr) { 583 /* 584 * If we have several similar optional attributes to 585 * process then we should do it all together here so that 586 * xoap and the requested bitmap can be set in one place. 587 */ 588 case F_READONLY: 589 XVA_SET_REQ(&xvattr, XAT_READONLY); 590 xoap->xoa_readonly = value; 591 break; 592 case F_HIDDEN: 593 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 594 xoap->xoa_hidden = value; 595 break; 596 case F_SYSTEM: 597 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 598 xoap->xoa_system = value; 599 break; 600 case F_ARCHIVE: 601 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 602 xoap->xoa_archive = value; 603 break; 604 case F_IMMUTABLE: 605 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 606 xoap->xoa_immutable = value; 607 break; 608 case F_NOUNLINK: 609 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 610 xoap->xoa_nounlink = value; 611 break; 612 case F_APPENDONLY: 613 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 614 xoap->xoa_appendonly = value; 615 break; 616 case F_NODUMP: 617 XVA_SET_REQ(&xvattr, XAT_NODUMP); 618 xoap->xoa_nodump = value; 619 break; 620 case F_AV_QUARANTINED: 621 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 622 xoap->xoa_av_quarantined = value; 623 break; 624 case F_AV_MODIFIED: 625 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 626 xoap->xoa_av_modified = value; 627 break; 628 case F_CRTIME: 629 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 630 time = (uint64_t *)&(xoap->xoa_createtime); 631 for (elem = 0; elem < nelems; elem++) 632 *time++ = times[elem]; 633 break; 634 case F_OWNERSID: 635 case F_GROUPSID: 636 if (nvlist_lookup_string(nvp_sid, SID_DOMAIN, 637 &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID, 638 &rid)) { 639 nvlist_free(nvp); 640 return (EINVAL); 641 } 642 643 /* 644 * Now map domain+rid to ephemeral id's 645 * 646 * If mapping fails, then the uid/gid will 647 * be set to UID_NOBODY by Winchester. 648 */ 649 650 if (attr == F_OWNERSID) { 651 (void) kidmap_getuidbysid(crgetzone(cr), domain, 652 rid, &xvattr.xva_vattr.va_uid); 653 xvattr.xva_vattr.va_mask |= AT_UID; 654 } else { 655 (void) kidmap_getgidbysid(crgetzone(cr), domain, 656 rid, &xvattr.xva_vattr.va_gid); 657 xvattr.xva_vattr.va_mask |= AT_GID; 658 } 659 break; 660 case F_AV_SCANSTAMP: 661 if (ppvp->v_type == VREG) { 662 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP); 663 (void) memcpy(xoap->xoa_av_scanstamp, 664 scanstamp, nelems); 665 } else { 666 nvlist_free(nvp); 667 return (EINVAL); 668 } 669 break; 670 default: 671 break; 672 } 673 } 674 675 ppvp = gfs_file_parent(gfs_file_parent(vp)); 676 error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct); 677 if (error) 678 uiop->uio_resid = size; 679 680 nvlist_free(nvp); 681 return (error); 682 } 683 684 static int 685 xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 686 caller_context_t *ct) 687 { 688 switch (cmd) { 689 case _PC_XATTR_EXISTS: 690 case _PC_SATTR_ENABLED: 691 case _PC_SATTR_EXISTS: 692 *valp = 0; 693 return (0); 694 default: 695 return (fs_pathconf(vp, cmd, valp, cr, ct)); 696 } 697 } 698 699 vnodeops_t *xattr_file_ops; 700 701 static const fs_operation_def_t xattr_file_tops[] = { 702 { VOPNAME_OPEN, { .vop_open = xattr_file_open } }, 703 { VOPNAME_CLOSE, { .vop_close = xattr_file_close } }, 704 { VOPNAME_READ, { .vop_read = xattr_file_read } }, 705 { VOPNAME_WRITE, { .vop_write = xattr_file_write } }, 706 { VOPNAME_IOCTL, { .error = fs_ioctl } }, 707 { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } }, 708 { VOPNAME_ACCESS, { .vop_access = xattr_file_access } }, 709 { VOPNAME_READDIR, { .error = fs_notdir } }, 710 { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 711 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } }, 712 { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 713 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } }, 714 { VOPNAME_PUTPAGE, { .error = fs_putpage } }, 715 { VOPNAME_FSYNC, { .error = fs_fsync } }, 716 { NULL } 717 }; 718 719 vnode_t * 720 xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view) 721 { 722 vnode_t *vp; 723 xattr_file_t *np; 724 725 vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops); 726 np = vp->v_data; 727 np->xattr_view = xattr_view; 728 vp->v_flag |= V_SYSATTR; 729 return (vp); 730 } 731 732 vnode_t * 733 xattr_mkfile_ro(vnode_t *pvp) 734 { 735 return (xattr_mkfile(pvp, XATTR_VIEW_READONLY)); 736 } 737 738 vnode_t * 739 xattr_mkfile_rw(vnode_t *pvp) 740 { 741 return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE)); 742 } 743 744 vnodeops_t *xattr_dir_ops; 745 746 static gfs_dirent_t xattr_dirents[] = { 747 { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, }, 748 { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, }, 749 { NULL }, 750 }; 751 752 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1) 753 754 static int 755 is_sattr_name(char *s) 756 { 757 int i; 758 759 for (i = 0; i < XATTRDIR_NENTS; ++i) { 760 if (strcmp(s, xattr_dirents[i].gfse_name) == 0) { 761 return (1); 762 } 763 } 764 return (0); 765 } 766 767 /* 768 * Given the name of an extended attribute file, determine if there is a 769 * normalization conflict with a sysattr view name. 770 */ 771 int 772 xattr_sysattr_casechk(char *s) 773 { 774 int i; 775 776 for (i = 0; i < XATTRDIR_NENTS; ++i) { 777 if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0) 778 return (1); 779 } 780 return (0); 781 } 782 783 static int 784 xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 785 cred_t *cr, caller_context_t *ct) 786 { 787 xvattr_t xvattr; 788 vnode_t *pdvp; 789 int error; 790 791 /* 792 * Only copy system attrs if the views are the same 793 */ 794 if (strcmp(snm, tnm) != 0) 795 return (EINVAL); 796 797 xva_init(&xvattr); 798 799 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 800 XVA_SET_REQ(&xvattr, XAT_READONLY); 801 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 802 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 803 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 804 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 805 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 806 XVA_SET_REQ(&xvattr, XAT_NODUMP); 807 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 808 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 809 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 810 811 pdvp = gfs_file_parent(sdvp); 812 error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 813 if (error) 814 return (error); 815 816 pdvp = gfs_file_parent(tdvp); 817 error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 818 return (error); 819 } 820 821 static int 822 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags, 823 cred_t *cr, caller_context_t *ct) 824 { 825 vnode_t *pvp; 826 int error; 827 struct pathname pn; 828 char *startnm = ""; 829 830 *realdvp = NULL; 831 832 pvp = gfs_file_parent(dvp); 833 834 error = pn_get(startnm, UIO_SYSSPACE, &pn); 835 if (error) { 836 VN_RELE(pvp); 837 return (error); 838 } 839 840 /* 841 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an 842 * infinite loop with fop_lookup calling back to xattr_dir_lookup. 843 */ 844 lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR; 845 error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags, 846 rootvp, cr, ct, NULL, NULL); 847 pn_free(&pn); 848 849 return (error); 850 } 851 852 /* ARGSUSED */ 853 static int 854 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 855 { 856 if (flags & FWRITE) { 857 return (EACCES); 858 } 859 860 return (0); 861 } 862 863 /* ARGSUSED */ 864 static int 865 xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr, 866 caller_context_t *ct) 867 { 868 return (0); 869 } 870 871 /* ARGSUSED */ 872 static int 873 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 874 caller_context_t *ct) 875 { 876 timestruc_t now; 877 vnode_t *pvp; 878 int error; 879 vattr_t pvattr; 880 881 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct); 882 if (error == 0) { 883 error = VOP_GETATTR(pvp, vap, 0, cr, ct); 884 VN_RELE(pvp); 885 if (error) { 886 return (error); 887 } 888 vap->va_nlink += XATTRDIR_NENTS; 889 vap->va_size += XATTRDIR_NENTS; 890 return (0); 891 } 892 893 /* 894 * There is no real xattr directory. Cobble together 895 * an entry using info from the parent object. 896 */ 897 pvp = gfs_file_parent(vp); 898 (void) memset(&pvattr, 0, sizeof (pvattr)); 899 pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME; 900 error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct); 901 if (error) { 902 return (error); 903 } 904 *vap = pvattr; 905 vap->va_type = VDIR; 906 vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777); 907 vap->va_fsid = vp->v_vfsp->vfs_dev; 908 vap->va_nodeid = gfs_file_inode(vp); 909 vap->va_nlink = XATTRDIR_NENTS+2; 910 vap->va_size = vap->va_nlink; 911 gethrestime(&now); 912 vap->va_atime = now; 913 vap->va_blksize = 0; 914 vap->va_nblocks = 0; 915 vap->va_seq = 0; 916 return (0); 917 } 918 919 static int 920 xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 921 caller_context_t *ct) 922 { 923 vnode_t *realvp; 924 int error; 925 926 /* 927 * If there is a real xattr directory, do the setattr there. 928 * Otherwise, just return success. The GFS directory is transient, 929 * and any setattr changes can disappear anyway. 930 */ 931 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 932 if (error == 0) { 933 error = VOP_SETATTR(realvp, vap, flags, cr, ct); 934 VN_RELE(realvp); 935 } 936 if (error == ENOENT) { 937 error = 0; 938 } 939 return (error); 940 } 941 942 /* ARGSUSED */ 943 static int 944 xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr, 945 caller_context_t *ct) 946 { 947 int error; 948 vnode_t *realvp = NULL; 949 950 if (mode & VWRITE) { 951 return (EACCES); 952 } 953 954 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 955 956 if (realvp) 957 VN_RELE(realvp); 958 959 /* 960 * No real xattr dir isn't an error 961 * an error of EINVAL indicates attributes on attributes 962 * are not supported. In that case just allow access to the 963 * transient directory. 964 */ 965 return ((error == ENOENT || error == EINVAL) ? 0 : error); 966 } 967 968 static int 969 xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, 970 int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 971 vsecattr_t *vsecp) 972 { 973 vnode_t *pvp; 974 int error; 975 976 *vpp = NULL; 977 978 /* 979 * Don't allow creation of extended attributes with sysattr names. 980 */ 981 if (is_sattr_name(name)) { 982 return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL)); 983 } 984 985 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 986 cr, ct); 987 if (error == 0) { 988 error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag, 989 ct, vsecp); 990 VN_RELE(pvp); 991 } 992 return (error); 993 } 994 995 static int 996 xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, 997 int flags) 998 { 999 vnode_t *pvp; 1000 int error; 1001 1002 if (is_sattr_name(name)) { 1003 return (EACCES); 1004 } 1005 1006 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1007 if (error == 0) { 1008 error = VOP_REMOVE(pvp, name, cr, ct, flags); 1009 VN_RELE(pvp); 1010 } 1011 return (error); 1012 } 1013 1014 static int 1015 xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, 1016 caller_context_t *ct, int flags) 1017 { 1018 vnode_t *pvp; 1019 int error; 1020 1021 if (svp->v_flag & V_SYSATTR) { 1022 return (EINVAL); 1023 } 1024 1025 error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct); 1026 if (error == 0) { 1027 error = VOP_LINK(pvp, svp, name, cr, ct, flags); 1028 VN_RELE(pvp); 1029 } 1030 return (error); 1031 } 1032 1033 static int 1034 xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 1035 cred_t *cr, caller_context_t *ct, int flags) 1036 { 1037 vnode_t *spvp, *tpvp; 1038 int error; 1039 int held_tgt; 1040 1041 if (is_sattr_name(snm) || is_sattr_name(tnm)) 1042 return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct)); 1043 /* 1044 * We know that sdvp is a GFS dir, or we wouldn't be here. 1045 * Get the real unnamed directory. 1046 */ 1047 error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct); 1048 if (error) { 1049 return (error); 1050 } 1051 1052 if (sdvp == tdvp) { 1053 /* 1054 * If the source and target are the same GFS directory, the 1055 * underlying unnamed source and target dir will be the same. 1056 */ 1057 tpvp = spvp; 1058 VN_HOLD(tpvp); 1059 held_tgt = 1; 1060 } else if (tdvp->v_flag & V_SYSATTR) { 1061 /* 1062 * If the target dir is a different GFS directory, 1063 * find its underlying unnamed dir. 1064 */ 1065 error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct); 1066 if (error) { 1067 VN_RELE(spvp); 1068 return (error); 1069 } 1070 held_tgt = 1; 1071 } else { 1072 /* 1073 * Target dir is outside of GFS, pass it on through. 1074 */ 1075 tpvp = tdvp; 1076 held_tgt = 0; 1077 } 1078 1079 error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags); 1080 1081 if (held_tgt) { 1082 VN_RELE(tpvp); 1083 } 1084 VN_RELE(spvp); 1085 1086 return (error); 1087 } 1088 1089 /* 1090 * readdir_xattr_casecmp: given a system attribute name, see if there 1091 * is a real xattr with the same normalized name. 1092 */ 1093 static int 1094 readdir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 1095 int *eflags) 1096 { 1097 int error; 1098 vnode_t *vp; 1099 struct pathname pn; 1100 1101 *eflags = 0; 1102 1103 error = pn_get(nm, UIO_SYSSPACE, &pn); 1104 if (error == 0) { 1105 error = VOP_LOOKUP(dvp, nm, &vp, &pn, 1106 FIGNORECASE, rootvp, cr, ct, NULL, NULL); 1107 if (error == 0) { 1108 *eflags = ED_CASE_CONFLICT; 1109 VN_RELE(vp); 1110 } else if (error == ENOENT) { 1111 error = 0; 1112 } 1113 pn_free(&pn); 1114 } 1115 1116 return (error); 1117 } 1118 1119 static int 1120 xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp, 1121 caller_context_t *ct, int flags) 1122 { 1123 vnode_t *pvp; 1124 int error; 1125 int local_eof; 1126 int reset_off = 0; 1127 int has_xattrs = 0; 1128 1129 if (eofp == NULL) { 1130 eofp = &local_eof; 1131 } 1132 *eofp = 0; 1133 1134 /* 1135 * See if there is a real extended attribute directory. 1136 */ 1137 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1138 if (error == 0) { 1139 has_xattrs = 1; 1140 } 1141 1142 /* 1143 * Start by reading up the static entries. 1144 */ 1145 if (uiop->uio_loffset == 0) { 1146 ino64_t pino, ino; 1147 offset_t off; 1148 gfs_dir_t *dp = dvp->v_data; 1149 gfs_readdir_state_t gstate; 1150 1151 if (has_xattrs) { 1152 /* 1153 * If there is a real xattr dir, skip . and .. 1154 * in the GFS dir. We'll pick them up below 1155 * when we call into the underlying fs. 1156 */ 1157 uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET; 1158 } 1159 error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino); 1160 if (error == 0) { 1161 error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, 1162 uiop, pino, ino, flags); 1163 } 1164 if (error) { 1165 if (has_xattrs) 1166 VN_RELE(pvp); 1167 return (error); 1168 } 1169 1170 while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 && 1171 !*eofp) { 1172 if (off >= 0 && off < dp->gfsd_nstatic) { 1173 int eflags; 1174 1175 /* 1176 * Check to see if this sysattr set name has a 1177 * case-insensitive conflict with a real xattr 1178 * name. 1179 */ 1180 eflags = 0; 1181 if ((flags & V_RDDIR_ENTFLAGS) && has_xattrs) { 1182 error = readdir_xattr_casecmp(pvp, 1183 dp->gfsd_static[off].gfse_name, 1184 cr, ct, &eflags); 1185 if (error) 1186 break; 1187 } 1188 ino = dp->gfsd_inode(dvp, off); 1189 1190 error = gfs_readdir_emit(&gstate, uiop, off, 1191 ino, dp->gfsd_static[off].gfse_name, 1192 eflags); 1193 if (error) 1194 break; 1195 } else { 1196 *eofp = 1; 1197 } 1198 } 1199 1200 error = gfs_readdir_fini(&gstate, error, eofp, *eofp); 1201 if (error) { 1202 if (has_xattrs) 1203 VN_RELE(pvp); 1204 return (error); 1205 } 1206 1207 /* 1208 * We must read all of the static entries in the first 1209 * call. Otherwise we won't know if uio_loffset in a 1210 * subsequent call refers to the static entries or to those 1211 * in an underlying fs. 1212 */ 1213 ASSERT(*eofp); 1214 reset_off = 1; 1215 } 1216 1217 if (!has_xattrs) { 1218 *eofp = 1; 1219 return (0); 1220 } 1221 1222 *eofp = 0; 1223 if (reset_off) { 1224 uiop->uio_loffset = 0; 1225 } 1226 (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1227 error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags); 1228 VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1229 VN_RELE(pvp); 1230 1231 return (error); 1232 } 1233 1234 /* ARGSUSED */ 1235 static void 1236 xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1237 { 1238 gfs_file_t *fp; 1239 1240 fp = gfs_dir_inactive(vp); 1241 if (fp != NULL) { 1242 kmem_free(fp, fp->gfs_size); 1243 } 1244 } 1245 1246 static int 1247 xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 1248 caller_context_t *ct) 1249 { 1250 switch (cmd) { 1251 case _PC_XATTR_EXISTS: 1252 case _PC_SATTR_ENABLED: 1253 case _PC_SATTR_EXISTS: 1254 *valp = 0; 1255 return (0); 1256 default: 1257 return (fs_pathconf(vp, cmd, valp, cr, ct)); 1258 } 1259 } 1260 1261 static const fs_operation_def_t xattr_dir_tops[] = { 1262 { VOPNAME_OPEN, { .vop_open = xattr_dir_open } }, 1263 { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } }, 1264 { VOPNAME_IOCTL, { .error = fs_inval } }, 1265 { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } }, 1266 { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } }, 1267 { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } }, 1268 { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } }, 1269 { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } }, 1270 { VOPNAME_CREATE, { .vop_create = xattr_dir_create } }, 1271 { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } }, 1272 { VOPNAME_LINK, { .vop_link = xattr_dir_link } }, 1273 { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } }, 1274 { VOPNAME_MKDIR, { .error = fs_inval } }, 1275 { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1276 { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } }, 1277 { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 1278 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } }, 1279 { NULL, NULL } 1280 }; 1281 1282 static gfs_opsvec_t xattr_opsvec[] = { 1283 { "xattr dir", xattr_dir_tops, &xattr_dir_ops }, 1284 { "system attributes", xattr_file_tops, &xattr_file_ops }, 1285 { NULL, NULL, NULL } 1286 }; 1287 1288 static int 1289 xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop, 1290 cred_t *cr, int flags, int *deflags, pathname_t *rpnp) 1291 { 1292 vnode_t *pvp; 1293 struct pathname pn; 1294 int error; 1295 1296 *vpp = NULL; 1297 *inop = 0; 1298 1299 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 1300 cr, NULL); 1301 1302 /* 1303 * Return ENOENT for EACCES requests during lookup. Once an 1304 * attribute create is attempted EACCES will be returned. 1305 */ 1306 if (error) { 1307 if (error == EACCES) 1308 return (ENOENT); 1309 return (error); 1310 } 1311 1312 error = pn_get((char *)nm, UIO_SYSSPACE, &pn); 1313 if (error == 0) { 1314 error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, flags, rootvp, 1315 cr, NULL, deflags, rpnp); 1316 pn_free(&pn); 1317 } 1318 VN_RELE(pvp); 1319 1320 return (error); 1321 } 1322 1323 /* ARGSUSED */ 1324 static ino64_t 1325 xattrdir_do_ino(vnode_t *vp, int index) 1326 { 1327 /* 1328 * We use index 0 for the directory fid. Start 1329 * the file numbering at 1. 1330 */ 1331 return ((ino64_t)index+1); 1332 } 1333 1334 void 1335 xattr_init(void) 1336 { 1337 VERIFY(gfs_make_opsvec(xattr_opsvec) == 0); 1338 } 1339 1340 int 1341 xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr) 1342 { 1343 int error = 0; 1344 1345 *vpp = NULL; 1346 1347 if (dvp->v_type != VDIR && dvp->v_type != VREG) 1348 return (EINVAL); 1349 1350 mutex_enter(&dvp->v_lock); 1351 1352 /* 1353 * If we're already in sysattr space, don't allow creation 1354 * of another level of sysattrs. 1355 */ 1356 if (dvp->v_flag & V_SYSATTR) { 1357 mutex_exit(&dvp->v_lock); 1358 return (EINVAL); 1359 } 1360 1361 if (dvp->v_xattrdir != NULL) { 1362 *vpp = dvp->v_xattrdir; 1363 VN_HOLD(*vpp); 1364 } else { 1365 ulong_t val; 1366 int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR; 1367 int sysattrs_allowed = 1; 1368 1369 /* 1370 * We have to drop the lock on dvp. gfs_dir_create will 1371 * grab it for a VN_HOLD. 1372 */ 1373 mutex_exit(&dvp->v_lock); 1374 1375 /* 1376 * If dvp allows xattr creation, but not sysattr 1377 * creation, return the real xattr dir vp. We can't 1378 * use the vfs feature mask here because _PC_SATTR_ENABLED 1379 * has vnode-level granularity (e.g. .zfs). 1380 */ 1381 error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL); 1382 if (error != 0 || val == 0) 1383 sysattrs_allowed = 0; 1384 1385 if (!xattrs_allowed && !sysattrs_allowed) 1386 return (EINVAL); 1387 1388 if (!sysattrs_allowed) { 1389 struct pathname pn; 1390 char *nm = ""; 1391 1392 error = pn_get(nm, UIO_SYSSPACE, &pn); 1393 if (error) 1394 return (error); 1395 error = VOP_LOOKUP(dvp, nm, vpp, &pn, 1396 flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL, 1397 NULL, NULL); 1398 pn_free(&pn); 1399 return (error); 1400 } 1401 1402 /* 1403 * Note that we act as if we were given CREATE_XATTR_DIR, 1404 * but only for creation of the GFS directory. 1405 */ 1406 *vpp = gfs_dir_create( 1407 sizeof (gfs_dir_t), dvp, xattr_dir_ops, xattr_dirents, 1408 xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb); 1409 mutex_enter(&dvp->v_lock); 1410 if (dvp->v_xattrdir != NULL) { 1411 /* 1412 * We lost the race to create the xattr dir. 1413 * Destroy this one, use the winner. We can't 1414 * just call VN_RELE(*vpp), because the vnode 1415 * is only partially initialized. 1416 */ 1417 gfs_dir_t *dp = (*vpp)->v_data; 1418 1419 ASSERT((*vpp)->v_count == 1); 1420 vn_free(*vpp); 1421 1422 mutex_destroy(&dp->gfsd_lock); 1423 kmem_free(dp->gfsd_static, 1424 dp->gfsd_nstatic * sizeof (gfs_dirent_t)); 1425 kmem_free(dp, dp->gfsd_file.gfs_size); 1426 1427 /* 1428 * There is an implied VN_HOLD(dvp) here. We should 1429 * be doing a VN_RELE(dvp) to clean up the reference 1430 * from *vpp, and then a VN_HOLD(dvp) for the new 1431 * reference. Instead, we just leave the count alone. 1432 */ 1433 1434 *vpp = dvp->v_xattrdir; 1435 VN_HOLD(*vpp); 1436 } else { 1437 (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR); 1438 dvp->v_xattrdir = *vpp; 1439 } 1440 } 1441 mutex_exit(&dvp->v_lock); 1442 1443 return (error); 1444 } 1445 1446 int 1447 xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 1448 { 1449 int error; 1450 vnode_t *pvp, *dvp; 1451 xattr_fid_t *xfidp; 1452 struct pathname pn; 1453 char *nm; 1454 uint16_t orig_len; 1455 1456 *vpp = NULL; 1457 1458 if (fidp->fid_len < XATTR_FIDSZ) 1459 return (EINVAL); 1460 1461 xfidp = (xattr_fid_t *)fidp; 1462 orig_len = fidp->fid_len; 1463 fidp->fid_len = xfidp->parent_len; 1464 1465 error = VFS_VGET(vfsp, &pvp, fidp); 1466 fidp->fid_len = orig_len; 1467 if (error) 1468 return (error); 1469 1470 /* 1471 * Start by getting the GFS sysattr directory. We might need 1472 * to recreate it during the VOP_LOOKUP. 1473 */ 1474 nm = ""; 1475 error = pn_get(nm, UIO_SYSSPACE, &pn); 1476 if (error) { 1477 VN_RELE(pvp); 1478 return (EINVAL); 1479 } 1480 1481 error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR, 1482 rootvp, CRED(), NULL, NULL, NULL); 1483 pn_free(&pn); 1484 VN_RELE(pvp); 1485 if (error) 1486 return (error); 1487 1488 if (xfidp->dir_offset == 0) { 1489 /* 1490 * If we were looking for the directory, we're done. 1491 */ 1492 *vpp = dvp; 1493 return (0); 1494 } 1495 1496 if (xfidp->dir_offset > XATTRDIR_NENTS) { 1497 VN_RELE(dvp); 1498 return (EINVAL); 1499 } 1500 1501 nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name; 1502 1503 error = pn_get(nm, UIO_SYSSPACE, &pn); 1504 if (error) { 1505 VN_RELE(dvp); 1506 return (EINVAL); 1507 } 1508 1509 error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL, 1510 NULL, NULL); 1511 1512 pn_free(&pn); 1513 VN_RELE(dvp); 1514 1515 return (error); 1516 } 1517