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