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.
25 #include <sys/param.h>
26 #include <sys/isa_defs.h>
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
32 #include <sys/fcntl.h>
33 #include <sys/pathname.h>
38 #include <sys/sunddi.h>
39 #include <sys/debug.h>
40 #include <sys/cmn_err.h>
41 #include <sys/vnode.h>
43 #include <sys/nvpair.h>
46 #include <sys/mutex.h>
47 #include <fs/fs_subr.h>
48 #include <sys/kidmap.h>
51 gfs_file_t xattr_gfs_private
;
52 xattr_view_t xattr_view
;
56 gfs_dir_t xattr_gfs_private
;
57 vnode_t
*xattr_realvp
; /* Only used for VOP_REALVP */
61 * xattr_realvp is only used for VOP_REALVP, this is so we don't
62 * keep an unnecessary hold on the *real* xattr dir unless we have
68 xattr_file_open(vnode_t
**vpp
, int flags
, cred_t
*cr
, caller_context_t
*ct
)
70 xattr_file_t
*np
= (*vpp
)->v_data
;
72 if ((np
->xattr_view
== XATTR_VIEW_READONLY
) && (flags
& FWRITE
))
80 xattr_file_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
83 xattr_file_t
*np
= vp
->v_data
;
85 if ((np
->xattr_view
== XATTR_VIEW_READONLY
) && (mode
& VWRITE
))
93 xattr_file_close(vnode_t
*vp
, int flags
, int count
, offset_t off
,
94 cred_t
*cr
, caller_context_t
*ct
)
96 cleanlocks(vp
, ddi_get_pid(), 0);
97 cleanshares(vp
, ddi_get_pid());
102 xattr_common_fid(vnode_t
*vp
, fid_t
*fidp
, caller_context_t
*ct
)
105 vnode_t
*pvp
, *savevp
;
109 if (fidp
->fid_len
< XATTR_FIDSZ
) {
110 fidp
->fid_len
= XATTR_FIDSZ
;
114 savevp
= pvp
= gfs_file_parent(vp
);
115 mutex_enter(&savevp
->v_lock
);
116 if (pvp
->v_flag
& V_XATTRDIR
) {
117 pvp
= gfs_file_parent(pvp
);
119 mutex_exit(&savevp
->v_lock
);
121 xfidp
= (xattr_fid_t
*)fidp
;
122 orig_len
= fidp
->fid_len
;
123 fidp
->fid_len
= sizeof (xfidp
->parent_fid
);
125 error
= VOP_FID(pvp
, fidp
, ct
);
127 fidp
->fid_len
= orig_len
;
131 xfidp
->parent_len
= fidp
->fid_len
;
132 fidp
->fid_len
= XATTR_FIDSZ
;
133 xfidp
->dir_offset
= gfs_file_inode(vp
);
140 xattr_fill_nvlist(vnode_t
*vp
, xattr_view_t xattr_view
, nvlist_t
*nvlp
,
141 cred_t
*cr
, caller_context_t
*ct
)
147 xoptattr_t
*xoap
; /* Pointer to optional attributes */
154 if ((xoap
= xva_getxoptattr(&xvattr
)) == NULL
)
158 * For detecting ephemeral uid/gid
160 xvattr
.xva_vattr
.va_mask
|= (AT_UID
|AT_GID
);
163 * We need to access the real fs object.
164 * vp points to a GFS file; ppvp points to the real object.
166 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
169 * Iterate through the attrs associated with this view
172 for (attr
= 0; attr
< F_ATTR_ALL
; attr
++) {
173 if (xattr_view
!= attr_to_xattr_view(attr
)) {
179 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
182 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
185 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
188 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
191 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
194 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
197 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
200 XVA_SET_REQ(&xvattr
, XAT_OPAQUE
);
203 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
205 case F_AV_QUARANTINED
:
206 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
209 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
212 if (ppvp
->v_type
== VREG
)
213 XVA_SET_REQ(&xvattr
, XAT_AV_SCANSTAMP
);
216 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
219 fsid
= (((uint64_t)vp
->v_vfsp
->vfs_fsid
.val
[0] << 32) |
220 (uint64_t)(vp
->v_vfsp
->vfs_fsid
.val
[1] &
222 VERIFY(nvlist_add_uint64(nvlp
, attr_to_name(attr
),
226 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
233 error
= VOP_GETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
238 * Process all the optional attributes together here. Notice that
239 * xoap was set when the optional attribute bits were set above.
241 if ((xvattr
.xva_vattr
.va_mask
& AT_XVATTR
) && xoap
) {
242 if (XVA_ISSET_RTN(&xvattr
, XAT_READONLY
)) {
243 VERIFY(nvlist_add_boolean_value(nvlp
,
244 attr_to_name(F_READONLY
),
245 xoap
->xoa_readonly
) == 0);
247 if (XVA_ISSET_RTN(&xvattr
, XAT_HIDDEN
)) {
248 VERIFY(nvlist_add_boolean_value(nvlp
,
249 attr_to_name(F_HIDDEN
),
250 xoap
->xoa_hidden
) == 0);
252 if (XVA_ISSET_RTN(&xvattr
, XAT_SYSTEM
)) {
253 VERIFY(nvlist_add_boolean_value(nvlp
,
254 attr_to_name(F_SYSTEM
),
255 xoap
->xoa_system
) == 0);
257 if (XVA_ISSET_RTN(&xvattr
, XAT_ARCHIVE
)) {
258 VERIFY(nvlist_add_boolean_value(nvlp
,
259 attr_to_name(F_ARCHIVE
),
260 xoap
->xoa_archive
) == 0);
262 if (XVA_ISSET_RTN(&xvattr
, XAT_IMMUTABLE
)) {
263 VERIFY(nvlist_add_boolean_value(nvlp
,
264 attr_to_name(F_IMMUTABLE
),
265 xoap
->xoa_immutable
) == 0);
267 if (XVA_ISSET_RTN(&xvattr
, XAT_NOUNLINK
)) {
268 VERIFY(nvlist_add_boolean_value(nvlp
,
269 attr_to_name(F_NOUNLINK
),
270 xoap
->xoa_nounlink
) == 0);
272 if (XVA_ISSET_RTN(&xvattr
, XAT_APPENDONLY
)) {
273 VERIFY(nvlist_add_boolean_value(nvlp
,
274 attr_to_name(F_APPENDONLY
),
275 xoap
->xoa_appendonly
) == 0);
277 if (XVA_ISSET_RTN(&xvattr
, XAT_NODUMP
)) {
278 VERIFY(nvlist_add_boolean_value(nvlp
,
279 attr_to_name(F_NODUMP
),
280 xoap
->xoa_nodump
) == 0);
282 if (XVA_ISSET_RTN(&xvattr
, XAT_OPAQUE
)) {
283 VERIFY(nvlist_add_boolean_value(nvlp
,
284 attr_to_name(F_OPAQUE
),
285 xoap
->xoa_opaque
) == 0);
287 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_QUARANTINED
)) {
288 VERIFY(nvlist_add_boolean_value(nvlp
,
289 attr_to_name(F_AV_QUARANTINED
),
290 xoap
->xoa_av_quarantined
) == 0);
292 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_MODIFIED
)) {
293 VERIFY(nvlist_add_boolean_value(nvlp
,
294 attr_to_name(F_AV_MODIFIED
),
295 xoap
->xoa_av_modified
) == 0);
297 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_SCANSTAMP
)) {
298 VERIFY(nvlist_add_uint8_array(nvlp
,
299 attr_to_name(F_AV_SCANSTAMP
),
300 xoap
->xoa_av_scanstamp
,
301 sizeof (xoap
->xoa_av_scanstamp
)) == 0);
303 if (XVA_ISSET_RTN(&xvattr
, XAT_CREATETIME
)) {
304 VERIFY(nvlist_add_uint64_array(nvlp
,
305 attr_to_name(F_CRTIME
),
306 (uint64_t *)&(xoap
->xoa_createtime
),
307 sizeof (xoap
->xoa_createtime
) /
308 sizeof (uint64_t)) == 0);
310 if (XVA_ISSET_RTN(&xvattr
, XAT_REPARSE
)) {
311 VERIFY(nvlist_add_boolean_value(nvlp
,
312 attr_to_name(F_REPARSE
),
313 xoap
->xoa_reparse
) == 0);
317 * Check for optional ownersid/groupsid
320 if (xvattr
.xva_vattr
.va_uid
> MAXUID
) {
323 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
326 if (kidmap_getsidbyuid(crgetzone(cr
), xvattr
.xva_vattr
.va_uid
,
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_OWNERSID
),
334 nvlist_free(nvl_sid
);
336 if (xvattr
.xva_vattr
.va_gid
> MAXUID
) {
339 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
342 if (kidmap_getsidbygid(crgetzone(cr
), xvattr
.xva_vattr
.va_gid
,
343 &domain
, &rid
) == 0) {
344 VERIFY(nvlist_add_string(nvl_sid
,
345 SID_DOMAIN
, domain
) == 0);
346 VERIFY(nvlist_add_uint32(nvl_sid
, SID_RID
, rid
) == 0);
347 VERIFY(nvlist_add_nvlist(nvlp
, attr_to_name(F_GROUPSID
),
350 nvlist_free(nvl_sid
);
357 * The size of a sysattr file is the size of the nvlist that will be
358 * returned by xattr_file_read(). A call to xattr_file_write() could
359 * change the size of that nvlist. That size is not stored persistently
360 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
363 xattr_file_size(vnode_t
*vp
, xattr_view_t xattr_view
, size_t *size
,
364 cred_t
*cr
, caller_context_t
*ct
)
368 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
)) {
372 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
377 VERIFY(nvlist_size(nvl
, size
, NV_ENCODE_XDR
) == 0);
384 xattr_file_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
385 caller_context_t
*ct
)
387 xattr_file_t
*np
= vp
->v_data
;
395 vap
->va_mode
= MAKEIMODE(vap
->va_type
,
396 (np
->xattr_view
== XATTR_VIEW_READONLY
? 0444 : 0644));
397 vap
->va_nodeid
= gfs_file_inode(vp
);
399 pvp
= gfs_file_parent(vp
);
400 (void) memset(&pvattr
, 0, sizeof (pvattr
));
401 pvattr
.va_mask
= AT_CTIME
|AT_MTIME
;
402 error
= VOP_GETATTR(pvp
, &pvattr
, flags
, cr
, ct
);
406 vap
->va_ctime
= pvattr
.va_ctime
;
407 vap
->va_mtime
= pvattr
.va_mtime
;
413 vap
->va_blksize
= DEV_BSIZE
;
415 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
416 error
= xattr_file_size(vp
, np
->xattr_view
, &size
, cr
, ct
);
418 vap
->va_nblocks
= howmany(vap
->va_size
, vap
->va_blksize
);
424 xattr_file_read(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
425 caller_context_t
*ct
)
427 xattr_file_t
*np
= vp
->v_data
;
428 xattr_view_t xattr_view
= np
->xattr_view
;
435 * Validate file offset and fasttrack empty reads
437 if (uiop
->uio_loffset
< (offset_t
)0)
440 if (uiop
->uio_resid
== 0)
443 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
))
446 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
451 VERIFY(nvlist_size(nvl
, &filesize
, NV_ENCODE_XDR
) == 0);
453 if (uiop
->uio_loffset
>= filesize
) {
458 buf
= kmem_alloc(filesize
, KM_SLEEP
);
459 VERIFY(nvlist_pack(nvl
, &buf
, &filesize
, NV_ENCODE_XDR
,
462 error
= uiomove((caddr_t
)buf
, filesize
, UIO_READ
, uiop
);
463 kmem_free(buf
, filesize
);
470 xattr_file_write(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
471 caller_context_t
*ct
)
477 ssize_t size
= uiop
->uio_resid
;
479 nvpair_t
*pair
= NULL
;
482 xoptattr_t
*xoap
= NULL
; /* Pointer to optional attributes */
484 if (vfs_has_feature(vp
->v_vfsp
, VFSFT_XVATTR
) == 0)
488 * Validate file offset and size.
490 if (uiop
->uio_loffset
< (offset_t
)0)
498 if ((xoap
= xva_getxoptattr(&xvattr
)) == NULL
) {
503 * Copy and unpack the nvlist
505 buf
= kmem_alloc(size
, KM_SLEEP
);
506 if (uiomove((caddr_t
)buf
, size
, UIO_WRITE
, uiop
)) {
510 if (nvlist_unpack(buf
, size
, &nvp
, KM_SLEEP
) != 0) {
511 kmem_free(buf
, size
);
512 uiop
->uio_resid
= size
;
515 kmem_free(buf
, size
);
518 * Fasttrack empty writes (nvlist with no nvpairs)
520 if (nvlist_next_nvpair(nvp
, NULL
) == 0)
523 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
525 while (pair
= nvlist_next_nvpair(nvp
, pair
)) {
529 uint64_t *time
, *times
;
535 * Validate the name and type of each attribute.
536 * Log any unknown names and continue. This will
537 * help if additional attributes are added later.
539 type
= nvpair_type(pair
);
540 if ((attr
= name_to_attr(nvpair_name(pair
))) == F_ATTR_INVAL
) {
541 cmn_err(CE_WARN
, "Unknown attribute %s",
547 * Verify nvlist type matches required type and view is OK
550 if (type
!= attr_to_data_type(attr
) ||
551 (attr_to_xattr_view(attr
) == XATTR_VIEW_READONLY
)) {
557 * For OWNERSID/GROUPSID make sure the target
558 * file system support ephemeral ID's
560 if ((attr
== F_OWNERSID
|| attr
== F_GROUPSID
) &&
561 (!(vp
->v_vfsp
->vfs_flag
& VFS_XID
))) {
567 * Retrieve data from nvpair
570 case DATA_TYPE_BOOLEAN_VALUE
:
571 if (nvpair_value_boolean_value(pair
, &value
)) {
576 case DATA_TYPE_UINT64_ARRAY
:
577 if (nvpair_value_uint64_array(pair
, ×
, &nelems
)) {
582 case DATA_TYPE_NVLIST
:
583 if (nvpair_value_nvlist(pair
, &nvp_sid
)) {
588 case DATA_TYPE_UINT8_ARRAY
:
589 if (nvpair_value_uint8_array(pair
,
590 &scanstamp
, &nelems
)) {
602 * If we have several similar optional attributes to
603 * process then we should do it all together here so that
604 * xoap and the requested bitmap can be set in one place.
607 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
608 xoap
->xoa_readonly
= value
;
611 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
612 xoap
->xoa_hidden
= value
;
615 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
616 xoap
->xoa_system
= value
;
619 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
620 xoap
->xoa_archive
= value
;
623 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
624 xoap
->xoa_immutable
= value
;
627 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
628 xoap
->xoa_nounlink
= value
;
631 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
632 xoap
->xoa_appendonly
= value
;
635 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
636 xoap
->xoa_nodump
= value
;
638 case F_AV_QUARANTINED
:
639 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
640 xoap
->xoa_av_quarantined
= value
;
643 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
644 xoap
->xoa_av_modified
= value
;
647 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
648 time
= (uint64_t *)&(xoap
->xoa_createtime
);
649 for (elem
= 0; elem
< nelems
; elem
++)
650 *time
++ = times
[elem
];
654 if (nvlist_lookup_string(nvp_sid
, SID_DOMAIN
,
655 &domain
) || nvlist_lookup_uint32(nvp_sid
, SID_RID
,
662 * Now map domain+rid to ephemeral id's
664 * If mapping fails, then the uid/gid will
665 * be set to UID_NOBODY by Winchester.
668 if (attr
== F_OWNERSID
) {
669 (void) kidmap_getuidbysid(crgetzone(cr
), domain
,
670 rid
, &xvattr
.xva_vattr
.va_uid
);
671 xvattr
.xva_vattr
.va_mask
|= AT_UID
;
673 (void) kidmap_getgidbysid(crgetzone(cr
), domain
,
674 rid
, &xvattr
.xva_vattr
.va_gid
);
675 xvattr
.xva_vattr
.va_mask
|= AT_GID
;
679 if (ppvp
->v_type
== VREG
) {
680 XVA_SET_REQ(&xvattr
, XAT_AV_SCANSTAMP
);
681 (void) memcpy(xoap
->xoa_av_scanstamp
,
689 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
690 xoap
->xoa_reparse
= value
;
697 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
698 error
= VOP_SETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
700 uiop
->uio_resid
= size
;
707 xattr_file_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
708 caller_context_t
*ct
)
711 case _PC_XATTR_EXISTS
:
712 case _PC_SATTR_ENABLED
:
713 case _PC_SATTR_EXISTS
:
717 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
721 vnodeops_t
*xattr_file_ops
;
723 static const fs_operation_def_t xattr_file_tops
[] = {
724 { VOPNAME_OPEN
, { .vop_open
= xattr_file_open
} },
725 { VOPNAME_CLOSE
, { .vop_close
= xattr_file_close
} },
726 { VOPNAME_READ
, { .vop_read
= xattr_file_read
} },
727 { VOPNAME_WRITE
, { .vop_write
= xattr_file_write
} },
728 { VOPNAME_IOCTL
, { .error
= fs_ioctl
} },
729 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_file_getattr
} },
730 { VOPNAME_ACCESS
, { .vop_access
= xattr_file_access
} },
731 { VOPNAME_READDIR
, { .error
= fs_notdir
} },
732 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
733 { VOPNAME_INACTIVE
, { .vop_inactive
= gfs_vop_inactive
} },
734 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
735 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_file_pathconf
} },
736 { VOPNAME_PUTPAGE
, { .error
= fs_putpage
} },
737 { VOPNAME_FSYNC
, { .error
= fs_fsync
} },
742 xattr_mkfile(vnode_t
*pvp
, xattr_view_t xattr_view
)
747 vp
= gfs_file_create(sizeof (xattr_file_t
), pvp
, xattr_file_ops
);
749 np
->xattr_view
= xattr_view
;
750 vp
->v_flag
|= V_SYSATTR
;
755 xattr_mkfile_ro(vnode_t
*pvp
)
757 return (xattr_mkfile(pvp
, XATTR_VIEW_READONLY
));
761 xattr_mkfile_rw(vnode_t
*pvp
)
763 return (xattr_mkfile(pvp
, XATTR_VIEW_READWRITE
));
766 vnodeops_t
*xattr_dir_ops
;
768 static gfs_dirent_t xattr_dirents
[] = {
769 { VIEW_READONLY
, xattr_mkfile_ro
, GFS_CACHE_VNODE
, },
770 { VIEW_READWRITE
, xattr_mkfile_rw
, GFS_CACHE_VNODE
, },
774 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
777 is_sattr_name(char *s
)
781 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
782 if (strcmp(s
, xattr_dirents
[i
].gfse_name
) == 0) {
790 * Given the name of an extended attribute file, determine if there is a
791 * normalization conflict with a sysattr view name.
794 xattr_sysattr_casechk(char *s
)
798 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
799 if (strcasecmp(s
, xattr_dirents
[i
].gfse_name
) == 0)
806 xattr_copy(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
807 cred_t
*cr
, caller_context_t
*ct
)
814 * Only copy system attrs if the views are the same
816 if (strcmp(snm
, tnm
) != 0)
821 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
822 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
823 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
824 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
825 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
826 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
827 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
828 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
829 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
830 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
831 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
832 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
834 pdvp
= gfs_file_parent(sdvp
);
835 error
= VOP_GETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
839 pdvp
= gfs_file_parent(tdvp
);
840 error
= VOP_SETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
845 xattr_dir_realdir(vnode_t
*dvp
, vnode_t
**realdvp
, int lookup_flags
,
846 cred_t
*cr
, caller_context_t
*ct
)
855 pvp
= gfs_file_parent(dvp
);
857 error
= pn_get(startnm
, UIO_SYSSPACE
, &pn
);
864 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
865 * infinite loop with fop_lookup calling back to xattr_dir_lookup.
867 lookup_flags
|= LOOKUP_HAVE_SYSATTR_DIR
;
868 error
= VOP_LOOKUP(pvp
, startnm
, realdvp
, &pn
, lookup_flags
,
869 rootvp
, cr
, ct
, NULL
, NULL
);
877 xattr_dir_open(vnode_t
**vpp
, int flags
, cred_t
*cr
, caller_context_t
*ct
)
879 if (flags
& FWRITE
) {
888 xattr_dir_close(vnode_t
*vpp
, int flags
, int count
, offset_t off
, cred_t
*cr
,
889 caller_context_t
*ct
)
895 * Retrieve the attributes on an xattr directory. If there is a "real"
896 * xattr directory, use that. Otherwise, get the attributes (represented
897 * by PARENT_ATTRMASK) from the "parent" node and fill in the rest. Note
898 * that VOP_GETATTR() could turn off bits in the va_mask.
901 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
905 xattr_dir_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
906 caller_context_t
*ct
)
912 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
914 error
= VOP_GETATTR(pvp
, vap
, 0, cr
, ct
);
919 vap
->va_nlink
+= XATTRDIR_NENTS
;
920 vap
->va_size
+= XATTRDIR_NENTS
;
925 * There is no real xattr directory. Cobble together
926 * an entry using info from the parent object (if needed)
927 * plus information common to all xattrs.
929 if (vap
->va_mask
& PARENT_ATTRMASK
) {
933 pvp
= gfs_file_parent(vp
);
934 (void) memset(&pvattr
, 0, sizeof (pvattr
));
935 pvattr
.va_mask
= PARENT_ATTRMASK
;
936 error
= VOP_GETATTR(pvp
, &pvattr
, 0, cr
, ct
);
942 * VOP_GETATTR() might have turned off some bits in
943 * pvattr.va_mask. This means that the underlying
944 * file system couldn't process those attributes.
945 * We need to make sure those bits get turned off
946 * in the vattr_t structure that gets passed back
947 * to the caller. Figure out which bits were turned
948 * off (if any) then set pvattr.va_mask before it
949 * gets copied to the vattr_t that the caller sees.
951 off_bits
= (pvattr
.va_mask
^ PARENT_ATTRMASK
) & PARENT_ATTRMASK
;
952 pvattr
.va_mask
= vap
->va_mask
& ~off_bits
;
957 vap
->va_mode
= MAKEIMODE(vap
->va_type
, S_ISVTX
| 0777);
958 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
959 vap
->va_nodeid
= gfs_file_inode(vp
);
960 vap
->va_nlink
= XATTRDIR_NENTS
+2;
961 vap
->va_size
= vap
->va_nlink
;
971 xattr_dir_setattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
972 caller_context_t
*ct
)
978 * If there is a real xattr directory, do the setattr there.
979 * Otherwise, just return success. The GFS directory is transient,
980 * and any setattr changes can disappear anyway.
982 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
984 error
= VOP_SETATTR(realvp
, vap
, flags
, cr
, ct
);
987 if (error
== ENOENT
) {
995 xattr_dir_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
996 caller_context_t
*ct
)
999 vnode_t
*realvp
= NULL
;
1001 if (mode
& VWRITE
) {
1005 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1011 * No real xattr dir isn't an error
1012 * an error of EINVAL indicates attributes on attributes
1013 * are not supported. In that case just allow access to the
1014 * transient directory.
1016 return ((error
== ENOENT
|| error
== EINVAL
) ? 0 : error
);
1020 xattr_dir_create(vnode_t
*dvp
, char *name
, vattr_t
*vap
, vcexcl_t excl
,
1021 int mode
, vnode_t
**vpp
, cred_t
*cr
, int flag
, caller_context_t
*ct
,
1030 * Don't allow creation of extended attributes with sysattr names.
1032 if (is_sattr_name(name
)) {
1033 return (gfs_dir_lookup(dvp
, name
, vpp
, cr
, 0, NULL
, NULL
));
1036 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1039 error
= VOP_CREATE(pvp
, name
, vap
, excl
, mode
, vpp
, cr
, flag
,
1047 xattr_dir_remove(vnode_t
*dvp
, char *name
, cred_t
*cr
, caller_context_t
*ct
,
1053 if (is_sattr_name(name
)) {
1057 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1059 error
= VOP_REMOVE(pvp
, name
, cr
, ct
, flags
);
1066 xattr_dir_link(vnode_t
*tdvp
, vnode_t
*svp
, char *name
, cred_t
*cr
,
1067 caller_context_t
*ct
, int flags
)
1072 if (svp
->v_flag
& V_SYSATTR
) {
1076 error
= xattr_dir_realdir(tdvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1078 error
= VOP_LINK(pvp
, svp
, name
, cr
, ct
, flags
);
1085 xattr_dir_rename(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
1086 cred_t
*cr
, caller_context_t
*ct
, int flags
)
1088 vnode_t
*spvp
, *tpvp
;
1092 if (is_sattr_name(snm
) || is_sattr_name(tnm
))
1093 return (xattr_copy(sdvp
, snm
, tdvp
, tnm
, cr
, ct
));
1095 * We know that sdvp is a GFS dir, or we wouldn't be here.
1096 * Get the real unnamed directory.
1098 error
= xattr_dir_realdir(sdvp
, &spvp
, LOOKUP_XATTR
, cr
, ct
);
1105 * If the source and target are the same GFS directory, the
1106 * underlying unnamed source and target dir will be the same.
1111 } else if (tdvp
->v_flag
& V_SYSATTR
) {
1113 * If the target dir is a different GFS directory,
1114 * find its underlying unnamed dir.
1116 error
= xattr_dir_realdir(tdvp
, &tpvp
, LOOKUP_XATTR
, cr
, ct
);
1124 * Target dir is outside of GFS, pass it on through.
1130 error
= VOP_RENAME(spvp
, snm
, tpvp
, tnm
, cr
, ct
, flags
);
1141 * readdir_xattr_casecmp: given a system attribute name, see if there
1142 * is a real xattr with the same normalized name.
1145 readdir_xattr_casecmp(vnode_t
*dvp
, char *nm
, cred_t
*cr
, caller_context_t
*ct
,
1154 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1156 error
= VOP_LOOKUP(dvp
, nm
, &vp
, &pn
,
1157 FIGNORECASE
, rootvp
, cr
, ct
, NULL
, NULL
);
1159 *eflags
= ED_CASE_CONFLICT
;
1161 } else if (error
== ENOENT
) {
1171 xattr_dir_readdir(vnode_t
*dvp
, uio_t
*uiop
, cred_t
*cr
, int *eofp
,
1172 caller_context_t
*ct
, int flags
)
1186 * See if there is a real extended attribute directory.
1188 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1194 * Start by reading up the static entries.
1196 if (uiop
->uio_loffset
== 0) {
1199 gfs_dir_t
*dp
= dvp
->v_data
;
1200 gfs_readdir_state_t gstate
;
1204 * If there is a real xattr dir, skip . and ..
1205 * in the GFS dir. We'll pick them up below
1206 * when we call into the underlying fs.
1208 uiop
->uio_loffset
= GFS_STATIC_ENTRY_OFFSET
;
1210 error
= gfs_get_parent_ino(dvp
, cr
, ct
, &pino
, &ino
);
1212 error
= gfs_readdir_init(&gstate
, dp
->gfsd_maxlen
, 1,
1213 uiop
, pino
, ino
, flags
);
1221 while ((error
= gfs_readdir_pred(&gstate
, uiop
, &off
)) == 0 &&
1223 if (off
>= 0 && off
< dp
->gfsd_nstatic
) {
1227 * Check to see if this sysattr set name has a
1228 * case-insensitive conflict with a real xattr
1232 if ((flags
& V_RDDIR_ENTFLAGS
) && has_xattrs
) {
1233 error
= readdir_xattr_casecmp(pvp
,
1234 dp
->gfsd_static
[off
].gfse_name
,
1239 ino
= dp
->gfsd_inode(dvp
, off
);
1241 error
= gfs_readdir_emit(&gstate
, uiop
, off
,
1242 ino
, dp
->gfsd_static
[off
].gfse_name
,
1251 error
= gfs_readdir_fini(&gstate
, error
, eofp
, *eofp
);
1259 * We must read all of the static entries in the first
1260 * call. Otherwise we won't know if uio_loffset in a
1261 * subsequent call refers to the static entries or to those
1262 * in an underlying fs.
1276 uiop
->uio_loffset
= 0;
1278 (void) VOP_RWLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1279 error
= VOP_READDIR(pvp
, uiop
, cr
, eofp
, ct
, flags
);
1280 VOP_RWUNLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1288 xattr_dir_inactive(vnode_t
*vp
, cred_t
*cr
, caller_context_t
*ct
)
1291 xattr_dir_t
*xattr_dir
;
1293 mutex_enter(&vp
->v_lock
);
1294 xattr_dir
= vp
->v_data
;
1295 if (xattr_dir
->xattr_realvp
) {
1296 VN_RELE(xattr_dir
->xattr_realvp
);
1297 xattr_dir
->xattr_realvp
= NULL
;
1299 mutex_exit(&vp
->v_lock
);
1300 fp
= gfs_dir_inactive(vp
);
1302 kmem_free(fp
, fp
->gfs_size
);
1307 xattr_dir_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
1308 caller_context_t
*ct
)
1311 case _PC_XATTR_EXISTS
:
1312 case _PC_SATTR_ENABLED
:
1313 case _PC_SATTR_EXISTS
:
1317 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
1323 xattr_dir_realvp(vnode_t
*vp
, vnode_t
**realvp
, caller_context_t
*ct
)
1325 xattr_dir_t
*xattr_dir
;
1327 mutex_enter(&vp
->v_lock
);
1328 xattr_dir
= vp
->v_data
;
1329 if (xattr_dir
->xattr_realvp
) {
1330 *realvp
= xattr_dir
->xattr_realvp
;
1331 mutex_exit(&vp
->v_lock
);
1337 mutex_exit(&vp
->v_lock
);
1338 if ((error
= xattr_dir_realdir(vp
, &xdvp
,
1339 LOOKUP_XATTR
, kcred
, NULL
)) == 0) {
1341 * verify we aren't racing with another thread
1342 * to find the xattr_realvp
1344 mutex_enter(&vp
->v_lock
);
1345 if (xattr_dir
->xattr_realvp
== NULL
) {
1346 xattr_dir
->xattr_realvp
= xdvp
;
1348 mutex_exit(&vp
->v_lock
);
1350 *realvp
= xattr_dir
->xattr_realvp
;
1351 mutex_exit(&vp
->v_lock
);
1359 static const fs_operation_def_t xattr_dir_tops
[] = {
1360 { VOPNAME_OPEN
, { .vop_open
= xattr_dir_open
} },
1361 { VOPNAME_CLOSE
, { .vop_close
= xattr_dir_close
} },
1362 { VOPNAME_IOCTL
, { .error
= fs_inval
} },
1363 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_dir_getattr
} },
1364 { VOPNAME_SETATTR
, { .vop_setattr
= xattr_dir_setattr
} },
1365 { VOPNAME_ACCESS
, { .vop_access
= xattr_dir_access
} },
1366 { VOPNAME_READDIR
, { .vop_readdir
= xattr_dir_readdir
} },
1367 { VOPNAME_LOOKUP
, { .vop_lookup
= gfs_vop_lookup
} },
1368 { VOPNAME_CREATE
, { .vop_create
= xattr_dir_create
} },
1369 { VOPNAME_REMOVE
, { .vop_remove
= xattr_dir_remove
} },
1370 { VOPNAME_LINK
, { .vop_link
= xattr_dir_link
} },
1371 { VOPNAME_RENAME
, { .vop_rename
= xattr_dir_rename
} },
1372 { VOPNAME_MKDIR
, { .error
= fs_inval
} },
1373 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
1374 { VOPNAME_INACTIVE
, { .vop_inactive
= xattr_dir_inactive
} },
1375 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
1376 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_dir_pathconf
} },
1377 { VOPNAME_REALVP
, { .vop_realvp
= xattr_dir_realvp
} },
1381 static gfs_opsvec_t xattr_opsvec
[] = {
1382 { "xattr dir", xattr_dir_tops
, &xattr_dir_ops
},
1383 { "system attributes", xattr_file_tops
, &xattr_file_ops
},
1384 { NULL
, NULL
, NULL
}
1388 xattr_lookup_cb(vnode_t
*vp
, const char *nm
, vnode_t
**vpp
, ino64_t
*inop
,
1389 cred_t
*cr
, int flags
, int *deflags
, pathname_t
*rpnp
)
1398 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1402 * Return ENOENT for EACCES requests during lookup. Once an
1403 * attribute create is attempted EACCES will be returned.
1406 if (error
== EACCES
)
1411 error
= pn_get((char *)nm
, UIO_SYSSPACE
, &pn
);
1413 error
= VOP_LOOKUP(pvp
, (char *)nm
, vpp
, &pn
, flags
, rootvp
,
1414 cr
, NULL
, deflags
, rpnp
);
1424 xattrdir_do_ino(vnode_t
*vp
, int index
)
1427 * We use index 0 for the directory fid. Start
1428 * the file numbering at 1.
1430 return ((ino64_t
)index
+1);
1436 VERIFY(gfs_make_opsvec(xattr_opsvec
) == 0);
1440 xattr_dir_lookup(vnode_t
*dvp
, vnode_t
**vpp
, int flags
, cred_t
*cr
)
1446 if (dvp
->v_type
!= VDIR
&& dvp
->v_type
!= VREG
)
1449 mutex_enter(&dvp
->v_lock
);
1452 * If we're already in sysattr space, don't allow creation
1453 * of another level of sysattrs.
1455 if (dvp
->v_flag
& V_SYSATTR
) {
1456 mutex_exit(&dvp
->v_lock
);
1460 if (dvp
->v_xattrdir
!= NULL
) {
1461 *vpp
= dvp
->v_xattrdir
;
1465 int xattrs_allowed
= dvp
->v_vfsp
->vfs_flag
& VFS_XATTR
;
1466 int sysattrs_allowed
= 1;
1469 * We have to drop the lock on dvp. gfs_dir_create will
1470 * grab it for a VN_HOLD.
1472 mutex_exit(&dvp
->v_lock
);
1475 * If dvp allows xattr creation, but not sysattr
1476 * creation, return the real xattr dir vp. We can't
1477 * use the vfs feature mask here because _PC_SATTR_ENABLED
1478 * has vnode-level granularity (e.g. .zfs).
1480 error
= VOP_PATHCONF(dvp
, _PC_SATTR_ENABLED
, &val
, cr
, NULL
);
1481 if (error
!= 0 || val
== 0)
1482 sysattrs_allowed
= 0;
1484 if (!xattrs_allowed
&& !sysattrs_allowed
)
1487 if (!sysattrs_allowed
) {
1491 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1494 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
,
1495 flags
|LOOKUP_HAVE_SYSATTR_DIR
, rootvp
, cr
, NULL
,
1502 * Note that we act as if we were given CREATE_XATTR_DIR,
1503 * but only for creation of the GFS directory.
1505 *vpp
= gfs_dir_create(
1506 sizeof (xattr_dir_t
), dvp
, xattr_dir_ops
, xattr_dirents
,
1507 xattrdir_do_ino
, MAXNAMELEN
, NULL
, xattr_lookup_cb
);
1508 mutex_enter(&dvp
->v_lock
);
1509 if (dvp
->v_xattrdir
!= NULL
) {
1511 * We lost the race to create the xattr dir.
1512 * Destroy this one, use the winner. We can't
1513 * just call VN_RELE(*vpp), because the vnode
1514 * is only partially initialized.
1516 gfs_dir_t
*dp
= (*vpp
)->v_data
;
1518 ASSERT((*vpp
)->v_count
== 1);
1521 mutex_destroy(&dp
->gfsd_lock
);
1522 kmem_free(dp
->gfsd_static
,
1523 dp
->gfsd_nstatic
* sizeof (gfs_dirent_t
));
1524 kmem_free(dp
, dp
->gfsd_file
.gfs_size
);
1527 * There is an implied VN_HOLD(dvp) here. We should
1528 * be doing a VN_RELE(dvp) to clean up the reference
1529 * from *vpp, and then a VN_HOLD(dvp) for the new
1530 * reference. Instead, we just leave the count alone.
1533 *vpp
= dvp
->v_xattrdir
;
1536 (*vpp
)->v_flag
|= (V_XATTRDIR
|V_SYSATTR
);
1537 dvp
->v_xattrdir
= *vpp
;
1540 mutex_exit(&dvp
->v_lock
);
1546 xattr_dir_vget(vfs_t
*vfsp
, vnode_t
**vpp
, fid_t
*fidp
)
1557 if (fidp
->fid_len
< XATTR_FIDSZ
)
1560 xfidp
= (xattr_fid_t
*)fidp
;
1561 orig_len
= fidp
->fid_len
;
1562 fidp
->fid_len
= xfidp
->parent_len
;
1564 error
= VFS_VGET(vfsp
, &pvp
, fidp
);
1565 fidp
->fid_len
= orig_len
;
1570 * Start by getting the GFS sysattr directory. We might need
1571 * to recreate it during the VOP_LOOKUP.
1574 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1580 error
= VOP_LOOKUP(pvp
, nm
, &dvp
, &pn
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1581 rootvp
, CRED(), NULL
, NULL
, NULL
);
1587 if (xfidp
->dir_offset
== 0) {
1589 * If we were looking for the directory, we're done.
1595 if (xfidp
->dir_offset
> XATTRDIR_NENTS
) {
1600 nm
= xattr_dirents
[xfidp
->dir_offset
- 1].gfse_name
;
1602 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1608 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
, 0, rootvp
, CRED(), NULL
,