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