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