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