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