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