Skip to content

Commit 6e3c109

Browse files
authored
Fix regression in dmu_buf_will_fill()
Direct I/O implementation added condition to call dbuf_undirty() only in case of block cloning. But the condition is not right if the block is no longer dirty in this TXG, but still in DB_NOFILL state. It resulted in block not reverting to DB_UNCACHED and following NULL de-reference on attempt to access absent db_data. While there, add assertions for db_data to make debugging easier. Reviewed-by: Brian Atkinson <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #16829
1 parent 3e9ba0f commit 6e3c109

File tree

3 files changed

+11
-2
lines changed

3 files changed

+11
-2
lines changed

module/os/freebsd/zfs/dmu_os.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ dmu_write_pages(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
103103
db->db_offset + bufoff);
104104
thiscpy = MIN(PAGESIZE, tocpy - copied);
105105
va = zfs_map_page(*ma, &sf);
106+
ASSERT(db->db_data != NULL);
106107
memcpy((char *)db->db_data + bufoff, va, thiscpy);
107108
zfs_unmap_page(sf);
108109
ma += 1;
@@ -172,6 +173,7 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count,
172173
ASSERT3U(db->db_size, >, PAGE_SIZE);
173174
bufoff = IDX_TO_OFF(m->pindex) % db->db_size;
174175
va = zfs_map_page(m, &sf);
176+
ASSERT(db->db_data != NULL);
175177
memcpy(va, (char *)db->db_data + bufoff, PAGESIZE);
176178
zfs_unmap_page(sf);
177179
vm_page_valid(m);
@@ -211,8 +213,10 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count,
211213
*/
212214
tocpy = MIN(db->db_size - bufoff, PAGESIZE - pgoff);
213215
ASSERT3S(tocpy, >=, 0);
214-
if (m != bogus_page)
216+
if (m != bogus_page) {
217+
ASSERT(db->db_data != NULL);
215218
memcpy(va + pgoff, (char *)db->db_data + bufoff, tocpy);
219+
}
216220

217221
pgoff += tocpy;
218222
ASSERT3S(pgoff, >=, 0);
@@ -290,6 +294,7 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count,
290294
bufoff = IDX_TO_OFF(m->pindex) % db->db_size;
291295
tocpy = MIN(db->db_size - bufoff, PAGESIZE);
292296
va = zfs_map_page(m, &sf);
297+
ASSERT(db->db_data != NULL);
293298
memcpy(va, (char *)db->db_data + bufoff, tocpy);
294299
if (tocpy < PAGESIZE) {
295300
ASSERT3S(i, ==, *rahead - 1);

module/zfs/dbuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2921,7 +2921,7 @@ dmu_buf_will_fill(dmu_buf_t *db_fake, dmu_tx_t *tx, boolean_t canfail)
29212921
* pending clone and mark the block as uncached. This will be
29222922
* as if the clone was never done.
29232923
*/
2924-
if (dr && dr->dt.dl.dr_brtwrite) {
2924+
if (db->db_state == DB_NOFILL) {
29252925
VERIFY(!dbuf_undirty(db, tx));
29262926
db->db_state = DB_UNCACHED;
29272927
}

module/zfs/dmu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,7 @@ dmu_read_impl(dnode_t *dn, uint64_t offset, uint64_t size,
12211221
bufoff = offset - db->db_offset;
12221222
tocpy = MIN(db->db_size - bufoff, size);
12231223

1224+
ASSERT(db->db_data != NULL);
12241225
(void) memcpy(buf, (char *)db->db_data + bufoff, tocpy);
12251226

12261227
offset += tocpy;
@@ -1278,6 +1279,7 @@ dmu_write_impl(dmu_buf_t **dbp, int numbufs, uint64_t offset, uint64_t size,
12781279
else
12791280
dmu_buf_will_dirty(db, tx);
12801281

1282+
ASSERT(db->db_data != NULL);
12811283
(void) memcpy((char *)db->db_data + bufoff, buf, tocpy);
12821284

12831285
if (tocpy == db->db_size)
@@ -1426,6 +1428,7 @@ dmu_read_uio_dnode(dnode_t *dn, zfs_uio_t *uio, uint64_t size)
14261428
bufoff = zfs_uio_offset(uio) - db->db_offset;
14271429
tocpy = MIN(db->db_size - bufoff, size);
14281430

1431+
ASSERT(db->db_data != NULL);
14291432
err = zfs_uio_fault_move((char *)db->db_data + bufoff, tocpy,
14301433
UIO_READ, uio);
14311434

@@ -1550,6 +1553,7 @@ dmu_write_uio_dnode(dnode_t *dn, zfs_uio_t *uio, uint64_t size, dmu_tx_t *tx)
15501553
else
15511554
dmu_buf_will_dirty(db, tx);
15521555

1556+
ASSERT(db->db_data != NULL);
15531557
err = zfs_uio_fault_move((char *)db->db_data + bufoff,
15541558
tocpy, UIO_WRITE, uio);
15551559

0 commit comments

Comments
 (0)