da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER START
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The contents of this file are subject to the terms of the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Common Development and Distribution License (the "License").
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You may not use this file except in compliance with the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See the License for the specific language governing permissions
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * and limitations under the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * When distributing Covered Code, include this CDDL HEADER in each
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If applicable, add the following below this CDDL HEADER, with the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * fields enclosed by brackets "[]" replaced with your own identifying
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * information: Portions Copyright [yyyy] [name of copyright owner]
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER END
3fece8600e183b5cfc2f2782273c649252a723e8Mark Shellenbaum * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Big Theory Statement for Extended Attribute (XATTR) directories
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * The Solaris VFS layer presents extended file attributes using a special
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * "XATTR" directory under files or directories that have extended file
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * attributes. See fsattr(5) for background.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * This design avoids the need for a separate set of VFS or vnode functions
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * for operating on XATTR objects. File system implementations that support
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * XATTR instantiate a special XATTR directory using this module.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Applications get to the XATTR directory by passing the LOOKUP_XATTR flag
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * to fop_lookup. Once the XATTR directory is obtained, all other file
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * system operations on extended attributes happen via the normal vnode
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * functions, applied to the XATTR directory or its contents.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * The XATTR directories returned by fop_lookup (with LOOKUP_XATTR) are
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * implemented differntly, depending on whether the file system supports
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * "extended attributes" (XATTR), "system attributes" (SYSATTR), or both.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * When SYSATTR=true, XATTR=true:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * The XATTR directory is a "generic file system" (GFS) object
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * that adds the special system attribute names (SUNWattr*) to
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * the list of XATTR files presented by the underling FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * In this case, many operations are "passed through" to the
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * lower-level FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * When SYSATTR=true, XATTR=false:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * The XATTR directory is a "generic file system" (GFS) object,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * presenting only the system attribute names (SUNWattr*)
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * In this case there's no lower-level FS, only the GFS object.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * When SYSATTR=false, XATTR=true:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * The XATTR directory is implemented by the file system code,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * and this module is not involved after xattr_dir_lookup()
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * returns the XATTR dir from the underlying file system.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * When SYSATTR=false, XATTR=false:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * xattr_dir_lookup just returns EINVAL
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * In the first two cases (where we have system attributes) this module
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * implements what can be thought of as a "translucent" directory containing
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * both the system attribute names (SUNWattr*) and whatever XATTR names may
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * exist in the XATTR directory of the underlying file system, if any.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * This affects operations on the (GFS) XATTR directory as follows:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * readdir: Merges the SUNWattr* names with any contents from the
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * underlying XATTR directory.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * rename: If "to" or "from" is a SUNWattr name, special handling,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * else pass through to the lower FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * link: If "from" is a SUNWattr name, disallow.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * create: If a SUNWattr name, disallow, else pass to lower FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * remove: (same)
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * open,close: Just pass through to the XATTR dir in the lower FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * lookup: Lookup an XATTR file in either the (GFS) XATTR directory
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * or the "real" XATTR directory of the underlying FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Note for file systems the support SYSATTR but not XATTR,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * only the GFS XATTR directory will exist. When both exist,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * gfs_vop_lookup uses the xattr_lookup_cb callback function
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * which passes the lookup call through to the "real" FS.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Operations on the XATTR _files_ are simpler:
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If the file vnode came from lookup at the GFS level, the file is one of
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * the special SUNWattr* vnodes, and it's vnode operations (xattr_file_tops)
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * allow only what's appropriate on these "files".
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If the file vnode came from the underlying FS, all operations on that
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * object are handled through the vnode operations set by that FS.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtypedef struct {
68469ade54beb02c61d9f7dc75d6a21ebfd046c6Mark Shellenbaumtypedef struct {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_close(vnode_t *vp, int flags, int count, offset_t off,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * For detecting ephemeral uid/gid
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We need to access the real fs object.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * vp points to a GFS file; ppvp points to the real object.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Iterate through the attrs associated with this view
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (attr) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 0xffffffff));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Process all the optional attributes together here. Notice that
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * xoap was set when the optional attribute bits were set above.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sizeof (uint64_t)) == 0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Check for optional ownersid/groupsid
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
bda89588bd7667394a834e8a9a34612cce2ae9c3jp if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The size of a sysattr file is the size of the nvlist that will be
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * returned by xattr_file_read(). A call to xattr_file_write() could
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * change the size of that nvlist. That size is not stored persistently
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_file_size(vp, np->xattr_view, &size, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Validate file offset and fasttrack empty reads
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw xoptattr_t *xoap = NULL; /* Pointer to optional attributes */
9660e5cb810c5efc22db0f1459461c1f1eec15b9Janice Chang if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Validate file offset and size.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Copy and unpack the nvlist
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Fasttrack empty writes (nvlist with no nvpairs)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Validate the name and type of each attribute.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Log any unknown names and continue. This will
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * help if additional attributes are added later.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Verify nvlist type matches required type and view is OK
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * For OWNERSID/GROUPSID make sure the target
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * file system support ephemeral ID's
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Retrieve data from nvpair
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (type) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (attr) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If we have several similar optional attributes to
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * process then we should do it all together here so that
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * xoap and the requested bitmap can be set in one place.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Now map domain+rid to ephemeral id's
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If mapping fails, then the uid/gid will
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * be set to UID_NOBODY by Winchester.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (cmd) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_ACCESS, { .vop_access = xattr_file_access } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw for (i = 0; i < XATTRDIR_NENTS; ++i) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (1);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
b38f097029665f4ece801ca129913d36f757b49cck * Given the name of an extended attribute file, determine if there is a
b38f097029665f4ece801ca129913d36f757b49cck * normalization conflict with a sysattr view name.
b38f097029665f4ece801ca129913d36f757b49cck for (i = 0; i < XATTRDIR_NENTS; ++i) {
b38f097029665f4ece801ca129913d36f757b49cck return (1);
b38f097029665f4ece801ca129913d36f757b49cck return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Only copy system attrs if the views are the same
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Get the "real" XATTR directory associtated with the GFS XATTR directory.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Note: This does NOT take any additional hold on the returned real_vp,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * because when this lookup succeeds we save the result in xattr_realvp
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * and keep that hold until the GFS XATTR directory goes inactive.
9b24702912cd165acd5682b2c0c853496d320536Gordon Rossxattr_dir_realdir(vnode_t *gfs_dvp, vnode_t **ret_vpp, int flags,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Usually, we've already found the underlying XATTR directory
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * during some previous lookup and stored it in xattr_realvp.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Lookup the XATTR dir in the underlying FS, relative to our
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * "parent", which is the real object for which this GFS XATTR
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * directory was created. Set the LOOKUP_HAVE_SYSATTR_DIR flag
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * so that we don't get into an infinite loop with fop_lookup
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * calling back to xattr_dir_lookup.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = VOP_LOOKUP(gfs_file_parent(gfs_dvp), nm, &realvp, &pn,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross flags | LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, ct, NULL, NULL);
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Have the real XATTR directory. Save it -- but first
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * check whether we lost a race doing the lookup.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Note that the hold taken by the VOP_LOOKUP above is
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * retained from here until xattr_dir_inactive.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross /* We lost the race. */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If there is a real extended attribute directory,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * let the underlying FS see the VOP_OPEN call;
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * otherwise just return zero.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = xattr_dir_realdir(*vpp, &realvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
9b24702912cd165acd5682b2c0c853496d320536Gordon Rossxattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If there is a real extended attribute directory,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * let the underlying FS see the VOP_CLOSE call;
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * otherwise just return zero.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = VOP_CLOSE(realvp, flags, count, off, cr, ct);
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * Retrieve the attributes on an xattr directory. If there is a "real"
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * xattr directory, use that. Otherwise, get the attributes (represented
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * by PARENT_ATTRMASK) from the "parent" node and fill in the rest. Note
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * that VOP_GETATTR() could turn off bits in the va_mask.
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi#define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * There is no real xattr directory. Cobble together
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * an entry using info from the parent object (if needed)
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * plus information common to all xattrs.
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct);
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * VOP_GETATTR() might have turned off some bits in
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * pvattr.va_mask. This means that the underlying
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * file system couldn't process those attributes.
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * We need to make sure those bits get turned off
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * in the vattr_t structure that gets passed back
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * to the caller. Figure out which bits were turned
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * off (if any) then set pvattr.va_mask before it
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi * gets copied to the vattr_t that the caller sees.
00ba712d889cedd6eb0c7de606f61b180572b600Garima Tripathi off_bits = (pvattr.va_mask ^ PARENT_ATTRMASK) & PARENT_ATTRMASK;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If there is a real xattr directory, do the setattr there.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Otherwise, just return success. The GFS directory is transient,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * and any setattr changes can disappear anyway.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If there is a real xattr directory, check access there;
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * otherwise just return success.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = VOP_ACCESS(realvp, mode, flags, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Don't allow creation of extended attributes with sysattr names.
ab04eb8ef60d9dc9614d6cccffc474f24ca1d162timh return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We know that sdvp is a GFS dir, or we wouldn't be here.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Get the real unnamed directory.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If the source and target are the same GFS directory, the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * underlying unnamed source and target dir will be the same.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If the target dir is a different GFS directory,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * find its underlying unnamed dir.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Target dir is outside of GFS, pass it on through.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags);
b38f097029665f4ece801ca129913d36f757b49cck * readdir_xattr_casecmp: given a system attribute name, see if there
b38f097029665f4ece801ca129913d36f757b49cck * is a real xattr with the same normalized name.
b38f097029665f4ece801ca129913d36f757b49cckreaddir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
b38f097029665f4ece801ca129913d36f757b49cck if (error == 0) {
b38f097029665f4ece801ca129913d36f757b49cck if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See if there is a real extended attribute directory.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Start by reading up the static entries.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If there is a real xattr dir, skip . and ..
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * in the GFS dir. We'll pick them up below
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * when we call into the underlying fs.
b38f097029665f4ece801ca129913d36f757b49cck if (error == 0) {
b38f097029665f4ece801ca129913d36f757b49cck while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 &&
b38f097029665f4ece801ca129913d36f757b49cck * Check to see if this sysattr set name has a
b38f097029665f4ece801ca129913d36f757b49cck * case-insensitive conflict with a real xattr
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We must read all of the static entries in the first
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * call. Otherwise we won't know if uio_loffset in a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * subsequent call refers to the static entries or to those
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * in an underlying fs.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Last reference on a (GFS) XATTR directory.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * If there's a real XATTR directory in the underlying FS, we will have
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * taken a hold on that directory in xattr_dir_realdir. Now that the
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * last hold on the GFS directory is gone, it's time to release that
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * hold on the underlying XATTR directory.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwstatic void
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (cmd) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);
68469ade54beb02c61d9f7dc75d6a21ebfd046c6Mark Shellenbaum/* ARGSUSED */
68469ade54beb02c61d9f7dc75d6a21ebfd046c6Mark Shellenbaumxattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = xattr_dir_realdir(vp, realvp, LOOKUP_XATTR, kcred, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } },
68469ade54beb02c61d9f7dc75d6a21ebfd046c6Mark Shellenbaum { VOPNAME_REALVP, { .vop_realvp = xattr_dir_realvp } },
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw { "system attributes", xattr_file_tops, &xattr_file_ops },
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Callback supporting lookup in a GFS XATTR directory.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Return ENOENT for EACCES requests during lookup. Once an
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * attribute create is attempted EACCES will be returned.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (error == 0) {
ab04eb8ef60d9dc9614d6cccffc474f24ca1d162timh error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, flags, rootvp,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/* ARGSUSED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We use index 0 for the directory fid. Start
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the file numbering at 1.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Get the XATTR dir for some file or directory.
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * See vnode.c: fop_lookup()
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * Note this only gets the GFS XATTR directory. We'll get the
9b24702912cd165acd5682b2c0c853496d320536Gordon Ross * real XATTR directory later, in xattr_dir_realdir.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwxattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If we're already in sysattr space, don't allow creation
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * of another level of sysattrs.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We have to drop the lock on dvp. gfs_dir_create will
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * grab it for a VN_HOLD.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If dvp allows xattr creation, but not sysattr
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * creation, return the real xattr dir vp. We can't
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * use the vfs feature mask here because _PC_SATTR_ENABLED
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * has vnode-level granularity (e.g. .zfs).
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Note that we act as if we were given CREATE_XATTR_DIR,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * but only for creation of the GFS directory.
68469ade54beb02c61d9f7dc75d6a21ebfd046c6Mark Shellenbaum sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * We lost the race to create the xattr dir.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Destroy this one, use the winner. We can't
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * just call VN_RELE(*vpp), because the vnode
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * is only partially initialized.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * There is an implied VN_HOLD(dvp) here. We should
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * be doing a VN_RELE(dvp) to clean up the reference
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * from *vpp, and then a VN_HOLD(dvp) for the new
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * reference. Instead, we just leave the count alone.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Start by getting the GFS sysattr directory. We might need
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * to recreate it during the VOP_LOOKUP.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If we were looking for the directory, we're done.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (0);