Skip to content

Commit b127381

Browse files
authored
Improve dbuf_read() error reporting
Previous code reported non-ZIO errors only via return value, but not via parent ZIO. It could cause NULL-dereference panics due to dmu_buf_hold_array_by_dnode() ignoring the return value, relying solely on parent ZIO status. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Ameer Hamza <[email protected]> Reported by: Ameer Hamza <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #16042
1 parent 39be46f commit b127381

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

module/zfs/dbuf.c

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,17 +1557,14 @@ dbuf_read_verify_dnode_crypt(dmu_buf_impl_t *db, uint32_t flags)
15571557
* returning.
15581558
*/
15591559
static int
1560-
dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags,
1560+
dbuf_read_impl(dmu_buf_impl_t *db, dnode_t *dn, zio_t *zio, uint32_t flags,
15611561
db_lock_type_t dblt, const void *tag)
15621562
{
1563-
dnode_t *dn;
15641563
zbookmark_phys_t zb;
15651564
uint32_t aflags = ARC_FLAG_NOWAIT;
15661565
int err, zio_flags;
15671566
blkptr_t bp, *bpp;
15681567

1569-
DB_DNODE_ENTER(db);
1570-
dn = DB_DNODE(db);
15711568
ASSERT(!zfs_refcount_is_zero(&db->db_holds));
15721569
ASSERT(MUTEX_HELD(&db->db_mtx));
15731570
ASSERT(db->db_state == DB_UNCACHED || db->db_state == DB_NOFILL);
@@ -1643,8 +1640,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags,
16431640
if (err != 0)
16441641
goto early_unlock;
16451642

1646-
DB_DNODE_EXIT(db);
1647-
16481643
db->db_state = DB_READ;
16491644
DTRACE_SET_STATE(db, "read issued");
16501645
mutex_exit(&db->db_mtx);
@@ -1669,12 +1664,11 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags,
16691664
* parent's rwlock, which would be a lock ordering violation.
16701665
*/
16711666
dmu_buf_unlock_parent(db, dblt, tag);
1672-
(void) arc_read(zio, db->db_objset->os_spa, bpp,
1667+
return (arc_read(zio, db->db_objset->os_spa, bpp,
16731668
dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ, zio_flags,
1674-
&aflags, &zb);
1675-
return (err);
1669+
&aflags, &zb));
1670+
16761671
early_unlock:
1677-
DB_DNODE_EXIT(db);
16781672
mutex_exit(&db->db_mtx);
16791673
dmu_buf_unlock_parent(db, dblt, tag);
16801674
return (err);
@@ -1759,7 +1753,7 @@ dbuf_fix_old_data(dmu_buf_impl_t *db, uint64_t txg)
17591753
}
17601754

17611755
int
1762-
dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
1756+
dbuf_read(dmu_buf_impl_t *db, zio_t *pio, uint32_t flags)
17631757
{
17641758
int err = 0;
17651759
boolean_t prefetch;
@@ -1775,7 +1769,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
17751769
dn = DB_DNODE(db);
17761770

17771771
prefetch = db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID &&
1778-
(flags & DB_RF_NOPREFETCH) == 0 && dn != NULL;
1772+
(flags & DB_RF_NOPREFETCH) == 0;
17791773

17801774
mutex_enter(&db->db_mtx);
17811775
if (flags & DB_RF_PARTIAL_FIRST)
@@ -1822,13 +1816,13 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
18221816

18231817
db_lock_type_t dblt = dmu_buf_lock_parent(db, RW_READER, FTAG);
18241818

1825-
if (zio == NULL && (db->db_state == DB_NOFILL ||
1819+
if (pio == NULL && (db->db_state == DB_NOFILL ||
18261820
(db->db_blkptr != NULL && !BP_IS_HOLE(db->db_blkptr)))) {
18271821
spa_t *spa = dn->dn_objset->os_spa;
1828-
zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
1822+
pio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
18291823
need_wait = B_TRUE;
18301824
}
1831-
err = dbuf_read_impl(db, zio, flags, dblt, FTAG);
1825+
err = dbuf_read_impl(db, dn, pio, flags, dblt, FTAG);
18321826
/*
18331827
* dbuf_read_impl has dropped db_mtx and our parent's rwlock
18341828
* for us
@@ -1849,9 +1843,10 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
18491843
*/
18501844
if (need_wait) {
18511845
if (err == 0)
1852-
err = zio_wait(zio);
1846+
err = zio_wait(pio);
18531847
else
1854-
VERIFY0(zio_wait(zio));
1848+
(void) zio_wait(pio);
1849+
pio = NULL;
18551850
}
18561851
} else {
18571852
/*
@@ -1878,7 +1873,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
18781873
ASSERT(db->db_state == DB_READ ||
18791874
(flags & DB_RF_HAVESTRUCT) == 0);
18801875
DTRACE_PROBE2(blocked__read, dmu_buf_impl_t *,
1881-
db, zio_t *, zio);
1876+
db, zio_t *, pio);
18821877
cv_wait(&db->db_changed, &db->db_mtx);
18831878
}
18841879
if (db->db_state == DB_UNCACHED)
@@ -1887,6 +1882,13 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
18871882
}
18881883
}
18891884

1885+
if (pio && err != 0) {
1886+
zio_t *zio = zio_null(pio, pio->io_spa, NULL, NULL, NULL,
1887+
ZIO_FLAG_CANFAIL);
1888+
zio->io_error = err;
1889+
zio_nowait(zio);
1890+
}
1891+
18901892
return (err);
18911893
}
18921894

0 commit comments

Comments
 (0)