X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=module%2Fzfs%2Fzfs_acl.c;h=8ab5abe81666cc361b2638ff99355f5ac14b06b7;hb=refs%2Fheads%2Frertzinger%2Ffeature-zpool-get--p;hp=98c0019503cd579443ba693c1a8a0cd95f719203;hpb=b8d06fca089fae4680c3a552fc55c512bfb02202;p=zfs.git diff --git a/module/zfs/zfs_acl.c b/module/zfs/zfs_acl.c index 98c0019..8ab5abe 100644 --- a/module/zfs/zfs_acl.c +++ b/module/zfs/zfs_acl.c @@ -1056,8 +1056,8 @@ zfs_acl_node_read(znode_t *zp, boolean_t have_lock, zfs_acl_t **aclpp, boolean_t will_modify) { zfs_acl_t *aclp; - int aclsize; - int acl_count; + int aclsize = 0; + int acl_count = 0; zfs_acl_node_t *aclnode; zfs_acl_phys_t znode_acl; int version; @@ -2453,32 +2453,52 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) { uint32_t working_mode; int error; - int is_attr; boolean_t check_privs; - znode_t *xzp; znode_t *check_zp = zp; mode_t needed_bits; uid_t owner; - is_attr = ((zp->z_pflags & ZFS_XATTR) && S_ISDIR(ZTOI(zp)->i_mode)); - /* * If attribute then validate against base file */ - if (is_attr) { + if ((zp->z_pflags & ZFS_XATTR) && S_ISDIR(ZTOI(zp)->i_mode)) { uint64_t parent; - if ((error = sa_lookup(zp->z_sa_hdl, - SA_ZPL_PARENT(ZTOZSB(zp)), &parent, - sizeof (parent))) != 0) - return (error); + rw_enter(&zp->z_xattr_lock, RW_READER); + if (zp->z_xattr_parent) { + check_zp = zp->z_xattr_parent; + rw_exit(&zp->z_xattr_lock); - if ((error = zfs_zget(ZTOZSB(zp), - parent, &xzp)) != 0) { - return (error); - } + /* + * Verify a lookup yields the same znode. + */ + ASSERT3S(sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT( + ZTOZSB(zp)), &parent, sizeof (parent)), ==, 0); + ASSERT3U(check_zp->z_id, ==, parent); + } else { + rw_exit(&zp->z_xattr_lock); - check_zp = xzp; + error = sa_lookup(zp->z_sa_hdl, SA_ZPL_PARENT( + ZTOZSB(zp)), &parent, sizeof (parent)); + if (error) + return (error); + + /* + * Cache the lookup on the parent file znode as + * zp->z_xattr_parent and hold a reference. This + * effectively pins the parent in memory until all + * child xattr znodes have been destroyed and + * release their references in zfs_inode_destroy(). + */ + error = zfs_zget(ZTOZSB(zp), parent, &check_zp); + if (error) + return (error); + + rw_enter(&zp->z_xattr_lock, RW_WRITER); + if (zp->z_xattr_parent == NULL) + zp->z_xattr_parent = check_zp; + rw_exit(&zp->z_xattr_lock); + } /* * fixup mode to map to xattr perms @@ -2521,15 +2541,11 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, &check_privs, skipaclchk, cr)) == 0) { - if (is_attr) - iput(ZTOI(xzp)); return (secpolicy_vnode_access2(cr, ZTOI(zp), owner, needed_bits, needed_bits)); } if (error && !check_privs) { - if (is_attr) - iput(ZTOI(xzp)); return (error); } @@ -2590,10 +2606,6 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) needed_bits, needed_bits); } - - if (is_attr) - iput(ZTOI(xzp)); - return (error); }