* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
+ * or https://opensource.org/licenses/CDDL-1.0.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012 Cyril Plisko. All rights reserved.
* Copyright (c) 2013, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2021, 2022 by Pawel Jakub Dawidek
*/
#include <sys/types.h>
#include <sys/zil.h>
#include <sys/byteorder.h>
#include <sys/stat.h>
-#include <sys/mode.h>
#include <sys/acl.h>
#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
+ * hold the locks across all subsequent VOPs until vput is called.
+ * This means that its zfs vnops routines can't do any internal locking.
+ * In order to have the same contract as the Linux vnops there would
+ * needed to be duplicate locked vnops. If the vnops were used more widely
+ * in common code this would likely be preferable. However, currently
+ * this is the only file where this is the case.
+ */
/*
* Functions to replay ZFS intent log (ZIL) records
zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode,
uint64_t uid, uint64_t gid, uint64_t rdev, uint64_t nodeid)
{
- bzero(vap, sizeof (*vap));
+ memset(vap, 0, sizeof (*vap));
vap->va_mask = (uint_t)mask;
- vap->va_type = IFTOVT(mode);
vap->va_mode = mode;
+#if defined(__FreeBSD__) || defined(__APPLE__)
+ vap->va_type = IFTOVT(mode);
+#endif
vap->va_uid = (uid_t)(IS_EPHEMERAL(uid)) ? -1 : uid;
vap->va_gid = (gid_t)(IS_EPHEMERAL(gid)) ? -1 : gid;
- vap->va_rdev = rdev;
+ vap->va_rdev = zfs_cmpldev(rdev);
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));
}
if (XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) {
ASSERT(!XVA_ISSET_REQ(xvap, XAT_PROJID));
- bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
+ memcpy(xoap->xoa_av_scanstamp, scanstamp, AV_SCANSTAMP_SZ);
} else if (XVA_ISSET_REQ(xvap, XAT_PROJID)) {
/*
* XAT_PROJID and XAT_AV_SCANSTAMP will never be valid
* at the same time, so we can share the same space.
*/
- bcopy(scanstamp, &xoap->xoa_projid, sizeof (uint64_t));
+ memcpy(&xoap->xoa_projid, scanstamp, sizeof (uint64_t));
}
if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0);
char *name = NULL; /* location determined later */
lr_create_t *lr = (lr_create_t *)lracl;
znode_t *dzp;
- struct inode *ip = NULL;
+ znode_t *zp;
xvattr_t xva;
int vflg = 0;
vsecattr_t vsec = { 0 };
uint64_t dnodesize;
int error;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lracl));
+
txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
if (byteswap) {
byteswap_uint64_array(lracl, sizeof (*lracl));
xva.xva_vattr.va_nblocks = lr->lr_gen;
xva.xva_vattr.va_fsid = dnodesize;
- error = dmu_object_info(zfsvfs->z_os, lr->lr_foid, NULL);
- if (error != ENOENT)
+ error = dnode_try_claim(zfsvfs->z_os, objid, dnodesize >> DNODE_SHIFT);
+ if (error)
goto bail;
if (lr->lr_common.lrc_txtype & TX_CI)
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);
lr->lr_uid, lr->lr_gid);
}
- error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr,
- 0, 0, &ip, kcred, vflg, &vsec);
+#if defined(__linux__)
+ error = zfs_create(dzp, name, &xva.xva_vattr,
+ 0, 0, &zp, kcred, vflg, &vsec, zfs_init_idmap);
+#else
+ error = zfs_create(dzp, name, &xva.xva_vattr,
+ 0, 0, &zp, kcred, vflg, &vsec, NULL);
+#endif
break;
case TX_MKDIR_ACL:
aclstart = (caddr_t)(lracl + 1);
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);
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
lr->lr_uid, lr->lr_gid);
}
- error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr,
- &ip, kcred, vflg, &vsec);
+#if defined(__linux__)
+ error = zfs_mkdir(dzp, name, &xva.xva_vattr,
+ &zp, kcred, vflg, &vsec, zfs_init_idmap);
+#else
+ error = zfs_mkdir(dzp, name, &xva.xva_vattr,
+ &zp, kcred, vflg, &vsec, NULL);
+#endif
break;
default:
error = SET_ERROR(ENOTSUP);
}
bail:
- if (error == 0 && ip != NULL)
- iput(ip);
-
- iput(ZTOI(dzp));
+ if (error == 0 && zp != NULL) {
+#ifdef __FreeBSD__
+ VOP_UNLOCK1(ZTOV(zp));
+#endif
+ zrele(zp);
+ }
+ zrele(dzp);
if (zfsvfs->z_fuid_replay)
zfs_fuid_info_free(zfsvfs->z_fuid_replay);
char *name = NULL; /* location determined later */
char *link; /* symlink content follows name */
znode_t *dzp;
- struct inode *ip = NULL;
+ znode_t *zp = NULL;
xvattr_t xva;
int vflg = 0;
size_t lrsize = sizeof (lr_create_t);
uint64_t dnodesize;
int error;
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr));
+
txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
xva.xva_vattr.va_nblocks = lr->lr_gen;
xva.xva_vattr.va_fsid = dnodesize;
- error = dmu_object_info(zfsvfs->z_os, objid, NULL);
- if (error != ENOENT)
+ error = dnode_try_claim(zfsvfs->z_os, objid, dnodesize >> DNODE_SHIFT);
+ if (error)
goto out;
if (lr->lr_common.lrc_txtype & TX_CI)
*
* The _ATTR versions will grab the fuid info in their subcases.
*/
- if ((int)lr->lr_common.lrc_txtype != TX_SYMLINK &&
- (int)lr->lr_common.lrc_txtype != TX_MKDIR_ATTR &&
- (int)lr->lr_common.lrc_txtype != TX_CREATE_ATTR) {
+ if (txtype != TX_SYMLINK &&
+ txtype != TX_MKDIR_ATTR &&
+ txtype != TX_CREATE_ATTR) {
start = (lr + 1);
zfsvfs->z_fuid_replay =
zfs_replay_fuid_domain(start, &start,
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
+ zfs_fallthrough;
- /*FALLTHROUGH*/
case TX_CREATE:
if (name == NULL)
name = (char *)start;
- error = zfs_create(ZTOI(dzp), name, &xva.xva_vattr,
- 0, 0, &ip, kcred, vflg, NULL);
+#if defined(__linux__)
+ error = zfs_create(dzp, name, &xva.xva_vattr,
+ 0, 0, &zp, kcred, vflg, NULL, zfs_init_idmap);
+#else
+ error = zfs_create(dzp, name, &xva.xva_vattr,
+ 0, 0, &zp, kcred, vflg, NULL, NULL);
+#endif
break;
case TX_MKDIR_ATTR:
lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
name = (char *)start;
+ zfs_fallthrough;
- /*FALLTHROUGH*/
case TX_MKDIR:
if (name == NULL)
name = (char *)(lr + 1);
- error = zfs_mkdir(ZTOI(dzp), name, &xva.xva_vattr,
- &ip, kcred, vflg, NULL);
+#if defined(__linux__)
+ error = zfs_mkdir(dzp, name, &xva.xva_vattr,
+ &zp, kcred, vflg, NULL, zfs_init_idmap);
+#else
+ error = zfs_mkdir(dzp, name, &xva.xva_vattr,
+ &zp, kcred, vflg, NULL, NULL);
+#endif
+
break;
case TX_MKXATTR:
- error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &ip, kcred);
+ error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &zp, kcred);
break;
case TX_SYMLINK:
name = (char *)(lr + 1);
link = name + strlen(name) + 1;
- error = zfs_symlink(ZTOI(dzp), name, &xva.xva_vattr,
- link, &ip, kcred, vflg);
+#if defined(__linux__)
+ error = zfs_symlink(dzp, name, &xva.xva_vattr,
+ link, &zp, kcred, vflg, zfs_init_idmap);
+#else
+ error = zfs_symlink(dzp, name, &xva.xva_vattr,
+ link, &zp, kcred, vflg, NULL);
+#endif
break;
default:
error = SET_ERROR(ENOTSUP);
}
out:
- if (error == 0 && ip != NULL)
- iput(ip);
-
- iput(ZTOI(dzp));
+ if (error == 0 && zp != NULL) {
+#ifdef __FreeBSD__
+ VOP_UNLOCK1(ZTOV(zp));
+#endif
+ zrele(zp);
+ }
+ zrele(dzp);
if (zfsvfs->z_fuid_replay)
zfs_fuid_info_free(zfsvfs->z_fuid_replay);
int error;
int vflg = 0;
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr));
+
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
switch ((int)lr->lr_common.lrc_txtype) {
case TX_REMOVE:
- error = zfs_remove(ZTOI(dzp), name, kcred, vflg);
+ error = zfs_remove(dzp, name, kcred, vflg);
break;
case TX_RMDIR:
- error = zfs_rmdir(ZTOI(dzp), name, NULL, kcred, vflg);
+ error = zfs_rmdir(dzp, name, NULL, kcred, vflg);
break;
default:
error = SET_ERROR(ENOTSUP);
}
- iput(ZTOI(dzp));
+ zrele(dzp);
return (error);
}
int error;
int vflg = 0;
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr));
+
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
return (error);
if ((error = zfs_zget(zfsvfs, lr->lr_link_obj, &zp)) != 0) {
- iput(ZTOI(dzp));
+ zrele(dzp);
return (error);
}
if (lr->lr_common.lrc_txtype & TX_CI)
vflg |= FIGNORECASE;
- error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred, vflg);
-
- iput(ZTOI(zp));
- iput(ZTOI(dzp));
+ error = zfs_link(dzp, zp, name, kcred, vflg);
+ zrele(zp);
+ zrele(dzp);
return (error);
}
static int
-zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap)
+do_zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, char *sname,
+ char *tname, uint64_t rflags, vattr_t *wo_vap)
{
- zfsvfs_t *zfsvfs = arg1;
- lr_rename_t *lr = arg2;
- char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
- char *tname = sname + strlen(sname) + 1;
znode_t *sdzp, *tdzp;
- int error;
- int vflg = 0;
+ int error, vflg = 0;
- if (byteswap)
- byteswap_uint64_array(lr, sizeof (*lr));
+ /* Only Linux currently supports RENAME_* flags. */
+#ifdef __linux__
+ VERIFY0(rflags & ~(RENAME_EXCHANGE | RENAME_WHITEOUT));
+
+ /* wo_vap must be non-NULL iff. we're doing RENAME_WHITEOUT */
+ VERIFY_EQUIV(rflags & RENAME_WHITEOUT, wo_vap != NULL);
+#else
+ VERIFY0(rflags);
+#endif
if ((error = zfs_zget(zfsvfs, lr->lr_sdoid, &sdzp)) != 0)
return (error);
if ((error = zfs_zget(zfsvfs, lr->lr_tdoid, &tdzp)) != 0) {
- iput(ZTOI(sdzp));
+ zrele(sdzp);
return (error);
}
if (lr->lr_common.lrc_txtype & TX_CI)
vflg |= FIGNORECASE;
- error = zfs_rename(ZTOI(sdzp), sname, ZTOI(tdzp), tname, kcred, vflg);
-
- iput(ZTOI(tdzp));
- iput(ZTOI(sdzp));
+#if defined(__linux__)
+ error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags,
+ wo_vap, zfs_init_idmap);
+#else
+ error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags,
+ wo_vap, NULL);
+#endif
+ zrele(tdzp);
+ zrele(sdzp);
return (error);
}
+static int
+zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap)
+{
+ zfsvfs_t *zfsvfs = arg1;
+ lr_rename_t *lr = arg2;
+
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr));
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
+ char *tname = sname + strlen(sname) + 1;
+ return (do_zfs_replay_rename(zfsvfs, lr, sname, tname, 0, NULL));
+}
+
+static int
+zfs_replay_rename_exchange(void *arg1, void *arg2, boolean_t byteswap)
+{
+#ifdef __linux__
+ zfsvfs_t *zfsvfs = arg1;
+ lr_rename_t *lr = arg2;
+
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr));
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */
+ char *tname = sname + strlen(sname) + 1;
+ return (do_zfs_replay_rename(zfsvfs, lr, sname, tname, RENAME_EXCHANGE,
+ NULL));
+#else
+ return (SET_ERROR(ENOTSUP));
+#endif
+}
+
+static int
+zfs_replay_rename_whiteout(void *arg1, void *arg2, boolean_t byteswap)
+{
+#ifdef __linux__
+ zfsvfs_t *zfsvfs = arg1;
+ lr_rename_whiteout_t *lr = arg2;
+ int error;
+ /* For the whiteout file. */
+ xvattr_t xva;
+ uint64_t objid;
+ uint64_t dnodesize;
+
+ ASSERT3U(lr->lr_rename.lr_common.lrc_reclen, >, sizeof (*lr));
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ objid = LR_FOID_GET_OBJ(lr->lr_wfoid);
+ dnodesize = LR_FOID_GET_SLOTS(lr->lr_wfoid) << DNODE_SHIFT;
+
+ xva_init(&xva);
+ zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID,
+ lr->lr_wmode, lr->lr_wuid, lr->lr_wgid, lr->lr_wrdev, objid);
+
+ /*
+ * As with TX_CREATE, RENAME_WHITEOUT ends up in zfs_mknode(), which
+ * assigns the object's creation time, generation number, and dnode
+ * slot count. The generic zfs_rename() has no concept of these
+ * attributes, so we smuggle the values inside the vattr's otherwise
+ * unused va_ctime, va_nblocks, and va_fsid fields.
+ */
+ ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_wcrtime);
+ xva.xva_vattr.va_nblocks = lr->lr_wgen;
+ xva.xva_vattr.va_fsid = dnodesize;
+
+ error = dnode_try_claim(zfsvfs->z_os, objid, dnodesize >> DNODE_SHIFT);
+ if (error)
+ return (error);
+
+ /* sname and tname follow lr_rename_whiteout_t */
+ char *sname = (char *)(lr + 1);
+ char *tname = sname + strlen(sname) + 1;
+ return (do_zfs_replay_rename(zfsvfs, &lr->lr_rename, sname, tname,
+ RENAME_WHITEOUT, &xva.xva_vattr));
+#else
+ return (SET_ERROR(ENOTSUP));
+#endif
+}
+
static int
zfs_replay_write(void *arg1, void *arg2, boolean_t byteswap)
{
lr_write_t *lr = arg2;
char *data = (char *)(lr + 1); /* data follows lr_write_t */
znode_t *zp;
- int error, written;
+ int error;
uint64_t eod, offset, length;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
if (zp->z_size < eod)
zfsvfs->z_replay_eof = eod;
}
-
- written = zpl_write_common(ZTOI(zp), data, length, &offset,
- UIO_SYSSPACE, 0, kcred);
- if (written < 0)
- error = -written;
- else if (written < length)
- error = SET_ERROR(EIO); /* short write */
-
- iput(ZTOI(zp));
+ error = zfs_write_simple(zp, data, length, offset, NULL);
+ zrele(zp);
zfsvfs->z_replay_eof = 0; /* safety */
return (error);
int error;
uint64_t end;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
- iput(ZTOI(zp));
+ zrele(zp);
if (error == ERESTART) {
dmu_tx_wait(tx);
dmu_tx_abort(tx);
dmu_tx_commit(tx);
}
- iput(ZTOI(zp));
+ zrele(zp);
return (error);
}
zfsvfs_t *zfsvfs = arg1;
lr_truncate_t *lr = arg2;
znode_t *zp;
- flock64_t fl;
+ flock64_t fl = {0};
int error;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
return (error);
- bzero(&fl, sizeof (fl));
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = lr->lr_offset;
fl.l_len = lr->lr_length;
- error = zfs_space(ZTOI(zp), F_FREESP, &fl, FWRITE | FOFFMAX,
+ error = zfs_space(zp, F_FREESP, &fl, O_RDWR | O_LARGEFILE,
lr->lr_offset, kcred);
- iput(ZTOI(zp));
+ zrele(zp);
return (error);
}
int error;
void *start;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+
xva_init(&xva);
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start,
lr->lr_uid, lr->lr_gid);
- error = zfs_setattr(ZTOI(zp), vap, 0, kcred);
+#if defined(__linux__)
+ error = zfs_setattr(zp, vap, 0, kcred, zfs_init_idmap);
+#else
+ error = zfs_setattr(zp, vap, 0, kcred, NULL);
+#endif
zfs_fuid_info_free(zfsvfs->z_fuid_replay);
zfsvfs->z_fuid_replay = NULL;
- iput(ZTOI(zp));
+ zrele(zp);
+
+ return (error);
+}
+
+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;
+
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+ ASSERT3U(lr->lr_common.lrc_reclen, >, sizeof (*lr) + lr->lr_size);
+
+ 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);
}
zfsvfs_t *zfsvfs = arg1;
lr_acl_v0_t *lr = arg2;
ace_t *ace = (ace_t *)(lr + 1); /* ace array follows lr_acl_t */
- vsecattr_t vsa;
+ vsecattr_t vsa = {0};
znode_t *zp;
int error;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr) +
+ sizeof (ace_t) * lr->lr_aclcnt);
+
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
zfs_oldace_byteswap(ace, lr->lr_aclcnt);
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
return (error);
- bzero(&vsa, sizeof (vsa));
vsa.vsa_mask = VSA_ACE | VSA_ACECNT;
vsa.vsa_aclcnt = lr->lr_aclcnt;
vsa.vsa_aclentsz = sizeof (ace_t) * vsa.vsa_aclcnt;
vsa.vsa_aclflags = 0;
vsa.vsa_aclentp = ace;
- error = zfs_setsecattr(ZTOI(zp), &vsa, 0, kcred);
+ error = zfs_setsecattr(zp, &vsa, 0, kcred);
- iput(ZTOI(zp));
+ zrele(zp);
return (error);
}
zfsvfs_t *zfsvfs = arg1;
lr_acl_t *lr = arg2;
ace_t *ace = (ace_t *)(lr + 1);
- vsecattr_t vsa;
+ vsecattr_t vsa = {0};
znode_t *zp;
int error;
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr) + lr->lr_acl_bytes);
+
if (byteswap) {
byteswap_uint64_array(lr, sizeof (*lr));
zfs_ace_byteswap(ace, lr->lr_acl_bytes, B_FALSE);
if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0)
return (error);
- bzero(&vsa, sizeof (vsa));
vsa.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
vsa.vsa_aclcnt = lr->lr_aclcnt;
vsa.vsa_aclentp = ace;
lr->lr_fuidcnt, lr->lr_domcnt, 0, 0);
}
- error = zfs_setsecattr(ZTOI(zp), &vsa, 0, kcred);
+ error = zfs_setsecattr(zp, &vsa, 0, kcred);
if (zfsvfs->z_fuid_replay)
zfs_fuid_info_free(zfsvfs->z_fuid_replay);
zfsvfs->z_fuid_replay = NULL;
- iput(ZTOI(zp));
+ zrele(zp);
+
+ return (error);
+}
+
+static int
+zfs_replay_clone_range(void *arg1, void *arg2, boolean_t byteswap)
+{
+ zfsvfs_t *zfsvfs = arg1;
+ lr_clone_range_t *lr = arg2;
+ znode_t *zp;
+ int error;
+
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
+ ASSERT3U(lr->lr_common.lrc_reclen, >=, offsetof(lr_clone_range_t,
+ lr_bps[lr->lr_nbps]));
+
+ if (byteswap)
+ byteswap_uint64_array(lr, sizeof (*lr));
+
+ if ((error = zfs_zget(zfsvfs, lr->lr_foid, &zp)) != 0) {
+ /*
+ * Clones can be logged out of order, so don't be surprised if
+ * the file is gone - just return success.
+ */
+ if (error == ENOENT)
+ error = 0;
+ return (error);
+ }
+
+ error = zfs_clone_range_replay(zp, lr->lr_offset, lr->lr_length,
+ lr->lr_blksz, lr->lr_bps, lr->lr_nbps);
+ zrele(zp);
return (error);
}
/*
* Callback vectors for replaying records
*/
-zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE] = {
+zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE] = {
zfs_replay_error, /* no such type */
zfs_replay_create, /* TX_CREATE */
zfs_replay_create, /* TX_MKDIR */
zfs_replay_create, /* TX_MKDIR_ATTR */
zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */
zfs_replay_write2, /* TX_WRITE2 */
+ zfs_replay_setsaxattr, /* TX_SETSAXATTR */
+ zfs_replay_rename_exchange, /* TX_RENAME_EXCHANGE */
+ zfs_replay_rename_whiteout, /* TX_RENAME_WHITEOUT */
+ zfs_replay_clone_range, /* TX_CLONE_RANGE */
};