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, &times, &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 }