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 2008 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	gfs_private;
     53 	xattr_view_t	xattr_view;
     54 } xattr_file_t;
     55 
     56 /* ARGSUSED */
     57 static int
     58 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
     59 {
     60 	xattr_file_t *np = (*vpp)->v_data;
     61 
     62 	if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
     63 		return (EACCES);
     64 
     65 	return (0);
     66 }
     67 
     68 /* ARGSUSED */
     69 static int
     70 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
     71     caller_context_t *ct)
     72 {
     73 	xattr_file_t *np = vp->v_data;
     74 
     75 	if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))
     76 		return (EACCES);
     77 
     78 	return (0);
     79 }
     80 
     81 /* ARGSUSED */
     82 static int
     83 xattr_file_close(vnode_t *vp, int flags, int count, offset_t off,
     84     cred_t *cr, caller_context_t *ct)
     85 {
     86 	cleanlocks(vp, ddi_get_pid(), 0);
     87 	cleanshares(vp, ddi_get_pid());
     88 	return (0);
     89 }
     90 
     91 static int
     92 xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
     93 {
     94 	xattr_fid_t	*xfidp;
     95 	vnode_t		*pvp, *savevp;
     96 	int		error;
     97 	uint16_t	orig_len;
     98 
     99 	if (fidp->fid_len < XATTR_FIDSZ) {
    100 		fidp->fid_len = XATTR_FIDSZ;
    101 		return (ENOSPC);
    102 	}
    103 
    104 	savevp = pvp = gfs_file_parent(vp);
    105 	mutex_enter(&savevp->v_lock);
    106 	if (pvp->v_flag & V_XATTRDIR) {
    107 		pvp = gfs_file_parent(pvp);
    108 	}
    109 	mutex_exit(&savevp->v_lock);
    110 
    111 	xfidp = (xattr_fid_t *)fidp;
    112 	orig_len = fidp->fid_len;
    113 	fidp->fid_len = sizeof (xfidp->parent_fid);
    114 
    115 	error = VOP_FID(pvp, fidp, ct);
    116 	if (error) {
    117 		fidp->fid_len = orig_len;
    118 		return (error);
    119 	}
    120 
    121 	xfidp->parent_len = fidp->fid_len;
    122 	fidp->fid_len = XATTR_FIDSZ;
    123 	xfidp->dir_offset = gfs_file_inode(vp);
    124 
    125 	return (0);
    126 }
    127 
    128 /* ARGSUSED */
    129 static int
    130 xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
    131     cred_t *cr, caller_context_t *ct)
    132 {
    133 	int error;
    134 	f_attr_t attr;
    135 	uint64_t fsid;
    136 	xvattr_t xvattr;
    137 	xoptattr_t *xoap;	/* Pointer to optional attributes */
    138 	vnode_t *ppvp;
    139 	const char *domain;
    140 	uint32_t rid;
    141 
    142 	xva_init(&xvattr);
    143 
    144 	if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
    145 		return (EINVAL);
    146 
    147 	/*
    148 	 * For detecting ephemeral uid/gid
    149 	 */
    150 	xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID);
    151 
    152 	/*
    153 	 * We need to access the real fs object.
    154 	 * vp points to a GFS file; ppvp points to the real object.
    155 	 */
    156 	ppvp = gfs_file_parent(gfs_file_parent(vp));
    157 
    158 	/*
    159 	 * Iterate through the attrs associated with this view
    160 	 */
    161 
    162 	for (attr = 0; attr < F_ATTR_ALL; attr++) {
    163 		if (xattr_view != attr_to_xattr_view(attr)) {
    164 			continue;
    165 		}
    166 
    167 		switch (attr) {
    168 		case F_SYSTEM:
    169 			XVA_SET_REQ(&xvattr, XAT_SYSTEM);
    170 			break;
    171 		case F_READONLY:
    172 			XVA_SET_REQ(&xvattr, XAT_READONLY);
    173 			break;
    174 		case F_HIDDEN:
    175 			XVA_SET_REQ(&xvattr, XAT_HIDDEN);
    176 			break;
    177 		case F_ARCHIVE:
    178 			XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
    179 			break;
    180 		case F_IMMUTABLE:
    181 			XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
    182 			break;
    183 		case F_APPENDONLY:
    184 			XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
    185 			break;
    186 		case F_NOUNLINK:
    187 			XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
    188 			break;
    189 		case F_OPAQUE:
    190 			XVA_SET_REQ(&xvattr, XAT_OPAQUE);
    191 			break;
    192 		case F_NODUMP:
    193 			XVA_SET_REQ(&xvattr, XAT_NODUMP);
    194 			break;
    195 		case F_AV_QUARANTINED:
    196 			XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
    197 			break;
    198 		case F_AV_MODIFIED:
    199 			XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
    200 			break;
    201 		case F_AV_SCANSTAMP:
    202 			if (ppvp->v_type == VREG)
    203 				XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
    204 			break;
    205 		case F_CRTIME:
    206 			XVA_SET_REQ(&xvattr, XAT_CREATETIME);
    207 			break;
    208 		case F_FSID:
    209 			fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) |
    210 			    (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] &
    211 			    0xffffffff));
    212 			VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
    213 			    fsid) == 0);
    214 			break;
    215 		default:
    216 			break;
    217 		}
    218 	}
    219 
    220 	error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
    221 	if (error)
    222 		return (error);
    223 
    224 	/*
    225 	 * Process all the optional attributes together here.  Notice that
    226 	 * xoap was set when the optional attribute bits were set above.
    227 	 */
    228 	if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) {
    229 		if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) {
    230 			VERIFY(nvlist_add_boolean_value(nvlp,
    231 			    attr_to_name(F_READONLY),
    232 			    xoap->xoa_readonly) == 0);
    233 		}
    234 		if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) {
    235 			VERIFY(nvlist_add_boolean_value(nvlp,
    236 			    attr_to_name(F_HIDDEN),
    237 			    xoap->xoa_hidden) == 0);
    238 		}
    239 		if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) {
    240 			VERIFY(nvlist_add_boolean_value(nvlp,
    241 			    attr_to_name(F_SYSTEM),
    242 			    xoap->xoa_system) == 0);
    243 		}
    244 		if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) {
    245 			VERIFY(nvlist_add_boolean_value(nvlp,
    246 			    attr_to_name(F_ARCHIVE),
    247 			    xoap->xoa_archive) == 0);
    248 		}
    249 		if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) {
    250 			VERIFY(nvlist_add_boolean_value(nvlp,
    251 			    attr_to_name(F_IMMUTABLE),
    252 			    xoap->xoa_immutable) == 0);
    253 		}
    254 		if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) {
    255 			VERIFY(nvlist_add_boolean_value(nvlp,
    256 			    attr_to_name(F_NOUNLINK),
    257 			    xoap->xoa_nounlink) == 0);
    258 		}
    259 		if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) {
    260 			VERIFY(nvlist_add_boolean_value(nvlp,
    261 			    attr_to_name(F_APPENDONLY),
    262 			    xoap->xoa_appendonly) == 0);
    263 		}
    264 		if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) {
    265 			VERIFY(nvlist_add_boolean_value(nvlp,
    266 			    attr_to_name(F_NODUMP),
    267 			    xoap->xoa_nodump) == 0);
    268 		}
    269 		if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) {
    270 			VERIFY(nvlist_add_boolean_value(nvlp,
    271 			    attr_to_name(F_OPAQUE),
    272 			    xoap->xoa_opaque) == 0);
    273 		}
    274 		if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) {
    275 			VERIFY(nvlist_add_boolean_value(nvlp,
    276 			    attr_to_name(F_AV_QUARANTINED),
    277 			    xoap->xoa_av_quarantined) == 0);
    278 		}
    279 		if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) {
    280 			VERIFY(nvlist_add_boolean_value(nvlp,
    281 			    attr_to_name(F_AV_MODIFIED),
    282 			    xoap->xoa_av_modified) == 0);
    283 		}
    284 		if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) {
    285 			VERIFY(nvlist_add_uint8_array(nvlp,
    286 			    attr_to_name(F_AV_SCANSTAMP),
    287 			    xoap->xoa_av_scanstamp,
    288 			    sizeof (xoap->xoa_av_scanstamp)) == 0);
    289 		}
    290 		if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) {
    291 			VERIFY(nvlist_add_uint64_array(nvlp,
    292 			    attr_to_name(F_CRTIME),
    293 			    (uint64_t *)&(xoap->xoa_createtime),
    294 			    sizeof (xoap->xoa_createtime) /
    295 			    sizeof (uint64_t)) == 0);
    296 		}
    297 	}
    298 	/*
    299 	 * Check for optional ownersid/groupsid
    300 	 */
    301 
    302 	if (xvattr.xva_vattr.va_uid > MAXUID) {
    303 		nvlist_t *nvl_sid;
    304 
    305 		if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
    306 			return (ENOMEM);
    307 
    308 		if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid,
    309 		    &domain, &rid) == 0) {
    310 			VERIFY(nvlist_add_string(nvl_sid,
    311 			    SID_DOMAIN, domain) == 0);
    312 			VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
    313 			VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
    314 			    nvl_sid) == 0);
    315 		}
    316 		nvlist_free(nvl_sid);
    317 	}
    318 	if (xvattr.xva_vattr.va_gid > MAXUID) {
    319 		nvlist_t *nvl_sid;
    320 
    321 		if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
    322 			return (ENOMEM);
    323 
    324 		if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid,
    325 		    &domain, &rid) == 0) {
    326 			VERIFY(nvlist_add_string(nvl_sid,
    327 			    SID_DOMAIN, domain) == 0);
    328 			VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
    329 			VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
    330 			    nvl_sid) == 0);
    331 		}
    332 		nvlist_free(nvl_sid);
    333 	}
    334 
    335 	return (0);
    336 }
    337 
    338 /*
    339  * The size of a sysattr file is the size of the nvlist that will be
    340  * returned by xattr_file_read().  A call to xattr_file_write() could
    341  * change the size of that nvlist.  That size is not stored persistently
    342  * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
    343  */
    344 static int
    345 xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size,
    346     cred_t *cr, caller_context_t *ct)
    347 {
    348 	nvlist_t *nvl;
    349 
    350 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) {
    351 		return (ENOMEM);
    352 	}
    353 
    354 	if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
    355 		nvlist_free(nvl);
    356 		return (EFAULT);
    357 	}
    358 
    359 	VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0);
    360 	nvlist_free(nvl);
    361 	return (0);
    362 }
    363 
    364 /* ARGSUSED */
    365 static int
    366 xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
    367     caller_context_t *ct)
    368 {
    369 	xattr_file_t *np = vp->v_data;
    370 	timestruc_t now;
    371 	size_t size;
    372 	int error;
    373 	vnode_t *pvp;
    374 	vattr_t pvattr;
    375 
    376 	vap->va_type = VREG;
    377 	vap->va_mode = MAKEIMODE(vap->va_type,
    378 	    (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644));
    379 	vap->va_nodeid = gfs_file_inode(vp);
    380 	vap->va_nlink = 1;
    381 	pvp = gfs_file_parent(vp);
    382 	(void) memset(&pvattr, 0, sizeof (pvattr));
    383 	pvattr.va_mask = AT_CTIME|AT_MTIME;
    384 	error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct);
    385 	if (error) {
    386 		return (error);
    387 	}
    388 	vap->va_ctime = pvattr.va_ctime;
    389 	vap->va_mtime = pvattr.va_mtime;
    390 	gethrestime(&now);
    391 	vap->va_atime = now;
    392 	vap->va_uid = 0;
    393 	vap->va_gid = 0;
    394 	vap->va_rdev = 0;
    395 	vap->va_blksize = DEV_BSIZE;
    396 	vap->va_seq = 0;
    397 	vap->va_fsid = vp->v_vfsp->vfs_dev;
    398 	error = xattr_file_size(vp, np->xattr_view, &size, cr, ct);
    399 	vap->va_size = size;
    400 	vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
    401 	return (error);
    402 }
    403 
    404 /* ARGSUSED */
    405 static int
    406 xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    407     caller_context_t *ct)
    408 {
    409 	xattr_file_t *np = vp->v_data;
    410 	xattr_view_t xattr_view = np->xattr_view;
    411 	char *buf;
    412 	size_t filesize;
    413 	nvlist_t *nvl;
    414 	int error;
    415 
    416 	/*
    417 	 * Validate file offset and fasttrack empty reads
    418 	 */
    419 	if (uiop->uio_loffset < (offset_t)0)
    420 		return (EINVAL);
    421 
    422 	if (uiop->uio_resid == 0)
    423 		return (0);
    424 
    425 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP))
    426 		return (ENOMEM);
    427 
    428 	if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
    429 		nvlist_free(nvl);
    430 		return (EFAULT);
    431 	}
    432 
    433 	VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0);
    434 
    435 	if (uiop->uio_loffset >= filesize) {
    436 		nvlist_free(nvl);
    437 		return (0);
    438 	}
    439 
    440 	buf = kmem_alloc(filesize, KM_SLEEP);
    441 	VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR,
    442 	    KM_SLEEP) == 0);
    443 
    444 	error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop);
    445 	kmem_free(buf, filesize);
    446 	nvlist_free(nvl);
    447 	return (error);
    448 }
    449 
    450 /* ARGSUSED */
    451 static int
    452 xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    453     caller_context_t *ct)
    454 {
    455 	int error = 0;
    456 	char *buf;
    457 	char *domain;
    458 	uint32_t rid;
    459 	ssize_t size = uiop->uio_resid;
    460 	nvlist_t *nvp;
    461 	nvpair_t *pair = NULL;
    462 	vnode_t *ppvp;
    463 	xvattr_t xvattr;
    464 	xoptattr_t *xoap = NULL;	/* Pointer to optional attributes */
    465 
    466 	if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0)
    467 		return (EINVAL);
    468 
    469 	/*
    470 	 * Validate file offset and size.
    471 	 */
    472 	if (uiop->uio_loffset < (offset_t)0)
    473 		return (EINVAL);
    474 
    475 	if (size == 0)
    476 		return (EINVAL);
    477 
    478 	xva_init(&xvattr);
    479 
    480 	if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
    481 		return (EINVAL);
    482 	}
    483 
    484 	/*
    485 	 * Copy and unpack the nvlist
    486 	 */
    487 	buf = kmem_alloc(size, KM_SLEEP);
    488 	if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
    489 		return (EFAULT);
    490 	}
    491 
    492 	if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
    493 		kmem_free(buf, size);
    494 		uiop->uio_resid = size;
    495 		return (EINVAL);
    496 	}
    497 	kmem_free(buf, size);
    498 
    499 	/*
    500 	 * Fasttrack empty writes (nvlist with no nvpairs)
    501 	 */
    502 	if (nvlist_next_nvpair(nvp, NULL) == 0)
    503 		return (0);
    504 
    505 	ppvp = gfs_file_parent(gfs_file_parent(vp));
    506 
    507 	while (pair = nvlist_next_nvpair(nvp, pair)) {
    508 		data_type_t type;
    509 		f_attr_t attr;
    510 		boolean_t value;
    511 		uint64_t *time, *times;
    512 		uint_t elem, nelems;
    513 		nvlist_t *nvp_sid;
    514 		uint8_t *scanstamp;
    515 
    516 		/*
    517 		 * Validate the name and type of each attribute.
    518 		 * Log any unknown names and continue.  This will
    519 		 * help if additional attributes are added later.
    520 		 */
    521 		type = nvpair_type(pair);
    522 		if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
    523 			cmn_err(CE_WARN, "Unknown attribute %s",
    524 			    nvpair_name(pair));
    525 			continue;
    526 		}
    527 
    528 		/*
    529 		 * Verify nvlist type matches required type and view is OK
    530 		 */
    531 
    532 		if (type != attr_to_data_type(attr) ||
    533 		    (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
    534 			nvlist_free(nvp);
    535 			return (EINVAL);
    536 		}
    537 
    538 		/*
    539 		 * For OWNERSID/GROUPSID make sure the target
    540 		 * file system support ephemeral ID's
    541 		 */
    542 		if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
    543 		    (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
    544 			nvlist_free(nvp);
    545 			return (EINVAL);
    546 		}
    547 
    548 		/*
    549 		 * Retrieve data from nvpair
    550 		 */
    551 		switch (type) {
    552 		case DATA_TYPE_BOOLEAN_VALUE:
    553 			if (nvpair_value_boolean_value(pair, &value)) {
    554 				nvlist_free(nvp);
    555 				return (EINVAL);
    556 			}
    557 			break;
    558 		case DATA_TYPE_UINT64_ARRAY:
    559 			if (nvpair_value_uint64_array(pair, &times, &nelems)) {
    560 				nvlist_free(nvp);
    561 				return (EINVAL);
    562 			}
    563 			break;
    564 		case DATA_TYPE_NVLIST:
    565 			if (nvpair_value_nvlist(pair, &nvp_sid)) {
    566 				nvlist_free(nvp);
    567 				return (EINVAL);
    568 			}
    569 			break;
    570 		case DATA_TYPE_UINT8_ARRAY:
    571 			if (nvpair_value_uint8_array(pair,
    572 			    &scanstamp, &nelems)) {
    573 				nvlist_free(nvp);
    574 				return (EINVAL);
    575 			}
    576 			break;
    577 		default:
    578 			nvlist_free(nvp);
    579 			return (EINVAL);
    580 		}
    581 
    582 		switch (attr) {
    583 		/*
    584 		 * If we have several similar optional attributes to
    585 		 * process then we should do it all together here so that
    586 		 * xoap and the requested bitmap can be set in one place.
    587 		 */
    588 		case F_READONLY:
    589 			XVA_SET_REQ(&xvattr, XAT_READONLY);
    590 			xoap->xoa_readonly = value;
    591 			break;
    592 		case F_HIDDEN:
    593 			XVA_SET_REQ(&xvattr, XAT_HIDDEN);
    594 			xoap->xoa_hidden = value;
    595 			break;
    596 		case F_SYSTEM:
    597 			XVA_SET_REQ(&xvattr, XAT_SYSTEM);
    598 			xoap->xoa_system = value;
    599 			break;
    600 		case F_ARCHIVE:
    601 			XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
    602 			xoap->xoa_archive = value;
    603 			break;
    604 		case F_IMMUTABLE:
    605 			XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
    606 			xoap->xoa_immutable = value;
    607 			break;
    608 		case F_NOUNLINK:
    609 			XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
    610 			xoap->xoa_nounlink = value;
    611 			break;
    612 		case F_APPENDONLY:
    613 			XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
    614 			xoap->xoa_appendonly = value;
    615 			break;
    616 		case F_NODUMP:
    617 			XVA_SET_REQ(&xvattr, XAT_NODUMP);
    618 			xoap->xoa_nodump = value;
    619 			break;
    620 		case F_AV_QUARANTINED:
    621 			XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
    622 			xoap->xoa_av_quarantined = value;
    623 			break;
    624 		case F_AV_MODIFIED:
    625 			XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
    626 			xoap->xoa_av_modified = value;
    627 			break;
    628 		case F_CRTIME:
    629 			XVA_SET_REQ(&xvattr, XAT_CREATETIME);
    630 			time = (uint64_t *)&(xoap->xoa_createtime);
    631 			for (elem = 0; elem < nelems; elem++)
    632 				*time++ = times[elem];
    633 			break;
    634 		case F_OWNERSID:
    635 		case F_GROUPSID:
    636 			if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
    637 			    &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
    638 			    &rid)) {
    639 				nvlist_free(nvp);
    640 				return (EINVAL);
    641 			}
    642 
    643 			/*
    644 			 * Now map domain+rid to ephemeral id's
    645 			 *
    646 			 * If mapping fails, then the uid/gid will
    647 			 * be set to UID_NOBODY by Winchester.
    648 			 */
    649 
    650 			if (attr == F_OWNERSID) {
    651 				(void) kidmap_getuidbysid(crgetzone(cr), domain,
    652 				    rid, &xvattr.xva_vattr.va_uid);
    653 				xvattr.xva_vattr.va_mask |= AT_UID;
    654 			} else {
    655 				(void) kidmap_getgidbysid(crgetzone(cr), domain,
    656 				    rid, &xvattr.xva_vattr.va_gid);
    657 				xvattr.xva_vattr.va_mask |= AT_GID;
    658 			}
    659 			break;
    660 		case F_AV_SCANSTAMP:
    661 			if (ppvp->v_type == VREG) {
    662 				XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
    663 				(void) memcpy(xoap->xoa_av_scanstamp,
    664 				    scanstamp, nelems);
    665 			} else {
    666 				nvlist_free(nvp);
    667 				return (EINVAL);
    668 			}
    669 			break;
    670 		default:
    671 			break;
    672 		}
    673 	}
    674 
    675 	ppvp = gfs_file_parent(gfs_file_parent(vp));
    676 	error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
    677 	if (error)
    678 		uiop->uio_resid = size;
    679 
    680 	nvlist_free(nvp);
    681 	return (error);
    682 }
    683 
    684 static int
    685 xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
    686     caller_context_t *ct)
    687 {
    688 	switch (cmd) {
    689 	case _PC_XATTR_EXISTS:
    690 	case _PC_SATTR_ENABLED:
    691 	case _PC_SATTR_EXISTS:
    692 		*valp = 0;
    693 		return (0);
    694 	default:
    695 		return (fs_pathconf(vp, cmd, valp, cr, ct));
    696 	}
    697 }
    698 
    699 vnodeops_t *xattr_file_ops;
    700 
    701 static const fs_operation_def_t xattr_file_tops[] = {
    702 	{ VOPNAME_OPEN,		{ .vop_open = xattr_file_open }		},
    703 	{ VOPNAME_CLOSE,	{ .vop_close = xattr_file_close }	},
    704 	{ VOPNAME_READ,		{ .vop_read = xattr_file_read }		},
    705 	{ VOPNAME_WRITE,	{ .vop_write = xattr_file_write }	},
    706 	{ VOPNAME_IOCTL,	{ .error = fs_ioctl }			},
    707 	{ VOPNAME_GETATTR,	{ .vop_getattr = xattr_file_getattr }	},
    708 	{ VOPNAME_ACCESS,	{ .vop_access = xattr_file_access }	},
    709 	{ VOPNAME_READDIR,	{ .error = fs_notdir }			},
    710 	{ VOPNAME_SEEK,		{ .vop_seek = fs_seek }			},
    711 	{ VOPNAME_INACTIVE,	{ .vop_inactive = gfs_vop_inactive }	},
    712 	{ VOPNAME_FID,		{ .vop_fid = xattr_common_fid }		},
    713 	{ VOPNAME_PATHCONF,	{ .vop_pathconf = xattr_file_pathconf }	},
    714 	{ VOPNAME_PUTPAGE,	{ .error = fs_putpage }			},
    715 	{ VOPNAME_FSYNC,	{ .error = fs_fsync }			},
    716 	{ NULL }
    717 };
    718 
    719 vnode_t *
    720 xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view)
    721 {
    722 	vnode_t *vp;
    723 	xattr_file_t *np;
    724 
    725 	vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops);
    726 	np = vp->v_data;
    727 	np->xattr_view = xattr_view;
    728 	vp->v_flag |= V_SYSATTR;
    729 	return (vp);
    730 }
    731 
    732 vnode_t *
    733 xattr_mkfile_ro(vnode_t *pvp)
    734 {
    735 	return (xattr_mkfile(pvp, XATTR_VIEW_READONLY));
    736 }
    737 
    738 vnode_t *
    739 xattr_mkfile_rw(vnode_t *pvp)
    740 {
    741 	return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE));
    742 }
    743 
    744 vnodeops_t *xattr_dir_ops;
    745 
    746 static gfs_dirent_t xattr_dirents[] = {
    747 	{ VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, },
    748 	{ VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, },
    749 	{ NULL },
    750 };
    751 
    752 #define	XATTRDIR_NENTS	((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
    753 
    754 static int
    755 is_sattr_name(char *s)
    756 {
    757 	int i;
    758 
    759 	for (i = 0; i < XATTRDIR_NENTS; ++i) {
    760 		if (strcmp(s, xattr_dirents[i].gfse_name) == 0) {
    761 			return (1);
    762 		}
    763 	}
    764 	return (0);
    765 }
    766 
    767 /*
    768  * Given the name of an extended attribute file, determine if there is a
    769  * normalization conflict with a sysattr view name.
    770  */
    771 int
    772 xattr_sysattr_casechk(char *s)
    773 {
    774 	int i;
    775 
    776 	for (i = 0; i < XATTRDIR_NENTS; ++i) {
    777 		if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0)
    778 			return (1);
    779 	}
    780 	return (0);
    781 }
    782 
    783 static int
    784 xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
    785     cred_t *cr, caller_context_t *ct)
    786 {
    787 	xvattr_t xvattr;
    788 	vnode_t *pdvp;
    789 	int error;
    790 
    791 	/*
    792 	 * Only copy system attrs if the views are the same
    793 	 */
    794 	if (strcmp(snm, tnm) != 0)
    795 		return (EINVAL);
    796 
    797 	xva_init(&xvattr);
    798 
    799 	XVA_SET_REQ(&xvattr, XAT_SYSTEM);
    800 	XVA_SET_REQ(&xvattr, XAT_READONLY);
    801 	XVA_SET_REQ(&xvattr, XAT_HIDDEN);
    802 	XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
    803 	XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
    804 	XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
    805 	XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
    806 	XVA_SET_REQ(&xvattr, XAT_NODUMP);
    807 	XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
    808 	XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
    809 	XVA_SET_REQ(&xvattr, XAT_CREATETIME);
    810 
    811 	pdvp = gfs_file_parent(sdvp);
    812 	error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
    813 	if (error)
    814 		return (error);
    815 
    816 	pdvp = gfs_file_parent(tdvp);
    817 	error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
    818 	return (error);
    819 }
    820 
    821 static int
    822 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
    823     cred_t *cr, caller_context_t *ct)
    824 {
    825 	vnode_t *pvp;
    826 	int error;
    827 	struct pathname pn;
    828 	char *startnm = "";
    829 
    830 	*realdvp = NULL;
    831 
    832 	pvp = gfs_file_parent(dvp);
    833 
    834 	error = pn_get(startnm, UIO_SYSSPACE, &pn);
    835 	if (error) {
    836 		VN_RELE(pvp);
    837 		return (error);
    838 	}
    839 
    840 	/*
    841 	 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
    842 	 * infinite loop with fop_lookup calling back to xattr_dir_lookup.
    843 	 */
    844 	lookup_flags |= LOOKUP_HAVE_SYSATTR_DIR;
    845 	error = VOP_LOOKUP(pvp, startnm, realdvp, &pn, lookup_flags,
    846 	    rootvp, cr, ct, NULL, NULL);
    847 	pn_free(&pn);
    848 
    849 	return (error);
    850 }
    851 
    852 /* ARGSUSED */
    853 static int
    854 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
    855 {
    856 	if (flags & FWRITE) {
    857 		return (EACCES);
    858 	}
    859 
    860 	return (0);
    861 }
    862 
    863 /* ARGSUSED */
    864 static int
    865 xattr_dir_close(vnode_t *vpp, int flags, int count, offset_t off, cred_t *cr,
    866     caller_context_t *ct)
    867 {
    868 	return (0);
    869 }
    870 
    871 /* ARGSUSED */
    872 static int
    873 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
    874     caller_context_t *ct)
    875 {
    876 	timestruc_t now;
    877 	vnode_t *pvp;
    878 	int error;
    879 	vattr_t pvattr;
    880 
    881 	error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct);
    882 	if (error == 0) {
    883 		error = VOP_GETATTR(pvp, vap, 0, cr, ct);
    884 		VN_RELE(pvp);
    885 		if (error) {
    886 			return (error);
    887 		}
    888 		vap->va_nlink += XATTRDIR_NENTS;
    889 		vap->va_size += XATTRDIR_NENTS;
    890 		return (0);
    891 	}
    892 
    893 	/*
    894 	 * There is no real xattr directory.  Cobble together
    895 	 * an entry using info from the parent object.
    896 	 */
    897 	pvp = gfs_file_parent(vp);
    898 	(void) memset(&pvattr, 0, sizeof (pvattr));
    899 	pvattr.va_mask = AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME;
    900 	error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct);
    901 	if (error) {
    902 		return (error);
    903 	}
    904 	*vap = pvattr;
    905 	vap->va_type = VDIR;
    906 	vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777);
    907 	vap->va_fsid = vp->v_vfsp->vfs_dev;
    908 	vap->va_nodeid = gfs_file_inode(vp);
    909 	vap->va_nlink = XATTRDIR_NENTS+2;
    910 	vap->va_size = vap->va_nlink;
    911 	gethrestime(&now);
    912 	vap->va_atime = now;
    913 	vap->va_blksize = 0;
    914 	vap->va_nblocks = 0;
    915 	vap->va_seq = 0;
    916 	return (0);
    917 }
    918 
    919 static int
    920 xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
    921     caller_context_t *ct)
    922 {
    923 	vnode_t *realvp;
    924 	int error;
    925 
    926 	/*
    927 	 * If there is a real xattr directory, do the setattr there.
    928 	 * Otherwise, just return success.  The GFS directory is transient,
    929 	 * and any setattr changes can disappear anyway.
    930 	 */
    931 	error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
    932 	if (error == 0) {
    933 		error = VOP_SETATTR(realvp, vap, flags, cr, ct);
    934 		VN_RELE(realvp);
    935 	}
    936 	if (error == ENOENT) {
    937 		error = 0;
    938 	}
    939 	return (error);
    940 }
    941 
    942 /* ARGSUSED */
    943 static int
    944 xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
    945     caller_context_t *ct)
    946 {
    947 	int error;
    948 	vnode_t *realvp = NULL;
    949 
    950 	if (mode & VWRITE) {
    951 		return (EACCES);
    952 	}
    953 
    954 	error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
    955 
    956 	if (realvp)
    957 		VN_RELE(realvp);
    958 
    959 	/*
    960 	 * No real xattr dir isn't an error
    961 	 * an error of EINVAL indicates attributes on attributes
    962 	 * are not supported.  In that case just allow access to the
    963 	 * transient directory.
    964 	 */
    965 	return ((error == ENOENT || error == EINVAL) ? 0 : error);
    966 }
    967 
    968 static int
    969 xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
    970     int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
    971     vsecattr_t *vsecp)
    972 {
    973 	vnode_t *pvp;
    974 	int error;
    975 
    976 	*vpp = NULL;
    977 
    978 	/*
    979 	 * Don't allow creation of extended attributes with sysattr names.
    980 	 */
    981 	if (is_sattr_name(name)) {
    982 		return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL));
    983 	}
    984 
    985 	error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
    986 	    cr, ct);
    987 	if (error == 0) {
    988 		error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
    989 		    ct, vsecp);
    990 		VN_RELE(pvp);
    991 	}
    992 	return (error);
    993 }
    994 
    995 static int
    996 xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
    997     int flags)
    998 {
    999 	vnode_t *pvp;
   1000 	int error;
   1001 
   1002 	if (is_sattr_name(name)) {
   1003 		return (EACCES);
   1004 	}
   1005 
   1006 	error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
   1007 	if (error == 0) {
   1008 		error = VOP_REMOVE(pvp, name, cr, ct, flags);
   1009 		VN_RELE(pvp);
   1010 	}
   1011 	return (error);
   1012 }
   1013 
   1014 static int
   1015 xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name,