Skip to content

Commit a3494fa

Browse files
committed
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. Signed-off-by: Chunwei Chen <[email protected]> Closes #10593 Change-Id: I07307002ad3e0a7de577bab487dc11c447645a83
1 parent bedbc13 commit a3494fa

File tree

7 files changed

+28
-8
lines changed

7 files changed

+28
-8
lines changed

cmd/ztest/ztest.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,8 +2287,8 @@ ztest_get_done(zgd_t *zgd, int error)
22872287
}
22882288

22892289
static int
2290-
ztest_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb,
2291-
zio_t *zio)
2290+
ztest_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
2291+
struct lwb *lwb, zio_t *zio)
22922292
{
22932293
ztest_ds_t *zd = arg;
22942294
objset_t *os = zd->zd_os;

include/sys/zil.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ typedef struct itx {
399399
void *itx_callback_data; /* User data for the callback */
400400
size_t itx_size; /* allocated itx structure size */
401401
uint64_t itx_oid; /* object id */
402+
uint64_t itx_gen; /* gen number for zfs_get_data */
402403
lr_t itx_lr; /* common part of log record */
403404
/* followed by type-specific part of lr_xx_t and its immediate data */
404405
} itx_t;
@@ -467,7 +468,7 @@ typedef int zil_parse_blk_func_t(zilog_t *zilog, const blkptr_t *bp, void *arg,
467468
typedef int zil_parse_lr_func_t(zilog_t *zilog, const lr_t *lr, void *arg,
468469
uint64_t txg);
469470
typedef int zil_replay_func_t(void *arg1, void *arg2, boolean_t byteswap);
470-
typedef int zil_get_data_t(void *arg, lr_write_t *lr, char *dbuf,
471+
typedef int zil_get_data_t(void *arg, uint64_t arg2, lr_write_t *lr, char *dbuf,
471472
struct lwb *lwb, zio_t *zio);
472473

473474
extern int zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func,

include/sys/zvol_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ void zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off,
8585
uint64_t len, boolean_t sync);
8686
void zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset,
8787
uint64_t size, int sync);
88-
int zvol_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb,
89-
zio_t *zio);
88+
int zvol_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
89+
struct lwb *lwb, zio_t *zio);
9090
int zvol_init_impl(void);
9191
void zvol_fini_impl(void);
9292
void zvol_wait_close(zvol_state_t *zv);

module/zfs/zfs_log.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
540540
uint32_t blocksize = zp->z_blksz;
541541
itx_wr_state_t write_state;
542542
uintptr_t fsync_cnt;
543+
uint64_t gen = 0;
543544

544545
if (zil_replaying(zilog, tx) || zp->z_unlinked ||
545546
zfs_xattr_owner_unlinked(zp)) {
@@ -562,6 +563,9 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
562563
(void) tsd_set(zfs_fsyncer_key, (void *)(fsync_cnt - 1));
563564
}
564565

566+
(void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(zp)), &gen,
567+
sizeof (gen));
568+
565569
while (resid) {
566570
itx_t *itx;
567571
lr_write_t *lr;
@@ -609,6 +613,7 @@ zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype,
609613
BP_ZERO(&lr->lr_blkptr);
610614

611615
itx->itx_private = ZTOZSB(zp);
616+
itx->itx_gen = gen;
612617

613618
if (!(ioflag & (O_SYNC | O_DSYNC)) && (zp->z_sync_cnt == 0) &&
614619
(fsync_cnt == 0))

module/zfs/zfs_vnops.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,8 @@ static void zfs_get_done(zgd_t *zgd, int error);
738738
* Get data to generate a TX_WRITE intent log record.
739739
*/
740740
int
741-
zfs_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb, zio_t *zio)
741+
zfs_get_data(void *arg, uint64_t gen, lr_write_t *lr, char *buf,
742+
struct lwb *lwb, zio_t *zio)
742743
{
743744
zfsvfs_t *zfsvfs = arg;
744745
objset_t *os = zfsvfs->z_os;
@@ -749,6 +750,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb, zio_t *zio)
749750
dmu_buf_t *db;
750751
zgd_t *zgd;
751752
int error = 0;
753+
uint64_t zp_gen;
752754

753755
ASSERT3P(lwb, !=, NULL);
754756
ASSERT3P(zio, !=, NULL);
@@ -767,6 +769,16 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb, zio_t *zio)
767769
zfs_zrele_async(zp);
768770
return (SET_ERROR(ENOENT));
769771
}
772+
/* check if generation number matches */
773+
if (sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(zfsvfs), &zp_gen,
774+
sizeof (zp_gen)) != 0) {
775+
zfs_zrele_async(zp);
776+
return (SET_ERROR(EIO));
777+
}
778+
if (zp_gen != gen) {
779+
zfs_zrele_async(zp);
780+
return (SET_ERROR(ENOENT));
781+
}
770782

771783
zgd = (zgd_t *)kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
772784
zgd->zgd_lwb = lwb;

module/zfs/zil.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1744,7 +1744,8 @@ zil_lwb_commit(zilog_t *zilog, itx_t *itx, lwb_t *lwb)
17441744
* completed after "lwb_write_zio" completed.
17451745
*/
17461746
error = zilog->zl_get_data(itx->itx_private,
1747-
lrwb, dbuf, lwb, lwb->lwb_write_zio);
1747+
itx->itx_gen, lrwb, dbuf, lwb,
1748+
lwb->lwb_write_zio);
17481749

17491750
if (error == EIO) {
17501751
txg_wait_synced(zilog->zl_dmu_pool, txg);

module/zfs/zvol.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,8 @@ zvol_get_done(zgd_t *zgd, int error)
660660
* Get data to generate a TX_WRITE intent log record.
661661
*/
662662
int
663-
zvol_get_data(void *arg, lr_write_t *lr, char *buf, struct lwb *lwb, zio_t *zio)
663+
zvol_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
664+
struct lwb *lwb, zio_t *zio)
664665
{
665666
zvol_state_t *zv = arg;
666667
uint64_t offset = lr->lr_offset;

0 commit comments

Comments
 (0)