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 /* 773 * Given the name of an extended attribute file, determine if there is a 774 * normalization conflict with a sysattr view name. 775 */ 776 int 777 xattr_sysattr_casechk(char *s) 778 { 779 int i; 780 781 for (i = 0; i < XATTRDIR_NENTS; ++i) { 782 if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0) 783 return (1); 784 } 785 return (0); 786 } 787 788 static int 789 xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 790 cred_t *cr, caller_context_t *ct) 791 { 792 xvattr_t xvattr; 793 vnode_t *pdvp; 794 int error; 795 796 /* 797 * Only copy system attrs if the views are the same 798 */ 799 if (strcmp(snm, tnm) != 0) 800 return (EINVAL); 801 802 xva_init(&xvattr); 803 804 XVA_SET_REQ(&xvattr, XAT_SYSTEM); 805 XVA_SET_REQ(&xvattr, XAT_READONLY); 806 XVA_SET_REQ(&xvattr, XAT_HIDDEN); 807 XVA_SET_REQ(&xvattr, XAT_ARCHIVE); 808 XVA_SET_REQ(&xvattr, XAT_APPENDONLY); 809 XVA_SET_REQ(&xvattr, XAT_NOUNLINK); 810 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE); 811 XVA_SET_REQ(&xvattr, XAT_NODUMP); 812 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED); 813 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED); 814 XVA_SET_REQ(&xvattr, XAT_CREATETIME); 815 816 pdvp = gfs_file_parent(sdvp); 817 error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 818 if (error) 819 return (error); 820 821 pdvp = gfs_file_parent(tdvp); 822 error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct); 823 return (error); 824 } 825 826 static int 827 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags, 828 cred_t *cr, caller_context_t *ct) 829 { 830 vnode_t *pvp; 831 int error; 832 struct pathname pn; 833 char *startnm = ""; 834 835 *realdvp = NULL; 836 837 pvp = gfs_file_parent(dvp); 838 839 error = pn_get(startnm, UIO_SYSSPACE, &pn); 840 if (error) { 841 VN_RELE(pvp); 842 return (error); 843 } 844 845 /* 846 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an 847 * infinite loop with fop_lookup calling back to xattr_dir_lookup. 848 */ 849 lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR; 850 error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags, 851 rootvp, cr, ct, NULL, NULL); 852 pn_free(&pn); 853 854 return (error); 855 } 856 857 /* ARGSUSED */ 858 static int 859 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct) 860 { 861 if (flags & FWRITE) { 862 return (EACCES); 863 } 864 865 return (0); 866 } 867 868 /* ARGSUSED */ 869 static int 870 xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr, 871 caller_context_t *ct) 872 { 873 return (0); 874 } 875 876 /* ARGSUSED */ 877 static int 878 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 879 caller_context_t *ct) 880 { 881 timestruc_t now; 882 vnode_t *pvp; 883 int error; 884 vattr_t pvattr; 885 886 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct); 887 if (error == 0) { 888 error = VOP_GETATTR(pvp, vap, 0, cr, ct); 889 VN_RELE(pvp); 890 if (error) { 891 return (error); 892 } 893 vap->va_nlink += XATTRDIR_NENTS; 894 vap->va_size += XATTRDIR_NENTS; 895 return (0); 896 } 897 898 /* 899 * There is no real xattr directory. Cobble together 900 * an entry using info from the parent object. 901 */ 902 pvp = gfs_file_parent(vp); 903 (void) memset(&pvattr, 0, sizeof (pvattr)); 904 pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME; 905 error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct); 906 if (error) { 907 return (error); 908 } 909 *vap = pvattr; 910 vap->va_type = VDIR; 911 vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777); 912 vap->va_fsid = vp->v_vfsp->vfs_dev; 913 vap->va_nodeid = gfs_file_inode(vp); 914 vap->va_nlink = XATTRDIR_NENTS+2; 915 vap->va_size = vap->va_nlink; 916 gethrestime(&now); 917 vap->va_atime = now; 918 vap->va_blksize = 0; 919 vap->va_nblocks = 0; 920 vap->va_seq = 0; 921 return (0); 922 } 923 924 static int 925 xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 926 caller_context_t *ct) 927 { 928 vnode_t *realvp; 929 int error; 930 931 /* 932 * If there is a real xattr directory, do the setattr there. 933 * Otherwise, just return success. The GFS directory is transient, 934 * and any setattr changes can disappear anyway. 935 */ 936 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 937 if (error == 0) { 938 error = VOP_SETATTR(realvp, vap, flags, cr, ct); 939 VN_RELE(realvp); 940 } 941 if (error == ENOENT) { 942 error = 0; 943 } 944 return (error); 945 } 946 947 /* ARGSUSED */ 948 static int 949 xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr, 950 caller_context_t *ct) 951 { 952 int error; 953 vnode_t *realvp = NULL; 954 955 if (mode & VWRITE) { 956 return (EACCES); 957 } 958 959 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct); 960 961 if (realvp) 962 VN_RELE(realvp); 963 964 /* 965 * No real xattr dir isn't an error 966 * an error of EINVAL indicates attributes on attributes 967 * are not supported. In that case just allow access to the 968 * transient directory. 969 */ 970 return ((error == ENOENT || error == EINVAL) ? 0 : error); 971 } 972 973 static int 974 xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, 975 int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 976 vsecattr_t *vsecp) 977 { 978 vnode_t *pvp; 979 int error; 980 981 *vpp = NULL; 982 983 /* 984 * Don't allow creation of extended attributes with sysattr names. 985 */ 986 if (is_sattr_name(name)) { 987 return (gfs_dir_lookup(dvp, name, vpp, cr)); 988 } 989 990 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 991 cr, ct); 992 if (error == 0) { 993 error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag, 994 ct, vsecp); 995 VN_RELE(pvp); 996 } 997 return (error); 998 } 999 1000 static int 1001 xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct, 1002 int flags) 1003 { 1004 vnode_t *pvp; 1005 int error; 1006 1007 if (is_sattr_name(name)) { 1008 return (EACCES); 1009 } 1010 1011 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1012 if (error == 0) { 1013 error = VOP_REMOVE(pvp, name, cr, ct, flags); 1014 VN_RELE(pvp); 1015 } 1016 return (error); 1017 } 1018 1019 static int 1020 xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, 1021 caller_context_t *ct, int flags) 1022 { 1023 vnode_t *pvp; 1024 int error; 1025 1026 if (svp->v_flag & V_SYSATTR) { 1027 return (EINVAL); 1028 } 1029 1030 error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct); 1031 if (error == 0) { 1032 error = VOP_LINK(pvp, svp, name, cr, ct, flags); 1033 VN_RELE(pvp); 1034 } 1035 return (error); 1036 } 1037 1038 static int 1039 xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 1040 cred_t *cr, caller_context_t *ct, int flags) 1041 { 1042 vnode_t *spvp, *tpvp; 1043 int error; 1044 int held_tgt; 1045 1046 if (is_sattr_name(snm) || is_sattr_name(tnm)) 1047 return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct)); 1048 /* 1049 * We know that sdvp is a GFS dir, or we wouldn't be here. 1050 * Get the real unnamed directory. 1051 */ 1052 error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct); 1053 if (error) { 1054 return (error); 1055 } 1056 1057 if (sdvp == tdvp) { 1058 /* 1059 * If the source and target are the same GFS directory, the 1060 * underlying unnamed source and target dir will be the same. 1061 */ 1062 tpvp = spvp; 1063 VN_HOLD(tpvp); 1064 held_tgt = 1; 1065 } else if (tdvp->v_flag & V_SYSATTR) { 1066 /* 1067 * If the target dir is a different GFS directory, 1068 * find its underlying unnamed dir. 1069 */ 1070 error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct); 1071 if (error) { 1072 VN_RELE(spvp); 1073 return (error); 1074 } 1075 held_tgt = 1; 1076 } else { 1077 /* 1078 * Target dir is outside of GFS, pass it on through. 1079 */ 1080 tpvp = tdvp; 1081 held_tgt = 0; 1082 } 1083 1084 error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags); 1085 1086 if (held_tgt) { 1087 VN_RELE(tpvp); 1088 } 1089 VN_RELE(spvp); 1090 1091 return (error); 1092 } 1093 1094 /* 1095 * readdir_xattr_casecmp: given a system attribute name, see if there 1096 * is a real xattr with the same normalized name. 1097 */ 1098 static int 1099 readdir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 1100 int *eflags) 1101 { 1102 int error; 1103 vnode_t *vp; 1104 struct pathname pn; 1105 int flags = FIGNORECASE; 1106 1107 *eflags = 0; 1108 1109 error = pn_get(nm, UIO_SYSSPACE, &pn); 1110 if (error == 0) { 1111 error = VOP_LOOKUP(dvp, nm, &vp, &pn, LOOKUP_XATTR, rootvp, 1112 cr, ct, &flags, NULL); 1113 if (error == 0) { 1114 *eflags = ED_CASE_CONFLICT; 1115 VN_RELE(vp); 1116 } else if (error == ENOENT) { 1117 error = 0; 1118 } 1119 pn_free(&pn); 1120 } 1121 1122 return (error); 1123 } 1124 1125 static int 1126 xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp, 1127 caller_context_t *ct, int flags) 1128 { 1129 vnode_t *pvp; 1130 int error; 1131 int local_eof = 0; 1132 int reset_off = 0; 1133 int has_xattrs = 0; 1134 1135 if (eofp == NULL) { 1136 eofp = &local_eof; 1137 } 1138 1139 /* 1140 * See if there is a real extended attribute directory. 1141 */ 1142 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct); 1143 if (error == 0) { 1144 has_xattrs = 1; 1145 } 1146 1147 /* 1148 * Start by reading up the static entries. 1149 */ 1150 if (uiop->uio_loffset == 0) { 1151 ino64_t pino, ino; 1152 offset_t off; 1153 gfs_dir_t *dp = dvp->v_data; 1154 gfs_readdir_state_t gstate; 1155 1156 if (has_xattrs) { 1157 /* 1158 * If there is a real xattr dir, skip . and .. 1159 * in the GFS dir. We'll pick them up below 1160 * when we call into the underlying fs. 1161 */ 1162 uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET; 1163 } 1164 error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino); 1165 if (error == 0) { 1166 error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, 1167 uiop, pino, ino, flags); 1168 } 1169 if (error) { 1170 if (has_xattrs) 1171 VN_RELE(pvp); 1172 return (error); 1173 } 1174 1175 while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 && 1176 !*eofp) { 1177 if (off >= 0 && off < dp->gfsd_nstatic) { 1178 int eflags = 0; 1179 1180 /* 1181 * Check to see if this sysattr set name has a 1182 * case-insensitive conflict with a real xattr 1183 * name. 1184 */ 1185 if ((flags & V_RDDIR_ENTFLAGS) && has_xattrs) { 1186 error = readdir_xattr_casecmp(pvp, 1187 dp->gfsd_static[off].gfse_name, 1188 cr, ct, &eflags); 1189 if (error) 1190 break; 1191 } 1192 ino = dp->gfsd_inode(dvp, off); 1193 1194 error = gfs_readdir_emit(&gstate, uiop, off, 1195 ino, dp->gfsd_static[off].gfse_name, 1196 eflags); 1197 if (error) 1198 break; 1199 } else { 1200 *eofp = 1; 1201 } 1202 } 1203 1204 error = gfs_readdir_fini(&gstate, error, eofp, *eofp); 1205 if (error) { 1206 if (has_xattrs) 1207 VN_RELE(pvp); 1208 return (error); 1209 } 1210 1211 /* 1212 * We must read all of the static entries in the first 1213 * call. Otherwise we won't know if uio_loffset in a 1214 * subsequent call refers to the static entries or to those 1215 * in an underlying fs. 1216 */ 1217 ASSERT(*eofp); 1218 reset_off = 1; 1219 } 1220 1221 if (!has_xattrs) { 1222 *eofp = 1; 1223 return (0); 1224 } 1225 1226 *eofp = 0; 1227 if (reset_off) { 1228 uiop->uio_loffset = 0; 1229 } 1230 (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1231 error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags); 1232 VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL); 1233 VN_RELE(pvp); 1234 1235 return (error); 1236 } 1237 1238 /* ARGSUSED */ 1239 static void 1240 xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 1241 { 1242 gfs_file_t *fp; 1243 1244 fp = gfs_dir_inactive(vp); 1245 if (fp != NULL) { 1246 kmem_free(fp, fp->gfs_size); 1247 } 1248 } 1249 1250 static int 1251 xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 1252 caller_context_t *ct) 1253 { 1254 switch (cmd) { 1255 case _PC_XATTR_EXISTS: 1256 case _PC_SATTR_ENABLED: 1257 case _PC_SATTR_EXISTS: 1258 *valp = 0; 1259 return (0); 1260 default: 1261 return (fs_pathconf(vp, cmd, valp, cr, ct)); 1262 } 1263 } 1264 1265 static const fs_operation_def_t xattr_dir_tops[] = { 1266 { VOPNAME_OPEN, { .vop_open = xattr_dir_open } }, 1267 { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } }, 1268 { VOPNAME_IOCTL, { .error = fs_inval } }, 1269 { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } }, 1270 { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } }, 1271 { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } }, 1272 { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } }, 1273 { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } }, 1274 { VOPNAME_CREATE, { .vop_create = xattr_dir_create } }, 1275 { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } }, 1276 { VOPNAME_LINK, { .vop_link = xattr_dir_link } }, 1277 { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } }, 1278 { VOPNAME_MKDIR, { .error = fs_inval } }, 1279 { VOPNAME_SEEK, { .vop_seek = fs_seek } }, 1280 { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } }, 1281 { VOPNAME_FID, { .vop_fid = xattr_common_fid } }, 1282 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } }, 1283 { NULL, NULL } 1284 }; 1285 1286 static gfs_opsvec_t xattr_opsvec[] = { 1287 { "xattr dir", xattr_dir_tops, &xattr_dir_ops }, 1288 { "system attributes", xattr_file_tops, &xattr_file_ops }, 1289 { NULL, NULL, NULL } 1290 }; 1291 1292 static int 1293 xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop, 1294 cred_t *cr) 1295 { 1296 vnode_t *pvp; 1297 struct pathname pn; 1298 int error; 1299 1300 *vpp = NULL; 1301 *inop = 0; 1302 1303 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR, 1304 cr, NULL); 1305 1306 /* 1307 * Return ENOENT for EACCES requests during lookup. Once an 1308 * attribute create is attempted EACCES will be returned. 1309 */ 1310 if (error) { 1311 if (error == EACCES) 1312 return (ENOENT); 1313 return (error); 1314 } 1315 1316 error = pn_get((char *)nm, UIO_SYSSPACE, &pn); 1317 if (error == 0) { 1318 error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, 0, rootvp, 1319 cr, NULL, NULL, NULL); 1320 pn_free(&pn); 1321 } 1322 VN_RELE(pvp); 1323 1324 return (error); 1325 } 1326 1327 /* ARGSUSED */ 1328 static ino64_t 1329 xattrdir_do_ino(vnode_t *vp, int index) 1330 { 1331 /* 1332 * We use index 0 for the directory fid. Start 1333 * the file numbering at 1. 1334 */ 1335 return ((ino64_t)index+1); 1336 } 1337 1338 void 1339 xattr_init(void) 1340 { 1341 VERIFY(gfs_make_opsvec(xattr_opsvec) == 0); 1342 } 1343 1344 int 1345 xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr) 1346 { 1347 int error = 0; 1348 1349 *vpp = NULL; 1350 1351 if (dvp->v_type != VDIR && dvp->v_type != VREG) 1352 return (EINVAL); 1353 1354 mutex_enter(&dvp->v_lock); 1355 1356 /* 1357 * If we're already in sysattr space, don't allow creation 1358 * of another level of sysattrs. 1359 */ 1360 if (dvp->v_flag & V_SYSATTR) { 1361 mutex_exit(&dvp->v_lock); 1362 return (EINVAL); 1363 } 1364 1365 if (dvp->v_xattrdir != NULL) { 1366 *vpp = dvp->v_xattrdir; 1367 VN_HOLD(*vpp); 1368 } else { 1369 ulong_t val; 1370 int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR; 1371 int sysattrs_allowed = 1; 1372 1373 /* 1374 * We have to drop the lock on dvp. gfs_dir_create will 1375 * grab it for a VN_HOLD. 1376 */ 1377 mutex_exit(&dvp->v_lock); 1378 1379 /* 1380 * If dvp allows xattr creation, but not sysattr 1381 * creation, return the real xattr dir vp. We can't 1382 * use the vfs feature mask here because _PC_SATTR_ENABLED 1383 * has vnode-level granularity (e.g. .zfs). 1384 */ 1385 error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL); 1386 if (error != 0 || val == 0) 1387 sysattrs_allowed = 0; 1388 1389 if (!xattrs_allowed && !sysattrs_allowed) 1390 return (EINVAL); 1391 1392 if (!sysattrs_allowed) { 1393 struct pathname pn; 1394 char *nm = ""; 1395 1396 error = pn_get(nm, UIO_SYSSPACE, &pn); 1397 if (error) 1398 return (error); 1399 error = VOP_LOOKUP(dvp, nm, vpp, &pn, 1400 flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL, 1401 NULL, NULL); 1402 pn_free(&pn); 1403 return (error); 1404 } 1405 1406 /* 1407 * Note that we act as if we were given CREATE_XATTR_DIR, 1408 * but only for creation of the GFS directory. 1409 */ 1410 *vpp = gfs_dir_create( 1411 sizeof (gfs_dir_t), dvp, xattr_dir_ops, xattr_dirents, 1412 xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb); 1413 mutex_enter(&dvp->v_lock); 1414 if (dvp->v_xattrdir != NULL) { 1415 /* 1416 * We lost the race to create the xattr dir. 1417 * Destroy this one, use the winner. We can't 1418 * just call VN_RELE(*vpp), because the vnode 1419 * is only partially initialized. 1420 */ 1421 gfs_dir_t *dp = (*vpp)->v_data; 1422 1423 ASSERT((*vpp)->v_count == 1); 1424 vn_free(*vpp); 1425 1426 mutex_destroy(&dp->gfsd_lock); 1427 kmem_free(dp->gfsd_static, 1428 dp->gfsd_nstatic * sizeof (gfs_dirent_t)); 1429 kmem_free(dp, dp->gfsd_file.gfs_size); 1430 1431 /* 1432 * There is an implied VN_HOLD(dvp) here. We should 1433 * be doing a VN_RELE(dvp) to clean up the reference 1434 * from *vpp, and then a VN_HOLD(dvp) for the new 1435 * reference. Instead, we just leave the count alone. 1436 */ 1437 1438 *vpp = dvp->v_xattrdir; 1439 VN_HOLD(*vpp); 1440 } else { 1441 (*vpp)->v_flag |= (V_XATTRDIR|V_SYSATTR); 1442 dvp->v_xattrdir = *vpp; 1443 } 1444 } 1445 mutex_exit(&dvp->v_lock); 1446 1447 return (error); 1448 } 1449 1450 int 1451 xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) 1452 { 1453 int error; 1454 vnode_t *pvp, *dvp; 1455 xattr_fid_t *xfidp; 1456 struct pathname pn; 1457 char *nm; 1458 uint16_t orig_len; 1459 1460 *vpp = NULL; 1461 1462 if (fidp->fid_len < XATTR_FIDSZ) 1463 return (EINVAL); 1464 1465 xfidp = (xattr_fid_t *)fidp; 1466 orig_len = fidp->fid_len; 1467 fidp->fid_len = xfidp->parent_len; 1468 1469 error = VFS_VGET(vfsp, &pvp, fidp); 1470 fidp->fid_len = orig_len; 1471 if (error) 1472 return (error); 1473 1474 /* 1475 * Start by getting the GFS sysattr directory. We might need 1476 * to recreate it during the VOP_LOOKUP. 1477 */ 1478 nm = ""; 1479 error = pn_get(nm, UIO_SYSSPACE, &pn); 1480 if (error) { 1481 VN_RELE(pvp); 1482 return (EINVAL); 1483 } 1484 1485 error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR, 1486 rootvp, CRED(), NULL, NULL, NULL); 1487 pn_free(&pn); 1488 VN_RELE(pvp); 1489 if (error) 1490 return (error); 1491 1492 if (xfidp->dir_offset == 0) { 1493 /* 1494 * If we were looking for the directory, we're done. 1495 */ 1496 *vpp = dvp; 1497 return (0); 1498 } 1499 1500 if (xfidp->dir_offset > XATTRDIR_NENTS) { 1501 VN_RELE(dvp); 1502 return (EINVAL); 1503 } 1504 1505 nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name; 1506 1507 error = pn_get(nm, UIO_SYSSPACE, &pn); 1508 if (error) { 1509 VN_RELE(dvp); 1510 return (EINVAL); 1511 } 1512 1513 error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL, 1514 NULL, NULL); 1515 1516 pn_free(&pn); 1517 VN_RELE(dvp); 1518 1519 return (error); 1520 } 1521