aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/zvol.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2017-09-08 15:07:00 -0700
committerGitHub <[email protected]>2017-09-08 15:07:00 -0700
commit5c214ae318cbca37285ec38e6a2044a7002d31e9 (patch)
tree199f8691dbb618a53d2761c568075660d4d7e3e5 /module/zfs/zvol.c
parente0dd0a32a8c8db725be673153b09bee0ca9adcf2 (diff)
Fix volume WR_INDIRECT log replay
The portion of the zvol_replay_write() handler responsible for replaying indirect log records for some reason never existed. As a result indirect log records were not being correctly replayed. This went largely unnoticed since the majority of zvol log records were of the type WR_COPIED or WR_NEED_COPY prior to OpenZFS 7578. This patch updates zvol_replay_write() to correctly handle these log records and adds a new test case which verifies volume replay to prevent any regression. The existing test case which verified replay on filesystem was renamed slog_replay_fs.ksh for clarity. Reviewed-by: George Melikov <[email protected]> Reviewed-by: loli10K <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #6603 Closes #6615
Diffstat (limited to 'module/zfs/zvol.c')
-rw-r--r--module/zfs/zvol.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 60fab5cc6..1cb03fc7e 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -599,26 +599,37 @@ static int
zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap)
{
objset_t *os = zv->zv_objset;
- char *data = (char *)(lr + 1); /* data follows lr_write_t */
- uint64_t off = lr->lr_offset;
- uint64_t len = lr->lr_length;
+ char *data = (char *)(lr + 1); /* data follows lr_write_t */
+ uint64_t offset, length;
dmu_tx_t *tx;
int error;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
+ offset = lr->lr_offset;
+ length = lr->lr_length;
+
+ /* If it's a dmu_sync() block, write the whole block */
+ if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+ uint64_t blocksize = BP_GET_LSIZE(&lr->lr_blkptr);
+ if (length < blocksize) {
+ offset -= offset % blocksize;
+ length = blocksize;
+ }
+ }
+
tx = dmu_tx_create(os);
- dmu_tx_hold_write(tx, ZVOL_OBJ, off, len);
+ dmu_tx_hold_write(tx, ZVOL_OBJ, offset, length);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
dmu_tx_abort(tx);
} else {
- dmu_write(os, ZVOL_OBJ, off, len, data, tx);
+ dmu_write(os, ZVOL_OBJ, offset, length, data, tx);
dmu_tx_commit(tx);
}
- return (SET_ERROR(error));
+ return (error);
}
static int