xref: /titanic_52/usr/src/uts/common/fs/xattr.c (revision 3b133bec939f5230f040960ee1503dadd3dff343)
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