Skip to content

Commit

Permalink
FreeBSD: Implement zfs_setextattr_sa
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Moeller <ryan@iXsystems.com>
  • Loading branch information
Ryan Moeller committed May 5, 2021
1 parent 4b4e8c5 commit 2f38723
Showing 1 changed file with 100 additions and 32 deletions.
132 changes: 100 additions & 32 deletions module/os/freebsd/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -5576,56 +5576,28 @@ struct vop_setextattr {
};
#endif

/*
* Vnode operation to set a named attribute.
*/
static int
zfs_setextattr(struct vop_setextattr_args *ap)
zfs_setextattr_dir(struct vop_setextattr_args *ap, const char *attrname)
{
zfsvfs_t *zfsvfs = VTOZ(ap->a_vp)->z_zfsvfs;
struct thread *td = ap->a_td;
struct nameidata nd;
char attrname[255];
struct vattr va;
vnode_t *xvp = NULL, *vp;
int error, flags;

/*
* If the xattr property is off, refuse the request.
*/
if (!(zfsvfs->z_flags & ZSB_XATTR)) {
return (SET_ERROR(EOPNOTSUPP));
}

error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
ap->a_cred, ap->a_td, VWRITE);
if (error != 0)
return (error);
error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
sizeof (attrname));
if (error != 0)
return (error);

ZFS_ENTER(zfsvfs);

error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td,
LOOKUP_XATTR | CREATE_XATTR_DIR, B_FALSE);
if (error != 0) {
ZFS_EXIT(zfsvfs);
if (error != 0)
return (error);
}

flags = FFLAGS(O_WRONLY | O_CREAT);
NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname,
xvp, td);
NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname, xvp, td);
error = vn_open_cred(&nd, &flags, 0600, VN_OPEN_INVFS, ap->a_cred,
NULL);
vp = nd.ni_vp;
NDFREE(&nd, NDF_ONLY_PNBUF);
if (error != 0) {
ZFS_EXIT(zfsvfs);
if (error != 0)
return (error);
}

VATTR_NULL(&va);
va.va_size = 0;
Expand All @@ -5635,6 +5607,102 @@ zfs_setextattr(struct vop_setextattr_args *ap)

VOP_UNLOCK1(vp);
vn_close(vp, flags, ap->a_cred, td);
return (error);
}

static int
zfs_setextattr_sa(struct vop_setextattr_args *ap, const char *attrname)
{
znode_t *zp = VTOZ(ap->a_vp);
nvlist_t *nvl;
size_t sa_size;
int error;

error = zfs_ensure_xattr_cached(zp);
if (error != 0)
return (error);

ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
ASSERT3P(zp->z_xattr_cached, !=, NULL);

nvl = zp->z_xattr_cached;
size_t entry_size = ap->a_uio->uio_resid;
if (entry_size > DXATTR_MAX_ENTRY_SIZE)
return (SET_ERROR(EFBIG));
error = nvlist_size(nvl, &sa_size, NV_ENCODE_XDR);
if (error != 0)
return (error);
if (sa_size > DXATTR_MAX_SA_SIZE)
return (SET_ERROR(EFBIG));
uchar_t *buf = kmem_alloc(entry_size, KM_SLEEP);
error = uiomove(buf, entry_size, ap->a_uio);
if (error == 0)
error = nvlist_add_byte_array(nvl, attrname, buf, entry_size);
kmem_free(buf, entry_size);
if (error == 0)
error = zfs_sa_set_xattr(zp);
if (error != 0) {
zp->z_xattr_cached = NULL;
nvlist_free(nvl);
}
return (error);
}

/*
* Vnode operation to set a named attribute.
*/
static int
zfs_setextattr(struct vop_setextattr_args *ap)
{
znode_t *zp = VTOZ(ap->a_vp);
zfsvfs_t *zfsvfs = ZTOZSB(zp);
char attrname[EXTATTR_MAXNAMELEN+1];
int error;

/*
* If the xattr property is off, refuse the request.
*/
if (!(zfsvfs->z_flags & ZSB_XATTR))
return (SET_ERROR(EOPNOTSUPP));

error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
ap->a_cred, ap->a_td, VWRITE);
if (error != 0)
return (error);

error = zfs_create_attrname(ap->a_attrnamespace, ap->a_name, attrname,
sizeof (attrname));
if (error != 0)
return (error);

struct vop_deleteextattr_args vda = {
.a_vp = ap->a_vp,
.a_cred = ap->a_cred,
.a_td = ap->a_td,
};
error = ENOENT;
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);
rw_enter(&zp->z_xattr_lock, RW_WRITER);
if (zfsvfs->z_use_sa && zp->z_is_sa && zfsvfs->z_xattr_sa) {
error = zfs_setextattr_sa(ap, attrname);
if (error == 0)
/*
* Successfully put into SA, we need to clear the one
* in dir if present.
*/
zfs_deleteextattr_dir(&vda, attrname);
}
if (error) {
error = zfs_setextattr_dir(ap, attrname);
if (error == 0)
/*
* Successfully put into dir, we need to clear the one
* in SA if present.
*/
zfs_deleteextattr_sa(&vda, attrname);
}
rw_exit(&zp->z_xattr_lock);
ZFS_EXIT(zfsvfs);
return (error);
}
Expand Down

0 comments on commit 2f38723

Please sign in to comment.