diff options
author | Brian Behlendorf <[email protected]> | 2017-09-08 15:07:00 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2017-09-08 15:07:00 -0700 |
commit | 5c214ae318cbca37285ec38e6a2044a7002d31e9 (patch) | |
tree | 199f8691dbb618a53d2761c568075660d4d7e3e5 /module/zfs/zvol.c | |
parent | e0dd0a32a8c8db725be673153b09bee0ca9adcf2 (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.c | 23 |
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 |