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