diff options
author | Rob Norris <[email protected]> | 2023-07-24 18:02:21 +1000 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2023-07-24 16:36:17 -0700 |
commit | f6facd242937e52ab1ad5a7fd3b6bbbb6ce08050 (patch) | |
tree | a87a7dc9c830c181301ed7c2501e1f3bc922ccbb | |
parent | d4edecd1a29f9162811dacf1500e2f3daf74a010 (diff) |
dbuf_sync_leaf: check DB_READ in state assertions
Block cloning introduced a new state transition from DB_NOFILL to
DB_READ. This occurs when a block is cloned and then read on the
current txg.
In this case, the clone will move the dbuf to DB_NOFILL, and then the
read will be issued for the overidden block pointer. If that read is
still outstanding when it comes time to write, the dbuf will be in
DB_READ, which is not handled by the checks in dbuf_sync_leaf, thus
tripping the assertions.
This updates those checks to allow DB_READ as a valid state iff the
dirty record is for a BRT write and there is a override block pointer.
This is a safe situation because the block already exists, so there's
nothing that could change from underneath the read.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Kay Pedersen <[email protected]>
Signed-off-by: Rob Norris <[email protected]>
Original-patch-by: Kay Pedersen <[email protected]>
Sponsored-By: OpenDrives Inc.
Sponsored-By: Klara Inc.
Closes #15050
-rw-r--r-- | module/zfs/dbuf.c | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index fbeac866a..b7453578a 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -4457,6 +4457,15 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx) } else if (db->db_state == DB_FILL) { /* This buffer was freed and is now being re-filled */ ASSERT(db->db.db_data != dr->dt.dl.dr_data); + } else if (db->db_state == DB_READ) { + /* + * This buffer has a clone we need to write, and an in-flight + * read on the BP we're about to clone. Its safe to issue the + * write here because the read has already been issued and the + * contents won't change. + */ + ASSERT(dr->dt.dl.dr_brtwrite && + dr->dt.dl.dr_override_state == DR_OVERRIDDEN); } else { ASSERT(db->db_state == DB_CACHED || db->db_state == DB_NOFILL); } |