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
);
229 XVA_SET_REQ(&xvattr
, XAT_GEN
);
232 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
235 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
242 error
= VOP_GETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
247 * Process all the optional attributes together here. Notice that
248 * xoap was set when the optional attribute bits were set above.
250 if ((xvattr
.xva_vattr
.va_mask
& AT_XVATTR
) && xoap
) {
251 if (XVA_ISSET_RTN(&xvattr
, XAT_READONLY
)) {
252 VERIFY(nvlist_add_boolean_value(nvlp
,
253 attr_to_name(F_READONLY
),
254 xoap
->xoa_readonly
) == 0);
256 if (XVA_ISSET_RTN(&xvattr
, XAT_HIDDEN
)) {
257 VERIFY(nvlist_add_boolean_value(nvlp
,
258 attr_to_name(F_HIDDEN
),
259 xoap
->xoa_hidden
) == 0);
261 if (XVA_ISSET_RTN(&xvattr
, XAT_SYSTEM
)) {
262 VERIFY(nvlist_add_boolean_value(nvlp
,
263 attr_to_name(F_SYSTEM
),
264 xoap
->xoa_system
) == 0);
266 if (XVA_ISSET_RTN(&xvattr
, XAT_ARCHIVE
)) {
267 VERIFY(nvlist_add_boolean_value(nvlp
,
268 attr_to_name(F_ARCHIVE
),
269 xoap
->xoa_archive
) == 0);
271 if (XVA_ISSET_RTN(&xvattr
, XAT_IMMUTABLE
)) {
272 VERIFY(nvlist_add_boolean_value(nvlp
,
273 attr_to_name(F_IMMUTABLE
),
274 xoap
->xoa_immutable
) == 0);
276 if (XVA_ISSET_RTN(&xvattr
, XAT_NOUNLINK
)) {
277 VERIFY(nvlist_add_boolean_value(nvlp
,
278 attr_to_name(F_NOUNLINK
),
279 xoap
->xoa_nounlink
) == 0);
281 if (XVA_ISSET_RTN(&xvattr
, XAT_APPENDONLY
)) {
282 VERIFY(nvlist_add_boolean_value(nvlp
,
283 attr_to_name(F_APPENDONLY
),
284 xoap
->xoa_appendonly
) == 0);
286 if (XVA_ISSET_RTN(&xvattr
, XAT_NODUMP
)) {
287 VERIFY(nvlist_add_boolean_value(nvlp
,
288 attr_to_name(F_NODUMP
),
289 xoap
->xoa_nodump
) == 0);
291 if (XVA_ISSET_RTN(&xvattr
, XAT_OPAQUE
)) {
292 VERIFY(nvlist_add_boolean_value(nvlp
,
293 attr_to_name(F_OPAQUE
),
294 xoap
->xoa_opaque
) == 0);
296 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_QUARANTINED
)) {
297 VERIFY(nvlist_add_boolean_value(nvlp
,
298 attr_to_name(F_AV_QUARANTINED
),
299 xoap
->xoa_av_quarantined
) == 0);
301 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_MODIFIED
)) {
302 VERIFY(nvlist_add_boolean_value(nvlp
,
303 attr_to_name(F_AV_MODIFIED
),
304 xoap
->xoa_av_modified
) == 0);
306 if (XVA_ISSET_RTN(&xvattr
, XAT_AV_SCANSTAMP
)) {
307 VERIFY(nvlist_add_uint8_array(nvlp
,
308 attr_to_name(F_AV_SCANSTAMP
),
309 xoap
->xoa_av_scanstamp
,
310 sizeof (xoap
->xoa_av_scanstamp
)) == 0);
312 if (XVA_ISSET_RTN(&xvattr
, XAT_CREATETIME
)) {
313 VERIFY(nvlist_add_uint64_array(nvlp
,
314 attr_to_name(F_CRTIME
),
315 (uint64_t *)&(xoap
->xoa_createtime
),
316 sizeof (xoap
->xoa_createtime
) /
317 sizeof (uint64_t)) == 0);
319 if (XVA_ISSET_RTN(&xvattr
, XAT_REPARSE
)) {
320 VERIFY(nvlist_add_boolean_value(nvlp
,
321 attr_to_name(F_REPARSE
),
322 xoap
->xoa_reparse
) == 0);
324 if (XVA_ISSET_RTN(&xvattr
, XAT_GEN
)) {
325 VERIFY(nvlist_add_uint64(nvlp
,
327 xoap
->xoa_generation
) == 0);
329 if (XVA_ISSET_RTN(&xvattr
, XAT_OFFLINE
)) {
330 VERIFY(nvlist_add_boolean_value(nvlp
,
331 attr_to_name(F_OFFLINE
),
332 xoap
->xoa_offline
) == 0);
334 if (XVA_ISSET_RTN(&xvattr
, XAT_SPARSE
)) {
335 VERIFY(nvlist_add_boolean_value(nvlp
,
336 attr_to_name(F_SPARSE
),
337 xoap
->xoa_sparse
) == 0);
341 * Check for optional ownersid/groupsid
344 if (xvattr
.xva_vattr
.va_uid
> MAXUID
) {
347 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
350 if (kidmap_getsidbyuid(crgetzone(cr
), xvattr
.xva_vattr
.va_uid
,
351 &domain
, &rid
) == 0) {
352 VERIFY(nvlist_add_string(nvl_sid
,
353 SID_DOMAIN
, domain
) == 0);
354 VERIFY(nvlist_add_uint32(nvl_sid
, SID_RID
, rid
) == 0);
355 VERIFY(nvlist_add_nvlist(nvlp
, attr_to_name(F_OWNERSID
),
358 nvlist_free(nvl_sid
);
360 if (xvattr
.xva_vattr
.va_gid
> MAXUID
) {
363 if (nvlist_alloc(&nvl_sid
, NV_UNIQUE_NAME
, KM_SLEEP
))
366 if (kidmap_getsidbygid(crgetzone(cr
), xvattr
.xva_vattr
.va_gid
,
367 &domain
, &rid
) == 0) {
368 VERIFY(nvlist_add_string(nvl_sid
,
369 SID_DOMAIN
, domain
) == 0);
370 VERIFY(nvlist_add_uint32(nvl_sid
, SID_RID
, rid
) == 0);
371 VERIFY(nvlist_add_nvlist(nvlp
, attr_to_name(F_GROUPSID
),
374 nvlist_free(nvl_sid
);
381 * The size of a sysattr file is the size of the nvlist that will be
382 * returned by xattr_file_read(). A call to xattr_file_write() could
383 * change the size of that nvlist. That size is not stored persistently
384 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
387 xattr_file_size(vnode_t
*vp
, xattr_view_t xattr_view
, size_t *size
,
388 cred_t
*cr
, caller_context_t
*ct
)
392 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
)) {
396 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
401 VERIFY(nvlist_size(nvl
, size
, NV_ENCODE_XDR
) == 0);
408 xattr_file_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
409 caller_context_t
*ct
)
411 xattr_file_t
*np
= vp
->v_data
;
419 vap
->va_mode
= MAKEIMODE(vap
->va_type
,
420 (np
->xattr_view
== XATTR_VIEW_READONLY
? 0444 : 0644));
421 vap
->va_nodeid
= gfs_file_inode(vp
);
423 pvp
= gfs_file_parent(vp
);
424 (void) memset(&pvattr
, 0, sizeof (pvattr
));
425 pvattr
.va_mask
= AT_CTIME
|AT_MTIME
;
426 error
= VOP_GETATTR(pvp
, &pvattr
, flags
, cr
, ct
);
430 vap
->va_ctime
= pvattr
.va_ctime
;
431 vap
->va_mtime
= pvattr
.va_mtime
;
437 vap
->va_blksize
= DEV_BSIZE
;
439 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
440 error
= xattr_file_size(vp
, np
->xattr_view
, &size
, cr
, ct
);
442 vap
->va_nblocks
= howmany(vap
->va_size
, vap
->va_blksize
);
448 xattr_file_read(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
449 caller_context_t
*ct
)
451 xattr_file_t
*np
= vp
->v_data
;
452 xattr_view_t xattr_view
= np
->xattr_view
;
459 * Validate file offset and fasttrack empty reads
461 if (uiop
->uio_loffset
< (offset_t
)0)
464 if (uiop
->uio_resid
== 0)
467 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, KM_SLEEP
))
470 if (xattr_fill_nvlist(vp
, xattr_view
, nvl
, cr
, ct
)) {
475 VERIFY(nvlist_size(nvl
, &filesize
, NV_ENCODE_XDR
) == 0);
477 if (uiop
->uio_loffset
>= filesize
) {
482 buf
= kmem_alloc(filesize
, KM_SLEEP
);
483 VERIFY(nvlist_pack(nvl
, &buf
, &filesize
, NV_ENCODE_XDR
,
486 error
= uiomove((caddr_t
)buf
, filesize
, UIO_READ
, uiop
);
487 kmem_free(buf
, filesize
);
494 xattr_file_write(vnode_t
*vp
, uio_t
*uiop
, int ioflag
, cred_t
*cr
,
495 caller_context_t
*ct
)
501 ssize_t size
= uiop
->uio_resid
;
503 nvpair_t
*pair
= NULL
;
506 xoptattr_t
*xoap
= NULL
; /* Pointer to optional attributes */
508 if (vfs_has_feature(vp
->v_vfsp
, VFSFT_XVATTR
) == 0)
512 * Validate file offset and size.
514 if (uiop
->uio_loffset
< (offset_t
)0)
522 if ((xoap
= xva_getxoptattr(&xvattr
)) == NULL
) {
527 * Copy and unpack the nvlist
529 buf
= kmem_alloc(size
, KM_SLEEP
);
530 if (uiomove((caddr_t
)buf
, size
, UIO_WRITE
, uiop
)) {
534 if (nvlist_unpack(buf
, size
, &nvp
, KM_SLEEP
) != 0) {
535 kmem_free(buf
, size
);
536 uiop
->uio_resid
= size
;
539 kmem_free(buf
, size
);
542 * Fasttrack empty writes (nvlist with no nvpairs)
544 if (nvlist_next_nvpair(nvp
, NULL
) == 0)
547 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
549 while (pair
= nvlist_next_nvpair(nvp
, pair
)) {
553 uint64_t *time
, *times
;
559 * Validate the name and type of each attribute.
560 * Log any unknown names and continue. This will
561 * help if additional attributes are added later.
563 type
= nvpair_type(pair
);
564 if ((attr
= name_to_attr(nvpair_name(pair
))) == F_ATTR_INVAL
) {
565 cmn_err(CE_WARN
, "Unknown attribute %s",
571 * Verify nvlist type matches required type and view is OK
574 if (type
!= attr_to_data_type(attr
) ||
575 (attr_to_xattr_view(attr
) == XATTR_VIEW_READONLY
)) {
581 * For OWNERSID/GROUPSID make sure the target
582 * file system support ephemeral ID's
584 if ((attr
== F_OWNERSID
|| attr
== F_GROUPSID
) &&
585 (!(vp
->v_vfsp
->vfs_flag
& VFS_XID
))) {
591 * Retrieve data from nvpair
594 case DATA_TYPE_BOOLEAN_VALUE
:
595 if (nvpair_value_boolean_value(pair
, &value
)) {
600 case DATA_TYPE_UINT64_ARRAY
:
601 if (nvpair_value_uint64_array(pair
, ×
, &nelems
)) {
606 case DATA_TYPE_NVLIST
:
607 if (nvpair_value_nvlist(pair
, &nvp_sid
)) {
612 case DATA_TYPE_UINT8_ARRAY
:
613 if (nvpair_value_uint8_array(pair
,
614 &scanstamp
, &nelems
)) {
626 * If we have several similar optional attributes to
627 * process then we should do it all together here so that
628 * xoap and the requested bitmap can be set in one place.
631 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
632 xoap
->xoa_readonly
= value
;
635 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
636 xoap
->xoa_hidden
= value
;
639 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
640 xoap
->xoa_system
= value
;
643 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
644 xoap
->xoa_archive
= value
;
647 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
648 xoap
->xoa_immutable
= value
;
651 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
652 xoap
->xoa_nounlink
= value
;
655 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
656 xoap
->xoa_appendonly
= value
;
659 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
660 xoap
->xoa_nodump
= value
;
662 case F_AV_QUARANTINED
:
663 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
664 xoap
->xoa_av_quarantined
= value
;
667 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
668 xoap
->xoa_av_modified
= value
;
671 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
672 time
= (uint64_t *)&(xoap
->xoa_createtime
);
673 for (elem
= 0; elem
< nelems
; elem
++)
674 *time
++ = times
[elem
];
678 if (nvlist_lookup_string(nvp_sid
, SID_DOMAIN
,
679 &domain
) || nvlist_lookup_uint32(nvp_sid
, SID_RID
,
686 * Now map domain+rid to ephemeral id's
688 * If mapping fails, then the uid/gid will
689 * be set to UID_NOBODY by Winchester.
692 if (attr
== F_OWNERSID
) {
693 (void) kidmap_getuidbysid(crgetzone(cr
), domain
,
694 rid
, &xvattr
.xva_vattr
.va_uid
);
695 xvattr
.xva_vattr
.va_mask
|= AT_UID
;
697 (void) kidmap_getgidbysid(crgetzone(cr
), domain
,
698 rid
, &xvattr
.xva_vattr
.va_gid
);
699 xvattr
.xva_vattr
.va_mask
|= AT_GID
;
703 if (ppvp
->v_type
== VREG
) {
704 XVA_SET_REQ(&xvattr
, XAT_AV_SCANSTAMP
);
705 (void) memcpy(xoap
->xoa_av_scanstamp
,
713 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
714 xoap
->xoa_reparse
= value
;
717 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
718 xoap
->xoa_offline
= value
;
721 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
722 xoap
->xoa_sparse
= value
;
729 ppvp
= gfs_file_parent(gfs_file_parent(vp
));
730 error
= VOP_SETATTR(ppvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
732 uiop
->uio_resid
= size
;
739 xattr_file_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
740 caller_context_t
*ct
)
743 case _PC_XATTR_EXISTS
:
744 case _PC_SATTR_ENABLED
:
745 case _PC_SATTR_EXISTS
:
749 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
753 vnodeops_t
*xattr_file_ops
;
755 static const fs_operation_def_t xattr_file_tops
[] = {
756 { VOPNAME_OPEN
, { .vop_open
= xattr_file_open
} },
757 { VOPNAME_CLOSE
, { .vop_close
= xattr_file_close
} },
758 { VOPNAME_READ
, { .vop_read
= xattr_file_read
} },
759 { VOPNAME_WRITE
, { .vop_write
= xattr_file_write
} },
760 { VOPNAME_IOCTL
, { .error
= fs_ioctl
} },
761 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_file_getattr
} },
762 { VOPNAME_ACCESS
, { .vop_access
= xattr_file_access
} },
763 { VOPNAME_READDIR
, { .error
= fs_notdir
} },
764 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
765 { VOPNAME_INACTIVE
, { .vop_inactive
= gfs_vop_inactive
} },
766 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
767 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_file_pathconf
} },
768 { VOPNAME_PUTPAGE
, { .error
= fs_putpage
} },
769 { VOPNAME_FSYNC
, { .error
= fs_fsync
} },
774 xattr_mkfile(vnode_t
*pvp
, xattr_view_t xattr_view
)
779 vp
= gfs_file_create(sizeof (xattr_file_t
), pvp
, xattr_file_ops
);
781 np
->xattr_view
= xattr_view
;
782 vp
->v_flag
|= V_SYSATTR
;
787 xattr_mkfile_ro(vnode_t
*pvp
)
789 return (xattr_mkfile(pvp
, XATTR_VIEW_READONLY
));
793 xattr_mkfile_rw(vnode_t
*pvp
)
795 return (xattr_mkfile(pvp
, XATTR_VIEW_READWRITE
));
798 vnodeops_t
*xattr_dir_ops
;
800 static gfs_dirent_t xattr_dirents
[] = {
801 { VIEW_READONLY
, xattr_mkfile_ro
, GFS_CACHE_VNODE
, },
802 { VIEW_READWRITE
, xattr_mkfile_rw
, GFS_CACHE_VNODE
, },
806 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
809 is_sattr_name(char *s
)
813 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
814 if (strcmp(s
, xattr_dirents
[i
].gfse_name
) == 0) {
822 * Given the name of an extended attribute file, determine if there is a
823 * normalization conflict with a sysattr view name.
826 xattr_sysattr_casechk(char *s
)
830 for (i
= 0; i
< XATTRDIR_NENTS
; ++i
) {
831 if (strcasecmp(s
, xattr_dirents
[i
].gfse_name
) == 0)
838 xattr_copy(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
839 cred_t
*cr
, caller_context_t
*ct
)
846 * Only copy system attrs if the views are the same
848 if (strcmp(snm
, tnm
) != 0)
853 XVA_SET_REQ(&xvattr
, XAT_SYSTEM
);
854 XVA_SET_REQ(&xvattr
, XAT_READONLY
);
855 XVA_SET_REQ(&xvattr
, XAT_HIDDEN
);
856 XVA_SET_REQ(&xvattr
, XAT_ARCHIVE
);
857 XVA_SET_REQ(&xvattr
, XAT_APPENDONLY
);
858 XVA_SET_REQ(&xvattr
, XAT_NOUNLINK
);
859 XVA_SET_REQ(&xvattr
, XAT_IMMUTABLE
);
860 XVA_SET_REQ(&xvattr
, XAT_NODUMP
);
861 XVA_SET_REQ(&xvattr
, XAT_AV_MODIFIED
);
862 XVA_SET_REQ(&xvattr
, XAT_AV_QUARANTINED
);
863 XVA_SET_REQ(&xvattr
, XAT_CREATETIME
);
864 XVA_SET_REQ(&xvattr
, XAT_REPARSE
);
865 XVA_SET_REQ(&xvattr
, XAT_OFFLINE
);
866 XVA_SET_REQ(&xvattr
, XAT_SPARSE
);
868 pdvp
= gfs_file_parent(sdvp
);
869 error
= VOP_GETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
873 pdvp
= gfs_file_parent(tdvp
);
874 error
= VOP_SETATTR(pdvp
, &xvattr
.xva_vattr
, 0, cr
, ct
);
879 xattr_dir_realdir(vnode_t
*dvp
, vnode_t
**realdvp
, int lookup_flags
,
880 cred_t
*cr
, caller_context_t
*ct
)
889 pvp
= gfs_file_parent(dvp
);
891 error
= pn_get(startnm
, UIO_SYSSPACE
, &pn
);
898 * Set the LOOKUP_HAVE_SYSATTR_DIR flag so that we don't get into an
899 * infinite loop with fop_lookup calling back to xattr_dir_lookup.
901 lookup_flags
|= LOOKUP_HAVE_SYSATTR_DIR
;
902 error
= VOP_LOOKUP(pvp
, startnm
, realdvp
, &pn
, lookup_flags
,
903 rootvp
, cr
, ct
, NULL
, NULL
);
911 xattr_dir_open(vnode_t
**vpp
, int flags
, cred_t
*cr
, caller_context_t
*ct
)
913 if (flags
& FWRITE
) {
922 xattr_dir_close(vnode_t
*vpp
, int flags
, int count
, offset_t off
, cred_t
*cr
,
923 caller_context_t
*ct
)
929 * Retrieve the attributes on an xattr directory. If there is a "real"
930 * xattr directory, use that. Otherwise, get the attributes (represented
931 * by PARENT_ATTRMASK) from the "parent" node and fill in the rest. Note
932 * that VOP_GETATTR() could turn off bits in the va_mask.
935 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
939 xattr_dir_getattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
940 caller_context_t
*ct
)
946 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
948 error
= VOP_GETATTR(pvp
, vap
, 0, cr
, ct
);
953 vap
->va_nlink
+= XATTRDIR_NENTS
;
954 vap
->va_size
+= XATTRDIR_NENTS
;
959 * There is no real xattr directory. Cobble together
960 * an entry using info from the parent object (if needed)
961 * plus information common to all xattrs.
963 if (vap
->va_mask
& PARENT_ATTRMASK
) {
967 pvp
= gfs_file_parent(vp
);
968 (void) memset(&pvattr
, 0, sizeof (pvattr
));
969 pvattr
.va_mask
= PARENT_ATTRMASK
;
970 error
= VOP_GETATTR(pvp
, &pvattr
, 0, cr
, ct
);
976 * VOP_GETATTR() might have turned off some bits in
977 * pvattr.va_mask. This means that the underlying
978 * file system couldn't process those attributes.
979 * We need to make sure those bits get turned off
980 * in the vattr_t structure that gets passed back
981 * to the caller. Figure out which bits were turned
982 * off (if any) then set pvattr.va_mask before it
983 * gets copied to the vattr_t that the caller sees.
985 off_bits
= (pvattr
.va_mask
^ PARENT_ATTRMASK
) & PARENT_ATTRMASK
;
986 pvattr
.va_mask
= vap
->va_mask
& ~off_bits
;
991 vap
->va_mode
= MAKEIMODE(vap
->va_type
, S_ISVTX
| 0777);
992 vap
->va_fsid
= vp
->v_vfsp
->vfs_dev
;
993 vap
->va_nodeid
= gfs_file_inode(vp
);
994 vap
->va_nlink
= XATTRDIR_NENTS
+2;
995 vap
->va_size
= vap
->va_nlink
;
1005 xattr_dir_setattr(vnode_t
*vp
, vattr_t
*vap
, int flags
, cred_t
*cr
,
1006 caller_context_t
*ct
)
1012 * If there is a real xattr directory, do the setattr there.
1013 * Otherwise, just return success. The GFS directory is transient,
1014 * and any setattr changes can disappear anyway.
1016 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1018 error
= VOP_SETATTR(realvp
, vap
, flags
, cr
, ct
);
1021 if (error
== ENOENT
) {
1029 xattr_dir_access(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
,
1030 caller_context_t
*ct
)
1033 vnode_t
*realvp
= NULL
;
1035 if (mode
& VWRITE
) {
1039 error
= xattr_dir_realdir(vp
, &realvp
, LOOKUP_XATTR
, cr
, ct
);
1045 * No real xattr dir isn't an error
1046 * an error of EINVAL indicates attributes on attributes
1047 * are not supported. In that case just allow access to the
1048 * transient directory.
1050 return ((error
== ENOENT
|| error
== EINVAL
) ? 0 : error
);
1054 xattr_dir_create(vnode_t
*dvp
, char *name
, vattr_t
*vap
, vcexcl_t excl
,
1055 int mode
, vnode_t
**vpp
, cred_t
*cr
, int flag
, caller_context_t
*ct
,
1064 * Don't allow creation of extended attributes with sysattr names.
1066 if (is_sattr_name(name
)) {
1067 return (gfs_dir_lookup(dvp
, name
, vpp
, cr
, 0, NULL
, NULL
));
1070 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1073 error
= VOP_CREATE(pvp
, name
, vap
, excl
, mode
, vpp
, cr
, flag
,
1081 xattr_dir_remove(vnode_t
*dvp
, char *name
, cred_t
*cr
, caller_context_t
*ct
,
1087 if (is_sattr_name(name
)) {
1091 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1093 error
= VOP_REMOVE(pvp
, name
, cr
, ct
, flags
);
1100 xattr_dir_link(vnode_t
*tdvp
, vnode_t
*svp
, char *name
, cred_t
*cr
,
1101 caller_context_t
*ct
, int flags
)
1106 if (svp
->v_flag
& V_SYSATTR
) {
1110 error
= xattr_dir_realdir(tdvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1112 error
= VOP_LINK(pvp
, svp
, name
, cr
, ct
, flags
);
1119 xattr_dir_rename(vnode_t
*sdvp
, char *snm
, vnode_t
*tdvp
, char *tnm
,
1120 cred_t
*cr
, caller_context_t
*ct
, int flags
)
1122 vnode_t
*spvp
, *tpvp
;
1126 if (is_sattr_name(snm
) || is_sattr_name(tnm
))
1127 return (xattr_copy(sdvp
, snm
, tdvp
, tnm
, cr
, ct
));
1129 * We know that sdvp is a GFS dir, or we wouldn't be here.
1130 * Get the real unnamed directory.
1132 error
= xattr_dir_realdir(sdvp
, &spvp
, LOOKUP_XATTR
, cr
, ct
);
1139 * If the source and target are the same GFS directory, the
1140 * underlying unnamed source and target dir will be the same.
1145 } else if (tdvp
->v_flag
& V_SYSATTR
) {
1147 * If the target dir is a different GFS directory,
1148 * find its underlying unnamed dir.
1150 error
= xattr_dir_realdir(tdvp
, &tpvp
, LOOKUP_XATTR
, cr
, ct
);
1158 * Target dir is outside of GFS, pass it on through.
1164 error
= VOP_RENAME(spvp
, snm
, tpvp
, tnm
, cr
, ct
, flags
);
1175 * readdir_xattr_casecmp: given a system attribute name, see if there
1176 * is a real xattr with the same normalized name.
1179 readdir_xattr_casecmp(vnode_t
*dvp
, char *nm
, cred_t
*cr
, caller_context_t
*ct
,
1188 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1190 error
= VOP_LOOKUP(dvp
, nm
, &vp
, &pn
,
1191 FIGNORECASE
, rootvp
, cr
, ct
, NULL
, NULL
);
1193 *eflags
= ED_CASE_CONFLICT
;
1195 } else if (error
== ENOENT
) {
1205 xattr_dir_readdir(vnode_t
*dvp
, uio_t
*uiop
, cred_t
*cr
, int *eofp
,
1206 caller_context_t
*ct
, int flags
)
1220 * See if there is a real extended attribute directory.
1222 error
= xattr_dir_realdir(dvp
, &pvp
, LOOKUP_XATTR
, cr
, ct
);
1228 * Start by reading up the static entries.
1230 if (uiop
->uio_loffset
== 0) {
1233 gfs_dir_t
*dp
= dvp
->v_data
;
1234 gfs_readdir_state_t gstate
;
1238 * If there is a real xattr dir, skip . and ..
1239 * in the GFS dir. We'll pick them up below
1240 * when we call into the underlying fs.
1242 uiop
->uio_loffset
= GFS_STATIC_ENTRY_OFFSET
;
1244 error
= gfs_get_parent_ino(dvp
, cr
, ct
, &pino
, &ino
);
1246 error
= gfs_readdir_init(&gstate
, dp
->gfsd_maxlen
, 1,
1247 uiop
, pino
, ino
, flags
);
1255 while ((error
= gfs_readdir_pred(&gstate
, uiop
, &off
)) == 0 &&
1257 if (off
>= 0 && off
< dp
->gfsd_nstatic
) {
1261 * Check to see if this sysattr set name has a
1262 * case-insensitive conflict with a real xattr
1266 if ((flags
& V_RDDIR_ENTFLAGS
) && has_xattrs
) {
1267 error
= readdir_xattr_casecmp(pvp
,
1268 dp
->gfsd_static
[off
].gfse_name
,
1273 ino
= dp
->gfsd_inode(dvp
, off
);
1275 error
= gfs_readdir_emit(&gstate
, uiop
, off
,
1276 ino
, dp
->gfsd_static
[off
].gfse_name
,
1285 error
= gfs_readdir_fini(&gstate
, error
, eofp
, *eofp
);
1293 * We must read all of the static entries in the first
1294 * call. Otherwise we won't know if uio_loffset in a
1295 * subsequent call refers to the static entries or to those
1296 * in an underlying fs.
1310 uiop
->uio_loffset
= 0;
1312 (void) VOP_RWLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1313 error
= VOP_READDIR(pvp
, uiop
, cr
, eofp
, ct
, flags
);
1314 VOP_RWUNLOCK(pvp
, V_WRITELOCK_FALSE
, NULL
);
1322 xattr_dir_inactive(vnode_t
*vp
, cred_t
*cr
, 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 VN_RELE(xattr_dir
->xattr_realvp
);
1331 xattr_dir
->xattr_realvp
= NULL
;
1333 mutex_exit(&vp
->v_lock
);
1334 fp
= gfs_dir_inactive(vp
);
1336 kmem_free(fp
, fp
->gfs_size
);
1341 xattr_dir_pathconf(vnode_t
*vp
, int cmd
, ulong_t
*valp
, cred_t
*cr
,
1342 caller_context_t
*ct
)
1345 case _PC_XATTR_EXISTS
:
1346 case _PC_SATTR_ENABLED
:
1347 case _PC_SATTR_EXISTS
:
1351 return (fs_pathconf(vp
, cmd
, valp
, cr
, ct
));
1357 xattr_dir_realvp(vnode_t
*vp
, vnode_t
**realvp
, caller_context_t
*ct
)
1359 xattr_dir_t
*xattr_dir
;
1361 mutex_enter(&vp
->v_lock
);
1362 xattr_dir
= vp
->v_data
;
1363 if (xattr_dir
->xattr_realvp
) {
1364 *realvp
= xattr_dir
->xattr_realvp
;
1365 mutex_exit(&vp
->v_lock
);
1371 mutex_exit(&vp
->v_lock
);
1372 if ((error
= xattr_dir_realdir(vp
, &xdvp
,
1373 LOOKUP_XATTR
, kcred
, NULL
)) == 0) {
1375 * verify we aren't racing with another thread
1376 * to find the xattr_realvp
1378 mutex_enter(&vp
->v_lock
);
1379 if (xattr_dir
->xattr_realvp
== NULL
) {
1380 xattr_dir
->xattr_realvp
= xdvp
;
1382 mutex_exit(&vp
->v_lock
);
1384 *realvp
= xattr_dir
->xattr_realvp
;
1385 mutex_exit(&vp
->v_lock
);
1393 static const fs_operation_def_t xattr_dir_tops
[] = {
1394 { VOPNAME_OPEN
, { .vop_open
= xattr_dir_open
} },
1395 { VOPNAME_CLOSE
, { .vop_close
= xattr_dir_close
} },
1396 { VOPNAME_IOCTL
, { .error
= fs_inval
} },
1397 { VOPNAME_GETATTR
, { .vop_getattr
= xattr_dir_getattr
} },
1398 { VOPNAME_SETATTR
, { .vop_setattr
= xattr_dir_setattr
} },
1399 { VOPNAME_ACCESS
, { .vop_access
= xattr_dir_access
} },
1400 { VOPNAME_READDIR
, { .vop_readdir
= xattr_dir_readdir
} },
1401 { VOPNAME_LOOKUP
, { .vop_lookup
= gfs_vop_lookup
} },
1402 { VOPNAME_CREATE
, { .vop_create
= xattr_dir_create
} },
1403 { VOPNAME_REMOVE
, { .vop_remove
= xattr_dir_remove
} },
1404 { VOPNAME_LINK
, { .vop_link
= xattr_dir_link
} },
1405 { VOPNAME_RENAME
, { .vop_rename
= xattr_dir_rename
} },
1406 { VOPNAME_MKDIR
, { .error
= fs_inval
} },
1407 { VOPNAME_SEEK
, { .vop_seek
= fs_seek
} },
1408 { VOPNAME_INACTIVE
, { .vop_inactive
= xattr_dir_inactive
} },
1409 { VOPNAME_FID
, { .vop_fid
= xattr_common_fid
} },
1410 { VOPNAME_PATHCONF
, { .vop_pathconf
= xattr_dir_pathconf
} },
1411 { VOPNAME_REALVP
, { .vop_realvp
= xattr_dir_realvp
} },
1415 static gfs_opsvec_t xattr_opsvec
[] = {
1416 { "xattr dir", xattr_dir_tops
, &xattr_dir_ops
},
1417 { "system attributes", xattr_file_tops
, &xattr_file_ops
},
1418 { NULL
, NULL
, NULL
}
1422 xattr_lookup_cb(vnode_t
*vp
, const char *nm
, vnode_t
**vpp
, ino64_t
*inop
,
1423 cred_t
*cr
, int flags
, int *deflags
, pathname_t
*rpnp
)
1432 error
= xattr_dir_realdir(vp
, &pvp
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1436 * Return ENOENT for EACCES requests during lookup. Once an
1437 * attribute create is attempted EACCES will be returned.
1440 if (error
== EACCES
)
1445 error
= pn_get((char *)nm
, UIO_SYSSPACE
, &pn
);
1447 error
= VOP_LOOKUP(pvp
, (char *)nm
, vpp
, &pn
, flags
, rootvp
,
1448 cr
, NULL
, deflags
, rpnp
);
1458 xattrdir_do_ino(vnode_t
*vp
, int index
)
1461 * We use index 0 for the directory fid. Start
1462 * the file numbering at 1.
1464 return ((ino64_t
)index
+1);
1470 VERIFY(gfs_make_opsvec(xattr_opsvec
) == 0);
1474 xattr_dir_lookup(vnode_t
*dvp
, vnode_t
**vpp
, int flags
, cred_t
*cr
)
1480 if (dvp
->v_type
!= VDIR
&& dvp
->v_type
!= VREG
)
1483 mutex_enter(&dvp
->v_lock
);
1486 * If we're already in sysattr space, don't allow creation
1487 * of another level of sysattrs.
1489 if (dvp
->v_flag
& V_SYSATTR
) {
1490 mutex_exit(&dvp
->v_lock
);
1494 if (dvp
->v_xattrdir
!= NULL
) {
1495 *vpp
= dvp
->v_xattrdir
;
1499 int xattrs_allowed
= dvp
->v_vfsp
->vfs_flag
& VFS_XATTR
;
1500 int sysattrs_allowed
= 1;
1503 * We have to drop the lock on dvp. gfs_dir_create will
1504 * grab it for a VN_HOLD.
1506 mutex_exit(&dvp
->v_lock
);
1509 * If dvp allows xattr creation, but not sysattr
1510 * creation, return the real xattr dir vp. We can't
1511 * use the vfs feature mask here because _PC_SATTR_ENABLED
1512 * has vnode-level granularity (e.g. .zfs).
1514 error
= VOP_PATHCONF(dvp
, _PC_SATTR_ENABLED
, &val
, cr
, NULL
);
1515 if (error
!= 0 || val
== 0)
1516 sysattrs_allowed
= 0;
1518 if (!xattrs_allowed
&& !sysattrs_allowed
)
1521 if (!sysattrs_allowed
) {
1525 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1528 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
,
1529 flags
|LOOKUP_HAVE_SYSATTR_DIR
, rootvp
, cr
, NULL
,
1536 * Note that we act as if we were given CREATE_XATTR_DIR,
1537 * but only for creation of the GFS directory.
1539 *vpp
= gfs_dir_create(
1540 sizeof (xattr_dir_t
), dvp
, xattr_dir_ops
, xattr_dirents
,
1541 xattrdir_do_ino
, MAXNAMELEN
, NULL
, xattr_lookup_cb
);
1542 mutex_enter(&dvp
->v_lock
);
1543 if (dvp
->v_xattrdir
!= NULL
) {
1545 * We lost the race to create the xattr dir.
1546 * Destroy this one, use the winner. We can't
1547 * just call VN_RELE(*vpp), because the vnode
1548 * is only partially initialized.
1550 gfs_dir_t
*dp
= (*vpp
)->v_data
;
1552 ASSERT((*vpp
)->v_count
== 1);
1555 mutex_destroy(&dp
->gfsd_lock
);
1556 kmem_free(dp
->gfsd_static
,
1557 dp
->gfsd_nstatic
* sizeof (gfs_dirent_t
));
1558 kmem_free(dp
, dp
->gfsd_file
.gfs_size
);
1561 * There is an implied VN_HOLD(dvp) here. We should
1562 * be doing a VN_RELE(dvp) to clean up the reference
1563 * from *vpp, and then a VN_HOLD(dvp) for the new
1564 * reference. Instead, we just leave the count alone.
1567 *vpp
= dvp
->v_xattrdir
;
1570 (*vpp
)->v_flag
|= (V_XATTRDIR
|V_SYSATTR
);
1571 dvp
->v_xattrdir
= *vpp
;
1574 mutex_exit(&dvp
->v_lock
);
1580 xattr_dir_vget(vfs_t
*vfsp
, vnode_t
**vpp
, fid_t
*fidp
)
1591 if (fidp
->fid_len
< XATTR_FIDSZ
)
1594 xfidp
= (xattr_fid_t
*)fidp
;
1595 orig_len
= fidp
->fid_len
;
1596 fidp
->fid_len
= xfidp
->parent_len
;
1598 error
= VFS_VGET(vfsp
, &pvp
, fidp
);
1599 fidp
->fid_len
= orig_len
;
1604 * Start by getting the GFS sysattr directory. We might need
1605 * to recreate it during the VOP_LOOKUP.
1608 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1614 error
= VOP_LOOKUP(pvp
, nm
, &dvp
, &pn
, LOOKUP_XATTR
|CREATE_XATTR_DIR
,
1615 rootvp
, CRED(), NULL
, NULL
, NULL
);
1621 if (xfidp
->dir_offset
== 0) {
1623 * If we were looking for the directory, we're done.
1629 if (xfidp
->dir_offset
> XATTRDIR_NENTS
) {
1634 nm
= xattr_dirents
[xfidp
->dir_offset
- 1].gfse_name
;
1636 error
= pn_get(nm
, UIO_SYSSPACE
, &pn
);
1642 error
= VOP_LOOKUP(dvp
, nm
, vpp
, &pn
, 0, rootvp
, CRED(), NULL
,