Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142038359
D49654.id153667.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D49654.id153667.diff
View Options
diff --git a/sys/contrib/openzfs/include/os/freebsd/spl/sys/vnode_impl.h.xattr b/sys/contrib/openzfs/include/os/freebsd/spl/sys/vnode_impl.h
--- a/sys/contrib/openzfs/include/os/freebsd/spl/sys/vnode_impl.h.xattr
+++ b/sys/contrib/openzfs/include/os/freebsd/spl/sys/vnode_impl.h
@@ -227,6 +227,7 @@
#define LOOKUP_XATTR 0x02 /* lookup up extended attr dir */
#define CREATE_XATTR_DIR 0x04 /* Create extended attr dir */
#define LOOKUP_HAVE_SYSATTR_DIR 0x08 /* Already created virtual GFS dir */
+#define LOOKUP_NAMED_ATTR 0x10 /* Lookup a named attribute */
/*
* Public vnode manipulation functions.
diff --git a/sys/contrib/openzfs/include/sys/xvattr.h.xattr b/sys/contrib/openzfs/include/sys/xvattr.h
--- a/sys/contrib/openzfs/include/sys/xvattr.h.xattr
+++ b/sys/contrib/openzfs/include/sys/xvattr.h
@@ -311,6 +311,7 @@
*/
#define V_ACE_MASK 0x1 /* mask represents NFSv4 ACE permissions */
#define V_APPEND 0x2 /* want to do append only check */
+#define V_NAMEDATTR 0x4 /* is a named attribute check */
/*
* Structure used on VOP_GETSECATTR and VOP_SETSECATTR operations
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c.xattr b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c.xattr
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c
@@ -2357,10 +2357,42 @@
* In FreeBSD, we don't care about permissions of individual ADS.
* Note that not checking them is not just an optimization - without
* this shortcut, EA operations may bogusly fail with EACCES.
+ *
+ * If this is a named attribute lookup, do the checks.
*/
- if (zp->z_pflags & ZFS_XATTR)
+ if ((zp->z_pflags & ZFS_XATTR)
+#ifdef VIRF_NAMEDATTR
+ && (flags & V_NAMEDATTR) == 0
+#endif
+ )
return (0);
+
+ /*
+ * If a named attribute directory then validate against base file
+ */
+ if (is_attr) {
+ if ((error = zfs_zget(ZTOZSB(zp),
+ zp->z_xattr_parent, &xzp)) != 0) {
+ return (error);
+ }
+
+ check_zp = xzp;
+
+ /*
+ * fixup mode to map to xattr perms
+ */
+
+ if (mode & (ACE_WRITE_DATA|ACE_APPEND_DATA)) {
+ mode &= ~(ACE_WRITE_DATA|ACE_APPEND_DATA);
+ mode |= ACE_WRITE_NAMED_ATTRS;
+ }
+ if (mode & (ACE_READ_DATA|ACE_EXECUTE)) {
+ mode &= ~(ACE_READ_DATA|ACE_EXECUTE);
+ mode |= ACE_READ_NAMED_ATTRS;
+ }
+ }
+
owner = zfs_fuid_map_id(zp->z_zfsvfs, zp->z_uid, cr, ZFS_OWNER);
/*
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c.xattr b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c.xattr
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
@@ -1174,6 +1174,8 @@
zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os);
zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os);
}
+
+extern int zfs_xattr_compat;
static int
zfs_domount(vfs_t *vfsp, char *osname)
@@ -1255,6 +1257,16 @@
goto out;
}
+#ifdef VIRF_NAMEDATTR
+ /*
+ * Named attributes can only work if the xattr property is set to
+ * on/dir and not sa. Also, zfs_xattr_compat must be set.
+ */
+ if ((zfsvfs->z_flags & ZSB_XATTR) != 0 && !zfsvfs->z_xattr_sa &&
+ zfs_xattr_compat)
+ vfsp->mnt_flag |= MNT_NAMEDATTR;
+#endif
+
vfs_mountedfrom(vfsp, osname);
if (!zfsvfs->z_issnap)
@@ -1778,6 +1790,14 @@
err = vn_lock(*vpp, flags);
if (err != 0)
vrele(*vpp);
+#ifdef VIRF_NAMEDATTR
+ else if ((zp->z_pflags & ZFS_XATTR) != 0) {
+ if ((*vpp)->v_type == VDIR)
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDDIR);
+ else
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDATTR);
+ }
+#endif
}
if (err != 0)
*vpp = NULL;
@@ -1930,9 +1950,17 @@
*vpp = ZTOV(zp);
zfs_exit(zfsvfs, FTAG);
err = vn_lock(*vpp, flags);
- if (err == 0)
+ if (err == 0) {
vnode_create_vobject(*vpp, zp->z_size, curthread);
- else
+#ifdef VIRF_NAMEDATTR
+ if ((zp->z_pflags & ZFS_XATTR) != 0) {
+ if ((*vpp)->v_type == VDIR)
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDDIR);
+ else
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDATTR);
+ }
+#endif
+ } else
*vpp = NULL;
return (err);
}
diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c.xattr b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
--- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c.xattr
+++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c
@@ -717,7 +717,12 @@
/*
* Do we have permission to get into attribute directory?
*/
- error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr, NULL);
+ if (flags & LOOKUP_NAMED_ATTR)
+ error = zfs_zaccess(zp, ACE_EXECUTE, V_NAMEDATTR,
+ B_FALSE, cr, NULL);
+ else
+ error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr,
+ NULL);
if (error) {
vrele(ZTOV(zp));
}
@@ -4480,8 +4485,16 @@
* ZFS itself only knowns about VREAD, VWRITE, VEXEC and VAPPEND,
*/
accmode = ap->a_accmode & (VREAD|VWRITE|VEXEC|VAPPEND);
- if (accmode != 0)
- error = zfs_access(zp, accmode, 0, ap->a_cred);
+ if (accmode != 0) {
+#ifdef VIRF_NAMEDATTR
+ /* For named attributes, do the checks. */
+ if ((vn_irflag_read(vp) & VIRF_NAMEDATTR) != 0)
+ error = zfs_access(zp, accmode, V_NAMEDATTR,
+ ap->a_cred);
+ else
+#endif
+ error = zfs_access(zp, accmode, 0, ap->a_cred);
+ }
/*
* VADMIN has to be handled by vaccess().
@@ -4513,7 +4526,89 @@
struct componentname *a_cnp;
};
#endif
+
+#ifdef VIRF_NAMEDATTR
+static int
+zfs_freebsd_lookup(struct vop_lookup_args *ap, boolean_t cached)
+{
+ struct componentname *cnp = ap->a_cnp;
+ char nm[NAME_MAX + 1];
+ int error;
+ struct vnode **vpp = ap->a_vpp, *dvp = ap->a_dvp;
+ struct vnode *xvp;
+ bool is_nameddir, needs_nameddir, opennamed = false;
+
+ /*
+ * These variables are used to handle the named attribute cases:
+ * opennamed - Is true when this is a call from open with O_NAMEDATTR
+ * specified and it is the last component.
+ * is_nameddir - Is true when the directory is a named attribute dir.
+ * needs_nameddir - Is set when the lookup needs to look for/create
+ * a named attribute directory. It is only set when is_nameddir
+ * is_nameddir is false and opennamed is true.
+ * xvp - Is the directory that the lookup needs to be done in.
+ * Usually dvp, unless needs_nameddir is true where it is the
+ * result of the first non-named directory lookup.
+ * Note that name caching must be disabled for named attribute
+ * handling.
+ */
+ needs_nameddir = false;
+ xvp = dvp;
+ opennamed = (cnp->cn_flags & (OPENNAMED | ISLASTCN)) ==
+ (OPENNAMED | ISLASTCN);
+ is_nameddir = (vn_irflag_read(dvp) & VIRF_NAMEDDIR) != 0;
+ if (is_nameddir && (cnp->cn_flags & ISLASTCN) == 0)
+ return (ENOATTR);
+ if (opennamed || is_nameddir)
+ cnp->cn_flags &= ~MAKEENTRY;
+ if (opennamed && !is_nameddir) {
+ vpp = &xvp;
+ needs_nameddir = true;
+ }
+ ASSERT3U(cnp->cn_namelen, <, sizeof (nm));
+ error = 0;
+ if (!needs_nameddir || cnp->cn_namelen != 1 ||
+ *cnp->cn_nameptr != '.') {
+ strlcpy(nm, cnp->cn_nameptr, MIN(cnp->cn_namelen + 1,
+ sizeof (nm)));
+ error = zfs_lookup(dvp, nm, vpp, cnp, cnp->cn_nameiop,
+ cnp->cn_cred, 0, cached);
+ if (is_nameddir && error == 0 && (cnp->cn_namelen != 1 ||
+ *cnp->cn_nameptr != '.') &&
+ (cnp->cn_flags & ISDOTDOT) == 0) {
+ if ((*vpp)->v_type == VDIR)
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDDIR);
+ else
+ vn_irflag_set_cond(*vpp, VIRF_NAMEDATTR);
+ }
+ } else {
+ /* Lookup of "." when a named attribute dir is needed. */
+ xvp = dvp;
+ }
+ if (needs_nameddir && error == 0) {
+ int flags;
+ flags = LOOKUP_XATTR | LOOKUP_NAMED_ATTR;
+ if ((cnp->cn_flags & CREATENAMED) != 0)
+ flags |= CREATE_XATTR_DIR;
+ error = zfs_lookup(xvp, NULL, ap->a_vpp, NULL, 0,
+ cnp->cn_cred, flags, B_FALSE);
+ if (error == 0) {
+ if ((cnp->cn_flags & LOCKLEAF) != 0)
+ error = vn_lock(*ap->a_vpp, cnp->cn_lkflags);
+ if (error == 0) {
+ vn_irflag_set_cond(*ap->a_vpp, VIRF_NAMEDDIR);
+ } else {
+ vrele(*ap->a_vpp);
+ *ap->a_vpp = NULL;
+ }
+ }
+ if (xvp != dvp)
+ vput(xvp);
+ }
+ return (error);
+}
+#else
static int
zfs_freebsd_lookup(struct vop_lookup_args *ap, boolean_t cached)
{
@@ -4526,6 +4621,7 @@
return (zfs_lookup(ap->a_dvp, nm, ap->a_vpp, cnp, cnp->cn_nameiop,
cnp->cn_cred, 0, cached));
}
+#endif
static int
zfs_freebsd_cachedlookup(struct vop_cachedlookup_args *ap)
@@ -4548,12 +4644,28 @@
zfsvfs_t *zfsvfs;
zfsvfs = ap->a_dvp->v_mount->mnt_data;
- if (zfsvfs->z_use_namecache)
+ if (zfsvfs->z_use_namecache
+#ifdef VIRF_NAMEDATTR
+ && (ap->a_cnp->cn_flags & OPENNAMED) == 0
+#endif
+ )
return (vfs_cache_lookup(ap));
else
return (zfs_freebsd_lookup(ap, B_FALSE));
}
+static int
+zfs_check_attrname(const char *name)
+{
+ /* We don't allow '/' character in attribute name. */
+ if (strchr(name, '/') != NULL)
+ return (SET_ERROR(EINVAL));
+ /* We don't allow attribute names that start with a namespace prefix. */
+ if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
+ return (SET_ERROR(EINVAL));
+ return (0);
+}
+
#ifndef _SYS_SYSPROTO_H_
struct vop_create_args {
struct vnode *a_dvp;
@@ -4571,6 +4683,9 @@
vattr_t *vap = ap->a_vap;
znode_t *zp = NULL;
int rc, mode;
+#ifdef VIRF_NAMEDATTR
+ bool is_nameddir;
+#endif
#if __FreeBSD_version < 1400068
ASSERT(cnp->cn_flags & SAVENAME);
@@ -4581,10 +4696,23 @@
zfsvfs = ap->a_dvp->v_mount->mnt_data;
*ap->a_vpp = NULL;
- rc = zfs_create(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap, 0, mode,
- &zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */, NULL);
+ rc = 0;
+#ifdef VIRF_NAMEDATTR
+ is_nameddir = (vn_irflag_read(ap->a_dvp) & VIRF_NAMEDDIR) != 0;
+ if (is_nameddir)
+ rc = zfs_check_attrname(cnp->cn_nameptr);
+#endif
+
if (rc == 0)
+ rc = zfs_create(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap, 0, mode,
+ &zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */, NULL);
+ if (rc == 0) {
*ap->a_vpp = ZTOV(zp);
+#ifdef VIRF_NAMEDATTR
+ if (is_nameddir)
+ vn_irflag_set_cond(*ap->a_vpp, VIRF_NAMEDATTR);
+#endif
+ }
if (zfsvfs->z_use_namecache &&
rc == 0 && (cnp->cn_flags & MAKEENTRY) != 0)
cache_enter(ap->a_dvp, *ap->a_vpp, cnp);
@@ -4603,13 +4731,21 @@
static int
zfs_freebsd_remove(struct vop_remove_args *ap)
{
+ int error = 0;
#if __FreeBSD_version < 1400068
ASSERT(ap->a_cnp->cn_flags & SAVENAME);
#endif
- return (zfs_remove_(ap->a_dvp, ap->a_vp, ap->a_cnp->cn_nameptr,
- ap->a_cnp->cn_cred));
+#ifdef VIRF_NAMEDATTR
+ if ((vn_irflag_read(ap->a_dvp) & VIRF_NAMEDDIR) != 0)
+ error = zfs_check_attrname(ap->a_cnp->cn_nameptr);
+#endif
+
+ if (error == 0)
+ error = zfs_remove_(ap->a_dvp, ap->a_vp, ap->a_cnp->cn_nameptr,
+ ap->a_cnp->cn_cred);
+ return (error);
}
#ifndef _SYS_SYSPROTO_H_
@@ -4767,6 +4903,11 @@
#undef FLAG_CHECK
*vap = xvap.xva_vattr;
vap->va_flags = fflags;
+
+#ifdef VIRF_NAMEDATTR
+ if ((vn_irflag_read(ap->a_vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)
+ vap->va_bsdflags |= SFBSD_NAMEDATTR;
+#endif
return (0);
}
@@ -4909,15 +5050,24 @@
vnode_t *fvp = ap->a_fvp;
vnode_t *tdvp = ap->a_tdvp;
vnode_t *tvp = ap->a_tvp;
- int error;
+ int error = 0;
#if __FreeBSD_version < 1400068
ASSERT(ap->a_fcnp->cn_flags & (SAVENAME|SAVESTART));
ASSERT(ap->a_tcnp->cn_flags & (SAVENAME|SAVESTART));
#endif
- error = zfs_do_rename(fdvp, &fvp, ap->a_fcnp, tdvp, &tvp,
- ap->a_tcnp, ap->a_fcnp->cn_cred);
+#ifdef VIRF_NAMEDATTR
+ if ((vn_irflag_read(fdvp) & VIRF_NAMEDDIR) != 0) {
+ error = zfs_check_attrname(ap->a_fcnp->cn_nameptr);
+ if (error == 0)
+ error = zfs_check_attrname(ap->a_tcnp->cn_nameptr);
+ }
+#endif
+
+ if (error == 0)
+ error = zfs_do_rename(fdvp, &fvp, ap->a_fcnp, tdvp, &tvp,
+ ap->a_tcnp, ap->a_fcnp->cn_cred);
vrele(fdvp);
vrele(fvp);
@@ -5171,24 +5321,22 @@
return (0);
}
return (EINVAL);
+#ifdef VIRF_NAMEDATTR
+ case _PC_NAMEDATTR_ENABLED:
+ MNT_ILOCK(ap->a_vp->v_mount);
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NAMEDATTR) != 0)
+ *ap->a_retval = 1;
+ else
+ *ap->a_retval = 0;
+ MNT_IUNLOCK(ap->a_vp->v_mount);
+ return (0);
+#endif
default:
return (vop_stdpathconf(ap));
}
}
-
-static int zfs_xattr_compat = 1;
-static int
-zfs_check_attrname(const char *name)
-{
- /* We don't allow '/' character in attribute name. */
- if (strchr(name, '/') != NULL)
- return (SET_ERROR(EINVAL));
- /* We don't allow attribute names that start with a namespace prefix. */
- if (ZFS_XA_NS_PREFIX_FORBIDDEN(name))
- return (SET_ERROR(EINVAL));
- return (0);
-}
+int zfs_xattr_compat = 1;
/*
* FreeBSD's extended attributes namespace defines file name prefix for ZFS'
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 16, 7:15 AM (21 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27659254
Default Alt Text
D49654.id153667.diff (12 KB)
Attached To
Mode
D49654: openzfs: Add support for Solaris style extended attributes
Attached
Detach File
Event Timeline
Log In to Comment