diff --git a/include/os/linux/zfs/sys/zfs_vnops.h b/include/os/linux/zfs/sys/zfs_vnops.h index 720509562596..b05bb00b73f0 100644 --- a/include/os/linux/zfs/sys/zfs_vnops.h +++ b/include/os/linux/zfs/sys/zfs_vnops.h @@ -43,6 +43,8 @@ extern int zfs_close(struct inode *ip, int flag, cred_t *cr); extern int zfs_holey(struct inode *ip, int cmd, loff_t *off); extern int zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr); extern int zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr); +extern int zfs_write_simple(znode_t *zp, const void *data, size_t len, + loff_t pos, size_t *resid); extern int zfs_access(struct inode *ip, int mode, int flag, cred_t *cr); extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags, cred_t *cr, int *direntflags, pathname_t *realpnp); diff --git a/module/os/linux/zfs/zfs_vnops.c b/module/os/linux/zfs/zfs_vnops.c index b1fa89167015..ec63dbdeb6c2 100644 --- a/module/os/linux/zfs/zfs_vnops.c +++ b/module/os/linux/zfs/zfs_vnops.c @@ -973,6 +973,42 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr) return (0); } +/* + * Write the bytes to a file. + * + * IN: zp - znode of file to be written to + * data - bytes to write + * len - number of bytes to write + * pos - offset to start writing at + * + * OUT: resid - remaining bytes to write + * + * RETURN: 0 if success + * positive error code if failure + * + * Timestamps: + * zp - ctime|mtime updated if byte count > 0 + */ +int +zfs_write_simple(znode_t *zp, const void *data, size_t len, + loff_t pos, size_t *resid) +{ + ssize_t written; + int error = 0; + + written = zpl_write_common(ZTOI(zp), data, len, &pos, + UIO_SYSSPACE, 0, kcred); + if (written < 0) { + error = -written; + } else if (resid == NULL) { + if (written < len) + error = SET_ERROR(EIO); /* short write */ + } else { + *resid = len - written; + } + return (error); +} + /* * Drop a reference on the passed inode asynchronously. This ensures * that the caller will never drop the last reference on an inode in diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index a476e58dd819..45f19785d4ec 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -320,6 +320,12 @@ zfs_znode_hold_exit(zfsvfs_t *zfsvfs, znode_hold_t *zh) kmem_cache_free(znode_hold_cache, zh); } +dev_t +zfs_cmpldev(uint64_t dev) +{ + return (dev); +} + static void zfs_znode_sa_init(zfsvfs_t *zfsvfs, znode_t *zp, dmu_buf_t *db, dmu_object_type_t obj_type, sa_handle_t *sa_hdl) diff --git a/module/zfs/zfs_replay.c b/module/zfs/zfs_replay.c index b94c946ddd72..59a219983e9d 100644 --- a/module/zfs/zfs_replay.c +++ b/module/zfs/zfs_replay.c @@ -63,7 +63,7 @@ zfs_init_vattr(vattr_t *vap, uint64_t mask, uint64_t mode, vap->va_mode = mode; 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; } @@ -493,6 +493,9 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) lr->lr_uid, lr->lr_gid); } +#ifdef __FreeBSD__ + vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY); +#endif switch (txtype) { case TX_CREATE_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); @@ -543,6 +546,9 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) error = SET_ERROR(ENOTSUP); } +#ifdef __FreeBSD__ + VOP_UNLOCK(ZTOV(dzp), 0); +#endif out: if (error == 0 && zp != NULL) zrele(zp); @@ -574,6 +580,9 @@ zfs_replay_remove(void *arg1, void *arg2, boolean_t byteswap) if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; +#ifdef __FreeBSD__ + vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY); +#endif switch ((int)lr->lr_common.lrc_txtype) { case TX_REMOVE: error = zfs_remove(dzp, name, kcred, vflg); @@ -585,6 +594,9 @@ zfs_replay_remove(void *arg1, void *arg2, boolean_t byteswap) error = SET_ERROR(ENOTSUP); } +#ifdef __FreeBSD__ + VOP_UNLOCK(ZTOV(dzp), 0); +#endif zrele(dzp); return (error); @@ -614,8 +626,15 @@ zfs_replay_link(void *arg1, void *arg2, boolean_t byteswap) if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; +#ifdef __FreeBSD__ + vn_lock(ZTOV(dzp), LK_EXCLUSIVE | LK_RETRY); + vn_lock(ZTOV(zp), LK_EXCLUSIVE | LK_RETRY); +#endif error = zfs_link(dzp, zp, name, kcred, vflg); - +#ifdef __FreeBSD__ + VOP_UNLOCK(ZTOV(zp), 0); + VOP_UNLOCK(ZTOV(dzp), 0); +#endif zrele(zp); zrele(dzp); @@ -662,7 +681,7 @@ 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; if (byteswap) @@ -706,14 +725,7 @@ zfs_replay_write(void *arg1, void *arg2, boolean_t byteswap) 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 */ - + error = zfs_write_simple(zp, data, length, offset, NULL); zrele(zp); zfsvfs->z_replay_eof = 0; /* safety */