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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
27 * Big Theory Statement for Extended Attribute (XATTR) directories
29 * The Solaris VFS layer presents extended file attributes using a special
30 * "XATTR" directory under files or directories that have extended file
31 * attributes. See fsattr(5) for background.
33 * This design avoids the need for a separate set of VFS or vnode functions
34 * for operating on XATTR objects. File system implementations that support
35 * XATTR instantiate a special XATTR directory using this module.
36 * Applications get to the XATTR directory by passing the LOOKUP_XATTR flag
37 * to fop_lookup. Once the XATTR directory is obtained, all other file
38 * system operations on extended attributes happen via the normal vnode
39 * functions, applied to the XATTR directory or its contents.
41 * The XATTR directories returned by fop_lookup (with LOOKUP_XATTR) are
42 * implemented differntly, depending on whether the file system supports
43 * "extended attributes" (XATTR), "system attributes" (SYSATTR), or both.
45 * When SYSATTR=true, XATTR=true:
46 * The XATTR directory is a "generic file system" (GFS) object
47 * that adds the special system attribute names (SUNWattr*) to
48 * the list of XATTR files presented by the underling FS.
49 * In this case, many operations are "passed through" to the
52 * When SYSATTR=true, XATTR=false:
53 * The XATTR directory is a "generic file system" (GFS) object,
54 * presenting only the system attribute names (SUNWattr*)
55 * In this case there's no lower-level FS, only the GFS object.
57 * When SYSATTR=false, XATTR=true:
58 * The XATTR directory is implemented by the file system code,
59 * and this module is not involved after xattr_dir_lookup()
60 * returns the XATTR dir from the underlying file system.
62 * When SYSATTR=false, XATTR=false:
63 * xattr_dir_lookup just returns EINVAL
65 * In the first two cases (where we have system attributes) this module
66 * implements what can be thought of as a "translucent" directory containing
67 * both the system attribute names (SUNWattr*) and whatever XATTR names may
68 * exist in the XATTR directory of the underlying file system, if any.
70 * This affects operations on the (GFS) XATTR directory as follows:
72 * readdir: Merges the SUNWattr* names with any contents from the
73 * underlying XATTR directory.
75 * rename: If "to" or "from" is a SUNWattr name, special handling,
76 * else pass through to the lower FS.
78 * link: If "from" is a SUNWattr name, disallow.
80 * create: If a SUNWattr name, disallow, else pass to lower FS.
83 * open,close: Just pass through to the XATTR dir in the lower FS.
85 * lookup: Lookup an XATTR file in either the (GFS) XATTR directory
86 * or the "real" XATTR directory of the underlying FS.
87 * Note for file systems the support SYSATTR but not XATTR,
88 * only the GFS XATTR directory will exist. When both exist,
89 * gfs_vop_lookup uses the xattr_lookup_cb callback function
90 * which passes the lookup call through to the "real" FS.
92 * Operations on the XATTR _files_ are simpler:
94 * If the file vnode came from lookup at the GFS level, the file is one of
95 * the special SUNWattr* vnodes, and it's vnode operations (xattr_file_tops)
96 * allow only what's appropriate on these "files".
98 * If the file vnode came from the underlying FS, all operations on that
99 * object are handled through the vnode operations set by that FS.
102 #include <sys/param.h>
103 #include <sys/isa_defs.h>
104 #include <sys/types.h>
105 #include <sys/sysmacros.h>
106 #include <sys/cred.h>
107 #include <sys/systm.h>
108 #include <sys/errno.h>
109 #include <sys/fcntl.h>
110 #include <sys/pathname.h>
111 #include <sys/stat.h>
114 #include <sys/file.h>
115 #include <sys/sunddi.h>
116 #include <sys/debug.h>
117 #include <sys/cmn_err.h>
118 #include <sys/vnode.h>
119 #include <sys/mode.h>
120 #include <sys/nvpair.h>
121 #include <sys/attr.h>
123 #include <sys/mutex.h>
124 #include <fs/fs_subr.h>
125 #include <sys/kidmap.h>
128 gfs_file_t xattr_gfs_private
;
129 xattr_view_t xattr_view
;
133 gfs_dir_t xattr_gfs_private
;
134 vnode_t
*xattr_realvp
;
139 xattr_file_open(vnode_t
**vpp
, int flags
, cred_t
*cr
, caller_context_t
*ct
)
141 xattr_file_t
*np
= (*vpp
)->v_data
;
143 if ((np
->xattr_view
== XATTR_VIEW_READONLY
) && (flags
& FWRITE
))
151 xattr_file_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
152 caller_context_t
*ct
)
154 xattr_file_t
*np
= vp
->v_data
;
156 if ((np
->xattr_view
== XATTR_VIEW_READONLY
) && (mode
& VWRITE
))
164 xattr_file_close(vnode_t
*vp
, int flags
, int count
, offset_t off
,
165 cred_t
*cr
, caller_context_t
*ct
)
167 cleanlocks(vp
, ddi_get_pid(), 0);
168 cleanshares(vp
, ddi_get_pid());
173 xattr_common_fid(vnode_t
*vp
, fid_t
*fidp
, caller_context_t
*ct
)
176 vnode_t
*pvp
, *savevp
;
180 if (fidp
->fid_len
< XATTR_FIDSZ
) {
181 fidp
->fid_len
= XATTR_FIDSZ
;
185 savevp
= pvp
= gfs_file_parent(vp
);
186 mutex_enter(&savevp
->v_lock
);
187 if (pvp
->v_flag
& V_XATTRDIR
) {
188 pvp
= gfs_file_parent(pvp
);
190 mutex_exit(&savevp
->v_lock
);
192 xfidp
= (xattr_fid_t
*)fidp
;
193 orig_len
= fidp
->fid_len
;
194 fidp
->fid_len
= sizeof (xfidp
->parent_fid
);
196 error
= VOP_FID(pvp
, fidp
, ct
);
198 fidp
->fid_len
= orig_len
;
202 xfidp
->parent_len
= fidp
->fid_len
;
203 fidp
->fid_len
= XATTR_FIDSZ
;
204 xfidp
->dir_offset
= gfs_file_inode(vp
);
211 xattr_fill_nvlist(vnode_t
*vp
, xattr_view_t xattr_view
, nvlist_t
*nvlp
,
212 cred_t
*cr
, caller_context_t
*ct
)
218 xoptattr_t
*xoap
; /* Pointer to optional attributes */
225 if ((xoap
= xva_getxoptattr(&xvattr
)) == NULL
)
229 * For detecting ephemeral uid/gid
231 xvattr
.xva_vattr
.va_mask
|= (AT_UID
|AT_GID
);
234 * We need to access the real fs object.
235 * vp points to a GFS file; ppvp points to the real object.
237 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
240 * Iterate through the attrs associated with this view
243 for (attr
= 0; attr
< F_ATTR_ALL
; attr
++) {
244 if (xattr_view
!= attr_to_xattr_view(attr
)) {
250 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
253 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
256 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
259 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
262 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
265 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
268 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
271 XVA_SET_REQ(&xvattr
, XAT_OPAQUE
);
274 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
276 case F_AV_QUARANTINED
:
277 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
280 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
283 if (ppvp
->v_type
== VREG
)
284 XVA_SET_REQ(&xvattr
, XAT_AV_SCANSTAMP
);
287 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
290 fsid
= (((uint64_t)vp
->v_vfsp
->vfs_fsid
.val
[0] << 32) |
291 (uint64_t)(vp
->v_vfsp
->vfs_fsid
.val
[1] &
293 VERIFY(nvlist_add_uint64(nvlp
, attr_to_name(attr
),
297 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
300 XVA_SET_REQ(&xvattr
, XAT_GEN
);
303 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
306 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
313 error
= VOP_GETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
318 * Process all the optional attributes together here. Notice that
319 * xoap was set when the optional attribute bits were set above.
321 if ((xvattr
.xva_vattr
.va_mask
& AT_XVATTR
) && xoap
) {
322 if (XVA_ISSET_RTN(&xvattr
, XAT_READONLY
)) {
323 VERIFY(nvlist_add_boolean_value(nvlp
,
324 attr_to_name(F_READONLY
),
325 xoap
->xoa_readonly
) == 0);
327 if (XVA_ISSET_RTN(&xvattr
, XAT_HIDDEN
)) {
328 VERIFY(nvlist_add_boolean_value(nvlp
,
329 attr_to_name(F_HIDDEN
),
330 xoap
->xoa_hidden
) == 0);
332 if (XVA_ISSET_RTN(&xvattr
, XAT_SYSTEM
)) {
333 VERIFY(nvlist_add_boolean_value(nvlp
,
334 attr_to_name(F_SYSTEM
),
335 xoap
->xoa_system
) == 0);
337 if (XVA_ISSET_RTN(&xvattr
, XAT_ARCHIVE
)) {
338 VERIFY(nvlist_add_boolean_value(nvlp
,
339 attr_to_name(F_ARCHIVE
),
340 xoap
->xoa_archive
) == 0);
342 if (XVA_ISSET_RTN(&xvattr
, XAT_IMMUTABLE
)) {
343 VERIFY(nvlist_add_boolean_value(nvlp
,
344 attr_to_name(F_IMMUTABLE
),
345 xoap
->xoa_immutable
) == 0);
347 if (XVA_ISSET_RTN(&xvattr
, XAT_NOUNLINK
)) {
348 VERIFY(nvlist_add_boolean_value(nvlp
,
349 attr_to_name(F_NOUNLINK
),
350 xoap
->xoa_nounlink
) == 0);
352 if (XVA_ISSET_RTN(&xvattr
, XAT_APPENDONLY
)) {
353 VERIFY(nvlist_add_boolean_value(nvlp
,
354 attr_to_name(F_APPENDONLY
),
355 xoap
->xoa_appendonly
) == 0);
357 if (XVA_ISSET_RTN(&xvattr
, XAT_NODUMP
)) {
358 VERIFY(nvlist_add_boolean_value(nvlp
,
359 attr_to_name(F_NODUMP
),
360 xoap
->xoa_nodump
) == 0);
362 if (XVA_ISSET_RTN(&xvattr
, XAT_OPAQUE
)) {
363 VERIFY(nvlist_add_boolean_value(nvlp
,
364 attr_to_name(F_OPAQUE
),
365 xoap
->xoa_opaque
) == 0);
367 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_QUARANTINED
)) {
368 VERIFY(nvlist_add_boolean_value(nvlp
,
369 attr_to_name(F_AV_QUARANTINED
),
370 xoap
->xoa_av_quarantined
) == 0);
372 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_MODIFIED
)) {
373 VERIFY(nvlist_add_boolean_value(nvlp
,
374 attr_to_name(F_AV_MODIFIED
),
375 xoap
->xoa_av_modified
) == 0);
377 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_SCANSTAMP
)) {
378 VERIFY(nvlist_add_uint8_array(nvlp
,
379 attr_to_name(F_AV_SCANSTAMP
),
380 xoap
->xoa_av_scanstamp
,
381 sizeof (xoap
->xoa_av_scanstamp
)) == 0);
383 if (XVA_ISSET_RTN(&xvattr
, XAT_CREATETIME
)) {
384 VERIFY(nvlist_add_uint64_array(nvlp
,
385 attr_to_name(F_CRTIME
),
386 (uint64_t *)&(xoap
->xoa_createtime
),
387 sizeof (xoap
->xoa_createtime
) /
388 sizeof (uint64_t)) == 0);
390 if (XVA_ISSET_RTN(&xvattr
, XAT_REPARSE
)) {
391 VERIFY(nvlist_add_boolean_value(nvlp
,
392 attr_to_name(F_REPARSE
),
393 xoap
->xoa_reparse
) == 0);
395 if (XVA_ISSET_RTN(&xvattr
, XAT_GEN
)) {
396 VERIFY(nvlist_add_uint64(nvlp
,
398 xoap
->xoa_generation
) == 0);
400 if (XVA_ISSET_RTN(&xvattr
, XAT_OFFLINE
)) {
401 VERIFY(nvlist_add_boolean_value(nvlp
,
402 attr_to_name(F_OFFLINE
),
403 xoap
->xoa_offline
) == 0);
405 if (XVA_ISSET_RTN(&xvattr
, XAT_SPARSE
)) {
406 VERIFY(nvlist_add_boolean_value(nvlp
,
407 attr_to_name(F_SPARSE
),
408 xoap
->xoa_sparse
) == 0);
412 * Check for optional ownersid/groupsid
415 if (xvattr
.xva_vattr
.va_uid
> MAXUID
) {
418 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
421 if (kidmap_getsidbyuid(crgetzone(cr
), xvattr
.xva_vattr
.va_uid
,
422 &domain
, &rid
) == 0) {
423 VERIFY(nvlist_add_string(nvl_sid
,
424 SID_DOMAIN
, domain
) == 0);
425 VERIFY(nvlist_add_uint32(nvl_sid
, SID_RID
, rid
) == 0);
426 VERIFY(nvlist_add_nvlist(nvlp
, attr_to_name(F_OWNERSID
),
429 nvlist_free(nvl_sid
);
431 if (xvattr
.xva_vattr
.va_gid
> MAXUID
) {
434 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
437 if (kidmap_getsidbygid(crgetzone(cr
), xvattr
.xva_vattr
.va_gid
,
438 &domain
, &rid
) == 0) {
439 VERIFY(nvlist_add_string(nvl_sid
,
440 SID_DOMAIN
, domain
) == 0);
441 VERIFY(nvlist_add_uint32(nvl_sid
, SID_RID
, rid
) == 0);
442 VERIFY(nvlist_add_nvlist(nvlp
, attr_to_name(F_GROUPSID
),
445 nvlist_free(nvl_sid
);
452 * The size of a sysattr file is the size of the nvlist that will be
453 * returned by xattr_file_read(). A call to xattr_file_write() could
454 * change the size of that nvlist. That size is not stored persistently
455 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
458 xattr_file_size(vnode_t
*vp
, xattr_view_t xattr_view
, size_t *size
,
459 cred_t
*cr
, caller_context_t
*ct
)
463 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
)) {
467 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
472 VERIFY(nvlist_size(nvl
, size
, NV_ENCODE_XDR
) == 0);
479 xattr_file_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
480 caller_context_t
*ct
)
482 xattr_file_t
*np
= vp
->v_data
;
490 vap
->va_mode
= MAKEIMODE(vap
->va_type
,
491 (np
->xattr_view
== XATTR_VIEW_READONLY
? 0444 : 0644));
492 vap
->va_nodeid
= gfs_file_inode(vp
);
494 pvp
= gfs_file_parent(vp
);
495 (void) memset(&pvattr
, 0, sizeof (pvattr
));
496 pvattr
.va_mask
= AT_CTIME
|AT_MTIME
;
497 error
= VOP_GETATTR(pvp
, &pvattr
, flags
, cr
, ct
);
501 vap
->va_ctime
= pvattr
.va_ctime
;
502 vap
->va_mtime
= pvattr
.va_mtime
;
508 vap
->va_blksize
= DEV_BSIZE
;
510 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
511 error
= xattr_file_size(vp
, np
->xattr_view
, &size
, cr
, ct
);
513 vap
->va_nblocks
= howmany(vap
->va_size
, vap
->va_blksize
);
519 xattr_file_read(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
520 caller_context_t
*ct
)
522 xattr_file_t
*np
= vp
->v_data
;
523 xattr_view_t xattr_view
= np
->xattr_view
;
530 * Validate file offset and fasttrack empty reads
532 if (uiop
->uio_loffset
< (offset_t
)0)
535 if (uiop
->uio_resid
== 0)
538 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
))
541 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
546 VERIFY(nvlist_size(nvl
, &filesize
, NV_ENCODE_XDR
) == 0);
548 if (uiop
->uio_loffset
>= filesize
) {
553 buf
= kmem_alloc(filesize
, KM_SLEEP
);
554 VERIFY(nvlist_pack(nvl
, &buf
, &filesize
, NV_ENCODE_XDR
,
557 error
= uiomove((caddr_t
)buf
, filesize
, UIO_READ
, uiop
);
558 kmem_free(buf
, filesize
);
565 xattr_file_write(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
566 caller_context_t
*ct
)
572 ssize_t size
= uiop
->uio_resid
;
574 nvpair_t
*pair
= NULL
;
577 xoptattr_t
*xoap
= NULL
; /* Pointer to optional attributes */
579 if (vfs_has_feature(vp
->v_vfsp
, VFSFT_XVATTR
) == 0)
583 * Validate file offset and size.
585 if (uiop
->uio_loffset
< (offset_t
)0)
593 if ((xoap
= xva_getxoptattr(&xvattr
)) == NULL
) {
598 * Copy and unpack the nvlist
600 buf
= kmem_alloc(size
, KM_SLEEP
);
601 if (uiomove((caddr_t
)buf
, size
, UIO_WRITE
, uiop
)) {
605 if (nvlist_unpack(buf
, size
, &nvp
, KM_SLEEP
) != 0) {
606 kmem_free(buf
, size
);
607 uiop
->uio_resid
= size
;
610 kmem_free(buf
, size
);
613 * Fasttrack empty writes (nvlist with no nvpairs)
615 if (nvlist_next_nvpair(nvp
, NULL
) == 0)
618 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
620 while (pair
= nvlist_next_nvpair(nvp
, pair
)) {
624 uint64_t *time
, *times
;
630 * Validate the name and type of each attribute.
631 * Log any unknown names and continue. This will
632 * help if additional attributes are added later.
634 type
= nvpair_type(pair
);
635 if ((attr
= name_to_attr(nvpair_name(pair
))) == F_ATTR_INVAL
) {
636 cmn_err(CE_WARN
, "Unknown attribute %s",
642 * Verify nvlist type matches required type and view is OK
645 if (type
!= attr_to_data_type(attr
) ||
646 (attr_to_xattr_view(attr
) == XATTR_VIEW_READONLY
)) {
652 * For OWNERSID/GROUPSID make sure the target
653 * file system support ephemeral ID's
655 if ((attr
== F_OWNERSID
|| attr
== F_GROUPSID
) &&
656 (!(vp
->v_vfsp
->vfs_flag
& VFS_XID
))) {
662 * Retrieve data from nvpair
665 case DATA_TYPE_BOOLEAN_VALUE
:
666 if (nvpair_value_boolean_value(pair
, &value
)) {
671 case DATA_TYPE_UINT64_ARRAY
:
672 if (nvpair_value_uint64_array(pair
, ×
, &nelems
)) {
677 case DATA_TYPE_NVLIST
:
678 if (nvpair_value_nvlist(pair
, &nvp_sid
)) {
683 case DATA_TYPE_UINT8_ARRAY
:
684 if (nvpair_value_uint8_array(pair
,
685 &scanstamp
, &nelems
)) {
697 * If we have several similar optional attributes to
698 * process then we should do it all together here so that
699 * xoap and the requested bitmap can be set in one place.
702 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
703 xoap
->xoa_readonly
= value
;
706 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
707 xoap
->xoa_hidden
= value
;
710 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
711 xoap
->xoa_system
= value
;
714 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
715 xoap
->xoa_archive
= value
;
718 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
719 xoap
->xoa_immutable
= value
;
722 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
723 xoap
->xoa_nounlink
= value
;
726 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
727 xoap
->xoa_appendonly
= value
;
730 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
731 xoap
->xoa_nodump
= value
;
733 case F_AV_QUARANTINED
:
734 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
735 xoap
->xoa_av_quarantined
= value
;
738 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
739 xoap
->xoa_av_modified
= value
;
742 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
743 time
= (uint64_t *)&(xoap
->xoa_createtime
);
744 for (elem
= 0; elem
< nelems
; elem
++)
745 *time
++ = times
[elem
];
749 if (nvlist_lookup_string(nvp_sid
, SID_DOMAIN
,
750 &domain
) || nvlist_lookup_uint32(nvp_sid
, SID_RID
,
757 * Now map domain+rid to ephemeral id's
759 * If mapping fails, then the uid/gid will
760 * be set to UID_NOBODY by Winchester.
763 if (attr
== F_OWNERSID
) {
764 (void) kidmap_getuidbysid(crgetzone(cr
), domain
,
765 rid
, &xvattr
.xva_vattr
.va_uid
);
766 xvattr
.xva_vattr
.va_mask
|= AT_UID
;
768 (void) kidmap_getgidbysid(crgetzone(cr
), domain
,
769 rid
, &xvattr
.xva_vattr
.va_gid
);
770 xvattr
.xva_vattr
.va_mask
|= AT_GID
;
774 if (ppvp
->v_type
== VREG
) {
775 XVA_SET_REQ(&xvattr
, XAT_AV_SCANSTAMP
);
776 (void) memcpy(xoap
->xoa_av_scanstamp
,
784 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
785 xoap
->xoa_reparse
= value
;
788 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
789 xoap
->xoa_offline
= value
;
792 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
793 xoap
->xoa_sparse
= value
;
800 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
801 error
= VOP_SETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
803 uiop
->uio_resid
= size
;
810 xattr_file_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
811 caller_context_t
*ct
)
814 case _PC_XATTR_EXISTS
:
815 case _PC_SATTR_ENABLED
:
816 case _PC_SATTR_EXISTS
:
820 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
824 vnodeops_t
*xattr_file_ops
;
826 static const fs_operation_def_t xattr_file_tops
[] = {
827 { VOPNAME_OPEN
, { .vop_open
= xattr_file_open
} },
828 { VOPNAME_CLOSE
, { .vop_close
= xattr_file_close
} },
829 { VOPNAME_READ
, { .vop_read
= xattr_file_read
} },
830 { VOPNAME_WRITE
, { .vop_write
= xattr_file_write
} },
831 { VOPNAME_IOCTL
, { .error
= fs_ioctl
} },
832 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_file_getattr
} },
833 { VOPNAME_ACCESS
, { .vop_access
= xattr_file_access
} },
834 { VOPNAME_READDIR
, { .error
= fs_notdir
} },
835 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
836 { VOPNAME_INACTIVE
, { .vop_inactive
= gfs_vop_inactive
} },
837 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
838 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_file_pathconf
} },
839 { VOPNAME_PUTPAGE
, { .error
= fs_putpage
} },
840 { VOPNAME_FSYNC
, { .error
= fs_fsync
} },
845 xattr_mkfile(vnode_t
*pvp
, xattr_view_t xattr_view
)
850 vp
= gfs_file_create(sizeof (xattr_file_t
), pvp
, xattr_file_ops
);
852 np
->xattr_view
= xattr_view
;
853 vp
->v_flag
|= V_SYSATTR
;
858 xattr_mkfile_ro(vnode_t
*pvp
)
860 return (xattr_mkfile(pvp
, XATTR_VIEW_READONLY
));
864 xattr_mkfile_rw(vnode_t
*pvp
)
866 return (xattr_mkfile(pvp
, XATTR_VIEW_READWRITE
));
869 vnodeops_t
*xattr_dir_ops
;
871 static gfs_dirent_t xattr_dirents
[] = {
872 { VIEW_READONLY
, xattr_mkfile_ro
, GFS_CACHE_VNODE
, },
873 { VIEW_READWRITE
, xattr_mkfile_rw
, GFS_CACHE_VNODE
, },
877 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
880 is_sattr_name(char *s
)
884 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
885 if (strcmp(s
, xattr_dirents
[i
].gfse_name
) == 0) {
893 * Given the name of an extended attribute file, determine if there is a
894 * normalization conflict with a sysattr view name.
897 xattr_sysattr_casechk(char *s
)
901 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
902 if (strcasecmp(s
, xattr_dirents
[i
].gfse_name
) == 0)
909 xattr_copy(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
910 cred_t
*cr
, caller_context_t
*ct
)
917 * Only copy system attrs if the views are the same
919 if (strcmp(snm
, tnm
) != 0)
924 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
925 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
926 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
927 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
928 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
929 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
930 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
931 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
932 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
933 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
934 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
935 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
936 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
937 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
939 pdvp
= gfs_file_parent(sdvp
);
940 error
= VOP_GETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
944 pdvp
= gfs_file_parent(tdvp
);
945 error
= VOP_SETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
950 * Get the "real" XATTR directory associtated with the GFS XATTR directory.
951 * Note: This does NOT take any additional hold on the returned real_vp,
952 * because when this lookup succeeds we save the result in xattr_realvp
953 * and keep that hold until the GFS XATTR directory goes inactive.
956 xattr_dir_realdir(vnode_t
*gfs_dvp
, vnode_t
**ret_vpp
, int flags
,
957 cred_t
*cr
, caller_context_t
*ct
)
961 xattr_dir_t
*xattr_dir
;
968 * Usually, we've already found the underlying XATTR directory
969 * during some previous lookup and stored it in xattr_realvp.
971 mutex_enter(&gfs_dvp
->v_lock
);
972 xattr_dir
= gfs_dvp
->v_data
;
973 realvp
= xattr_dir
->xattr_realvp
;
974 mutex_exit(&gfs_dvp
->v_lock
);
975 if (realvp
!= NULL
) {
981 * Lookup the XATTR dir in the underlying FS, relative to our
982 * "parent", which is the real object for which this GFS XATTR
983 * directory was created. Set the LOOKUP_HAVE_SYSATTR_DIR flag
984 * so that we don't get into an infinite loop with fop_lookup
985 * calling back to xattr_dir_lookup.
987 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
990 error
= VOP_LOOKUP(gfs_file_parent(gfs_dvp
), nm
, &realvp
, &pn
,
991 flags
| LOOKUP_HAVE_SYSATTR_DIR
, rootvp
, cr
, ct
, NULL
, NULL
);
997 * Have the real XATTR directory. Save it -- but first
998 * check whether we lost a race doing the lookup.
1000 mutex_enter(&gfs_dvp
->v_lock
);
1001 xattr_dir
= gfs_dvp
->v_data
;
1002 if (xattr_dir
->xattr_realvp
== NULL
) {
1004 * Note that the hold taken by the VOP_LOOKUP above is
1005 * retained from here until xattr_dir_inactive.
1007 xattr_dir
->xattr_realvp
= realvp
;
1009 /* We lost the race. */
1011 realvp
= xattr_dir
->xattr_realvp
;
1013 mutex_exit(&gfs_dvp
->v_lock
);
1021 xattr_dir_open(vnode_t
**vpp
, int flags
, cred_t
*cr
, caller_context_t
*ct
)
1026 if (flags
& FWRITE
) {
1031 * If there is a real extended attribute directory,
1032 * let the underlying FS see the VOP_OPEN call;
1033 * otherwise just return zero.
1035 error
= xattr_dir_realdir(*vpp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1037 error
= VOP_OPEN(&realvp
, flags
, cr
, ct
);
1047 xattr_dir_close(vnode_t
*vp
, int flags
, int count
, offset_t off
, cred_t
*cr
,
1048 caller_context_t
*ct
)
1054 * If there is a real extended attribute directory,
1055 * let the underlying FS see the VOP_CLOSE call;
1056 * otherwise just return zero.
1058 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1060 error
= VOP_CLOSE(realvp
, flags
, count
, off
, cr
, ct
);
1069 * Retrieve the attributes on an xattr directory. If there is a "real"
1070 * xattr directory, use that. Otherwise, get the attributes (represented
1071 * by PARENT_ATTRMASK) from the "parent" node and fill in the rest. Note
1072 * that VOP_GETATTR() could turn off bits in the va_mask.
1075 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
1079 xattr_dir_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
1080 caller_context_t
*ct
)
1086 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1088 error
= VOP_GETATTR(pvp
, vap
, 0, cr
, ct
);
1092 vap
->va_nlink
+= XATTRDIR_NENTS
;
1093 vap
->va_size
+= XATTRDIR_NENTS
;
1098 * There is no real xattr directory. Cobble together
1099 * an entry using info from the parent object (if needed)
1100 * plus information common to all xattrs.
1102 if (vap
->va_mask
& PARENT_ATTRMASK
) {
1106 pvp
= gfs_file_parent(vp
);
1107 (void) memset(&pvattr
, 0, sizeof (pvattr
));
1108 pvattr
.va_mask
= PARENT_ATTRMASK
;
1109 error
= VOP_GETATTR(pvp
, &pvattr
, 0, cr
, ct
);
1115 * VOP_GETATTR() might have turned off some bits in
1116 * pvattr.va_mask. This means that the underlying
1117 * file system couldn't process those attributes.
1118 * We need to make sure those bits get turned off
1119 * in the vattr_t structure that gets passed back
1120 * to the caller. Figure out which bits were turned
1121 * off (if any) then set pvattr.va_mask before it
1122 * gets copied to the vattr_t that the caller sees.
1124 off_bits
= (pvattr
.va_mask
^ PARENT_ATTRMASK
) & PARENT_ATTRMASK
;
1125 pvattr
.va_mask
= vap
->va_mask
& ~off_bits
;
1129 vap
->va_type
= VDIR
;
1130 vap
->va_mode
= MAKEIMODE(vap
->va_type
, S_ISVTX
| 0777);
1131 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
1132 vap
->va_nodeid
= gfs_file_inode(vp
);
1133 vap
->va_nlink
= XATTRDIR_NENTS
+2;
1134 vap
->va_size
= vap
->va_nlink
;
1136 vap
->va_atime
= now
;
1137 vap
->va_blksize
= 0;
1138 vap
->va_nblocks
= 0;
1144 xattr_dir_setattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
1145 caller_context_t
*ct
)
1151 * If there is a real xattr directory, do the setattr there.
1152 * Otherwise, just return success. The GFS directory is transient,
1153 * and any setattr changes can disappear anyway.
1155 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1157 error
= VOP_SETATTR(realvp
, vap
, flags
, cr
, ct
);
1159 if (error
== ENOENT
) {
1167 xattr_dir_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
1168 caller_context_t
*ct
)
1171 vnode_t
*realvp
= NULL
;
1173 if (mode
& VWRITE
) {
1177 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1178 if ((error
== ENOENT
|| error
== EINVAL
)) {
1180 * These errors mean there's no "real" xattr dir.
1181 * The GFS xattr dir always allows access.
1187 * The "real" xattr dir was not accessible.
1192 * We got the "real" xattr dir.
1193 * Pass through the access call.
1195 error
= VOP_ACCESS(realvp
, mode
, flags
, cr
, ct
);
1201 xattr_dir_create(vnode_t
*dvp
, char *name
, vattr_t
*vap
, vcexcl_t excl
,
1202 int mode
, vnode_t
**vpp
, cred_t
*cr
, int flag
, caller_context_t
*ct
,
1211 * Don't allow creation of extended attributes with sysattr names.
1213 if (is_sattr_name(name
)) {
1214 return (gfs_dir_lookup(dvp
, name
, vpp
, cr
, 0, NULL
, NULL
));
1217 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1220 error
= VOP_CREATE(pvp
, name
, vap
, excl
, mode
, vpp
, cr
, flag
,
1227 xattr_dir_remove(vnode_t
*dvp
, char *name
, cred_t
*cr
, caller_context_t
*ct
,
1233 if (is_sattr_name(name
)) {
1237 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1239 error
= VOP_REMOVE(pvp
, name
, cr
, ct
, flags
);
1245 xattr_dir_link(vnode_t
*tdvp
, vnode_t
*svp
, char *name
, cred_t
*cr
,
1246 caller_context_t
*ct
, int flags
)
1251 if (svp
->v_flag
& V_SYSATTR
) {
1255 error
= xattr_dir_realdir(tdvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1257 error
= VOP_LINK(pvp
, svp
, name
, cr
, ct
, flags
);
1263 xattr_dir_rename(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
1264 cred_t
*cr
, caller_context_t
*ct
, int flags
)
1266 vnode_t
*spvp
, *tpvp
;
1269 if (is_sattr_name(snm
) || is_sattr_name(tnm
))
1270 return (xattr_copy(sdvp
, snm
, tdvp
, tnm
, cr
, ct
));
1272 * We know that sdvp is a GFS dir, or we wouldn't be here.
1273 * Get the real unnamed directory.
1275 error
= xattr_dir_realdir(sdvp
, &spvp
, LOOKUP_XATTR
, cr
, ct
);
1282 * If the source and target are the same GFS directory, the
1283 * underlying unnamed source and target dir will be the same.
1286 } else if (tdvp
->v_flag
& V_SYSATTR
) {
1288 * If the target dir is a different GFS directory,
1289 * find its underlying unnamed dir.
1291 error
= xattr_dir_realdir(tdvp
, &tpvp
, LOOKUP_XATTR
, cr
, ct
);
1297 * Target dir is outside of GFS, pass it on through.
1302 error
= VOP_RENAME(spvp
, snm
, tpvp
, tnm
, cr
, ct
, flags
);
1308 * readdir_xattr_casecmp: given a system attribute name, see if there
1309 * is a real xattr with the same normalized name.
1312 readdir_xattr_casecmp(vnode_t
*dvp
, char *nm
, cred_t
*cr
, caller_context_t
*ct
,
1321 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1323 error
= VOP_LOOKUP(dvp
, nm
, &vp
, &pn
,
1324 FIGNORECASE
, rootvp
, cr
, ct
, NULL
, NULL
);
1326 *eflags
= ED_CASE_CONFLICT
;
1328 } else if (error
== ENOENT
) {
1338 xattr_dir_readdir(vnode_t
*dvp
, uio_t
*uiop
, cred_t
*cr
, int *eofp
,
1339 caller_context_t
*ct
, int flags
)
1353 * See if there is a real extended attribute directory.
1355 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1361 * Start by reading up the static entries.
1363 if (uiop
->uio_loffset
== 0) {
1366 gfs_dir_t
*dp
= dvp
->v_data
;
1367 gfs_readdir_state_t gstate
;
1371 * If there is a real xattr dir, skip . and ..
1372 * in the GFS dir. We'll pick them up below
1373 * when we call into the underlying fs.
1375 uiop
->uio_loffset
= GFS_STATIC_ENTRY_OFFSET
;
1377 error
= gfs_get_parent_ino(dvp
, cr
, ct
, &pino
, &ino
);
1379 error
= gfs_readdir_init(&gstate
, dp
->gfsd_maxlen
, 1,
1380 uiop
, pino
, ino
, flags
);
1386 while ((error
= gfs_readdir_pred(&gstate
, uiop
, &off
)) == 0 &&
1388 if (off
>= 0 && off
< dp
->gfsd_nstatic
) {
1392 * Check to see if this sysattr set name has a
1393 * case-insensitive conflict with a real xattr
1397 if ((flags
& V_RDDIR_ENTFLAGS
) && has_xattrs
) {
1398 error
= readdir_xattr_casecmp(pvp
,
1399 dp
->gfsd_static
[off
].gfse_name
,
1404 ino
= dp
->gfsd_inode(dvp
, off
);
1406 error
= gfs_readdir_emit(&gstate
, uiop
, off
,
1407 ino
, dp
->gfsd_static
[off
].gfse_name
,
1416 error
= gfs_readdir_fini(&gstate
, error
, eofp
, *eofp
);
1422 * We must read all of the static entries in the first
1423 * call. Otherwise we won't know if uio_loffset in a
1424 * subsequent call refers to the static entries or to those
1425 * in an underlying fs.
1439 uiop
->uio_loffset
= 0;
1441 (void) VOP_RWLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1442 error
= VOP_READDIR(pvp
, uiop
, cr
, eofp
, ct
, flags
);
1443 VOP_RWUNLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1449 * Last reference on a (GFS) XATTR directory.
1451 * If there's a real XATTR directory in the underlying FS, we will have
1452 * taken a hold on that directory in xattr_dir_realdir. Now that the
1453 * last hold on the GFS directory is gone, it's time to release that
1454 * hold on the underlying XATTR directory.
1458 xattr_dir_inactive(vnode_t
*vp
, cred_t
*cr
, caller_context_t
*ct
)
1462 dp
= gfs_dir_inactive(vp
); /* will track v_count */
1465 if (dp
->xattr_realvp
!= NULL
)
1466 VN_RELE(dp
->xattr_realvp
);
1468 kmem_free(dp
, ((gfs_file_t
*)dp
)->gfs_size
);
1473 xattr_dir_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
1474 caller_context_t
*ct
)
1477 case _PC_XATTR_EXISTS
:
1478 case _PC_SATTR_ENABLED
:
1479 case _PC_SATTR_EXISTS
:
1483 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
1489 xattr_dir_realvp(vnode_t
*vp
, vnode_t
**realvp
, caller_context_t
*ct
)
1493 error
= xattr_dir_realdir(vp
, realvp
, LOOKUP_XATTR
, kcred
, NULL
);
1498 static const fs_operation_def_t xattr_dir_tops
[] = {
1499 { VOPNAME_OPEN
, { .vop_open
= xattr_dir_open
} },
1500 { VOPNAME_CLOSE
, { .vop_close
= xattr_dir_close
} },
1501 { VOPNAME_IOCTL
, { .error
= fs_inval
} },
1502 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_dir_getattr
} },
1503 { VOPNAME_SETATTR
, { .vop_setattr
= xattr_dir_setattr
} },
1504 { VOPNAME_ACCESS
, { .vop_access
= xattr_dir_access
} },
1505 { VOPNAME_READDIR
, { .vop_readdir
= xattr_dir_readdir
} },
1506 { VOPNAME_LOOKUP
, { .vop_lookup
= gfs_vop_lookup
} },
1507 { VOPNAME_CREATE
, { .vop_create
= xattr_dir_create
} },
1508 { VOPNAME_REMOVE
, { .vop_remove
= xattr_dir_remove
} },
1509 { VOPNAME_LINK
, { .vop_link
= xattr_dir_link
} },
1510 { VOPNAME_RENAME
, { .vop_rename
= xattr_dir_rename
} },
1511 { VOPNAME_MKDIR
, { .error
= fs_inval
} },
1512 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
1513 { VOPNAME_INACTIVE
, { .vop_inactive
= xattr_dir_inactive
} },
1514 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
1515 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_dir_pathconf
} },
1516 { VOPNAME_REALVP
, { .vop_realvp
= xattr_dir_realvp
} },
1520 static gfs_opsvec_t xattr_opsvec
[] = {
1521 { "xattr dir", xattr_dir_tops
, &xattr_dir_ops
},
1522 { "system attributes", xattr_file_tops
, &xattr_file_ops
},
1523 { NULL
, NULL
, NULL
}
1527 * Callback supporting lookup in a GFS XATTR directory.
1530 xattr_lookup_cb(vnode_t
*vp
, const char *nm
, vnode_t
**vpp
, ino64_t
*inop
,
1531 cred_t
*cr
, int flags
, int *deflags
, pathname_t
*rpnp
)
1540 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
, cr
, NULL
);
1543 * Return ENOENT for EACCES requests during lookup. Once an
1544 * attribute create is attempted EACCES will be returned.
1547 if (error
== EACCES
)
1552 error
= pn_get((char *)nm
, UIO_SYSSPACE
, &pn
);
1554 error
= VOP_LOOKUP(pvp
, (char *)nm
, vpp
, &pn
, flags
, rootvp
,
1555 cr
, NULL
, deflags
, rpnp
);
1564 xattrdir_do_ino(vnode_t
*vp
, int index
)
1567 * We use index 0 for the directory fid. Start
1568 * the file numbering at 1.
1570 return ((ino64_t
)index
+1);
1576 VERIFY(gfs_make_opsvec(xattr_opsvec
) == 0);
1580 * Get the XATTR dir for some file or directory.
1581 * See vnode.c: fop_lookup()
1583 * Note this only gets the GFS XATTR directory. We'll get the
1584 * real XATTR directory later, in xattr_dir_realdir.
1587 xattr_dir_lookup(vnode_t
*dvp
, vnode_t
**vpp
, int flags
, cred_t
*cr
)
1593 if (dvp
->v_type
!= VDIR
&& dvp
->v_type
!= VREG
)
1596 mutex_enter(&dvp
->v_lock
);
1599 * If we're already in sysattr space, don't allow creation
1600 * of another level of sysattrs.
1602 if (dvp
->v_flag
& V_SYSATTR
) {
1603 mutex_exit(&dvp
->v_lock
);
1607 if (dvp
->v_xattrdir
!= NULL
) {
1608 *vpp
= dvp
->v_xattrdir
;
1612 int xattrs_allowed
= dvp
->v_vfsp
->vfs_flag
& VFS_XATTR
;
1613 int sysattrs_allowed
= 1;
1616 * We have to drop the lock on dvp. gfs_dir_create will
1617 * grab it for a VN_HOLD.
1619 mutex_exit(&dvp
->v_lock
);
1622 * If dvp allows xattr creation, but not sysattr
1623 * creation, return the real xattr dir vp. We can't
1624 * use the vfs feature mask here because _PC_SATTR_ENABLED
1625 * has vnode-level granularity (e.g. .zfs).
1627 error
= VOP_PATHCONF(dvp
, _PC_SATTR_ENABLED
, &val
, cr
, NULL
);
1628 if (error
!= 0 || val
== 0)
1629 sysattrs_allowed
= 0;
1631 if (!xattrs_allowed
&& !sysattrs_allowed
)
1634 if (!sysattrs_allowed
) {
1638 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1641 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
,
1642 flags
|LOOKUP_HAVE_SYSATTR_DIR
, rootvp
, cr
, NULL
,
1649 * Note that we act as if we were given CREATE_XATTR_DIR,
1650 * but only for creation of the GFS directory.
1652 *vpp
= gfs_dir_create(
1653 sizeof (xattr_dir_t
), dvp
, xattr_dir_ops
, xattr_dirents
,
1654 xattrdir_do_ino
, MAXNAMELEN
, NULL
, xattr_lookup_cb
);
1655 mutex_enter(&dvp
->v_lock
);
1656 if (dvp
->v_xattrdir
!= NULL
) {
1658 * We lost the race to create the xattr dir.
1659 * Destroy this one, use the winner. We can't
1660 * just call VN_RELE(*vpp), because the vnode
1661 * is only partially initialized.
1663 gfs_dir_t
*dp
= (*vpp
)->v_data
;
1665 ASSERT((*vpp
)->v_count
== 1);
1668 mutex_destroy(&dp
->gfsd_lock
);
1669 kmem_free(dp
->gfsd_static
,
1670 dp
->gfsd_nstatic
* sizeof (gfs_dirent_t
));
1671 kmem_free(dp
, dp
->gfsd_file
.gfs_size
);
1674 * There is an implied VN_HOLD(dvp) here. We should
1675 * be doing a VN_RELE(dvp) to clean up the reference
1676 * from *vpp, and then a VN_HOLD(dvp) for the new
1677 * reference. Instead, we just leave the count alone.
1680 *vpp
= dvp
->v_xattrdir
;
1683 (*vpp
)->v_flag
|= (V_XATTRDIR
|V_SYSATTR
);
1684 dvp
->v_xattrdir
= *vpp
;
1687 mutex_exit(&dvp
->v_lock
);
1693 xattr_dir_vget(vfs_t
*vfsp
, vnode_t
**vpp
, fid_t
*fidp
)
1704 if (fidp
->fid_len
< XATTR_FIDSZ
)
1707 xfidp
= (xattr_fid_t
*)fidp
;
1708 orig_len
= fidp
->fid_len
;
1709 fidp
->fid_len
= xfidp
->parent_len
;
1711 error
= VFS_VGET(vfsp
, &pvp
, fidp
);
1712 fidp
->fid_len
= orig_len
;
1717 * Start by getting the GFS sysattr directory. We might need
1718 * to recreate it during the VOP_LOOKUP.
1721 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1727 error
= VOP_LOOKUP(pvp
, nm
, &dvp
, &pn
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1728 rootvp
, CRED(), NULL
, NULL
, NULL
);
1734 if (xfidp
->dir_offset
== 0) {
1736 * If we were looking for the directory, we're done.
1742 if (xfidp
->dir_offset
> XATTRDIR_NENTS
) {
1747 nm
= xattr_dirents
[xfidp
->dir_offset
- 1].gfse_name
;
1749 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1755 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
, 0, rootvp
, CRED(), NULL
,