aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2021-03-19 22:53:31 -0700
committerTony Hutter <[email protected]>2021-06-23 13:22:15 -0700
commitbfb29284901afacf24269079515163a55a57aebf (patch)
tree5ae4abc3a7c2d80ddd27978f0a3e75bf2ccd2ed2 /module/zfs
parentecb1b1a31d05fa2dc2a2ee4fde82ad89883a0d4e (diff)
Fix zfs_get_data access to files with wrong generation
If TX_WRITE is create on a file, and the file is later deleted and a new directory is created on the same object id, it is possible that when zil_commit happens, zfs_get_data will be called on the new directory. This may result in panic as it tries to do range lock. This patch fixes this issue by record the generation number during zfs_log_write, so zfs_get_data can check if the object is valid. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Closes #10593 Closes #11682
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/zfs_log.c5
-rw-r--r--module/zfs/zil.c3
-rw-r--r--module/zfs/zvol.c3
3 files changed, 9 insertions, 2 deletions
diff --git a/module/zfs/zfs_log.c b/module/zfs/zfs_log.c
index 4bb529f78..30d5c4821 100644
--- a/module/zfs/zfs_log.c
+++ b/module/zfs/zfs_log.c
@@ -540,6 +540,7 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
uint32_t blocksize = zp->z_blksz;
itx_wr_state_t write_state;
uintptr_t fsync_cnt;
+ uint64_t gen = 0;
if (zil_replaying(zilog, tx) || zp->z_unlinked ||
zfs_xattr_owner_unlinked(zp)) {
@@ -562,6 +563,9 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
(void) tsd_set(zfs_fsyncer_key, (void *)(fsync_cnt - 1));
}
+ (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(zp)), &gen,
+ sizeof (gen));
+
while (resid) {
itx_t *itx;
lr_write_t *lr;
@@ -609,6 +613,7 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
BP_ZERO(&lr->lr_blkptr);
itx->itx_private = ZTOZSB(zp);
+ itx->itx_gen = gen;
if (!(ioflag & (O_SYNC | O_DSYNC)) && (zp->z_sync_cnt == 0) &&
(fsync_cnt == 0))
diff --git a/module/zfs/zil.c b/module/zfs/zil.c
index 632fef29b..8e620b409 100644
--- a/module/zfs/zil.c
+++ b/module/zfs/zil.c
@@ -1744,7 +1744,8 @@ cont:
* completed after "lwb_write_zio" completed.
*/
error = zilog->zl_get_data(itx->itx_private,
- lrwb, dbuf, lwb, lwb->lwb_write_zio);
+ itx->itx_gen, lrwb, dbuf, lwb,
+ lwb->lwb_write_zio);
if (error == EIO) {
txg_wait_synced(zilog->zl_dmu_pool, txg);
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 44f9832ce..b6609363f 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -673,7 +673,8 @@ zvol_get_done(zgd_t *zgd, int error)
* Get data to generate a TX_WRITE intent log record.
*/
int
-zvol_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb, zio_t *zio)
+zvol_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
+ struct lwb *lwb, zio_t *zio)
{
zvol_state_t *zv = arg;
uint64_t offset = lr->lr_offset;