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