aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/openzfs/module/zfs/zfs_replay.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/openzfs/module/zfs/zfs_replay.c')
-rw-r--r--sys/contrib/openzfs/module/zfs/zfs_replay.c93
1 files changed, 88 insertions, 5 deletions
diff --git a/sys/contrib/openzfs/module/zfs/zfs_replay.c b/sys/contrib/openzfs/module/zfs/zfs_replay.c
index f76725f0b716..3ccd96dc256d 100644
--- a/sys/contrib/openzfs/module/zfs/zfs_replay.c
+++ b/sys/contrib/openzfs/module/zfs/zfs_replay.c
@@ -47,6 +47,8 @@
#include <sys/atomic.h>
#include <sys/cred.h>
#include <sys/zpl.h>
+#include <sys/dmu_objset.h>
+#include <sys/zfeature.h>
/*
* NB: FreeBSD expects to be able to do vnode locking in lookup and
@@ -80,10 +82,10 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
vap->va_nodeid = nodeid;
}
-/* ARGSUSED */
static int
zfs_replay_error(void *arg1, void *arg2, boolean_t byteswap)
{
+ (void) arg1, (void) arg2, (void) byteswap;
return (SET_ERROR(ENOTSUP));
}
@@ -362,7 +364,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
lr->lr_uid, lr->lr_gid);
- fallthrough;
+ zfs_fallthrough;
case TX_CREATE_ACL_ATTR:
if (name == NULL) {
lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
@@ -394,7 +396,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart,
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
lr->lr_uid, lr->lr_gid);
- fallthrough;
+ zfs_fallthrough;
case TX_MKDIR_ACL_ATTR:
if (name == NULL) {
lrattr = (lr_attr_t *)(caddr_t)(lracl + 1);
@@ -519,7 +521,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
- fallthrough;
+ zfs_fallthrough;
case TX_CREATE:
if (name == NULL)
@@ -537,7 +539,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
- fallthrough;
+ zfs_fallthrough;
case TX_MKDIR:
if (name == NULL)
@@ -869,6 +871,86 @@ zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap)
}
static int
+zfs_replay_setsaxattr(void *arg1, void *arg2, boolean_t byteswap)
+{
+ zfsvfs_t *zfsvfs = arg1;
+ lr_setsaxattr_t *lr = arg2;
+ znode_t *zp;
+ nvlist_t *nvl;
+ size_t sa_size;
+ char *name;
+ char *value;
+ size_t size;
+ int error = 0;
+
+ ASSERT(spa_feature_is_active(zfsvfs->z_os->os_spa,
+ SPA_FEATURE_ZILSAXATTR));
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
+ return (error);
+
+ rw_enter(&zp->z_xattr_lock, RW_WRITER);
+ mutex_enter(&zp->z_lock);
+ if (zp->z_xattr_cached == NULL)
+ error = zfs_sa_get_xattr(zp);
+ mutex_exit(&zp->z_lock);
+
+ if (error)
+ goto out;
+
+ ASSERT(zp->z_xattr_cached);
+ nvl = zp->z_xattr_cached;
+
+ /* Get xattr name, value and size from log record */
+ size = lr->lr_size;
+ name = (char *)(lr + 1);
+ if (size == 0) {
+ value = NULL;
+ error = nvlist_remove(nvl, name, DATA_TYPE_BYTE_ARRAY);
+ } else {
+ value = name + strlen(name) + 1;
+ /* Limited to 32k to keep nvpair memory allocations small */
+ if (size > DXATTR_MAX_ENTRY_SIZE) {
+ error = SET_ERROR(EFBIG);
+ goto out;
+ }
+
+ /* Prevent the DXATTR SA from consuming the entire SA region */
+ error = nvlist_size(nvl, &sa_size, NV_ENCODE_XDR);
+ if (error)
+ goto out;
+
+ if (sa_size > DXATTR_MAX_SA_SIZE) {
+ error = SET_ERROR(EFBIG);
+ goto out;
+ }
+
+ error = nvlist_add_byte_array(nvl, name, (uchar_t *)value,
+ size);
+ }
+
+ /*
+ * Update the SA for additions, modifications, and removals. On
+ * error drop the inconsistent cached version of the nvlist, it
+ * will be reconstructed from the ARC when next accessed.
+ */
+ if (error == 0)
+ error = zfs_sa_set_xattr(zp, name, value, size);
+
+ if (error) {
+ nvlist_free(nvl);
+ zp->z_xattr_cached = NULL;
+ }
+
+out:
+ rw_exit(&zp->z_xattr_lock);
+ zrele(zp);
+ return (error);
+}
+
+static int
zfs_replay_acl_v0(void *arg1, void *arg2, boolean_t byteswap)
{
zfsvfs_t *zfsvfs = arg1;
@@ -989,4 +1071,5 @@ zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE] = {
zfs_replay_create, /* TX_MKDIR_ATTR */
zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */
zfs_replay_write2, /* TX_WRITE2 */
+ zfs_replay_setsaxattr, /* TX_SETSAXATTR */
};