]> git.proxmox.com Git - mirror_zfs.git/commitdiff
dbuf: Set dr_data when unoverriding after clone
authorAlexander Motin <mav@FreeBSD.org>
Tue, 12 Dec 2023 20:59:24 +0000 (15:59 -0500)
committerGitHub <noreply@github.com>
Tue, 12 Dec 2023 20:59:24 +0000 (12:59 -0800)
Block cloning normally creates dirty record without dr_data.  But if
the block is read after cloning, it is moved into DB_CACHED state and
receives the data buffer.  If after that we call dbuf_unoverride()
to convert the dirty record into normal write, we should give it the
data buffer from dbuf and release one.

Reviewed-by: Kay Pedersen <mail@mkwg.de>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored by: iXsystems, Inc.
Closes #15654
Closes #15656

module/zfs/dbuf.c

index a07fe1733586ee9c1f12115761b9c71247f3d54c..03c97941d6d307aa1f26a9f4e0c7022b68f657a0 100644 (file)
@@ -1919,7 +1919,6 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
        dmu_buf_impl_t *db = dr->dr_dbuf;
        blkptr_t *bp = &dr->dt.dl.dr_overridden_by;
        uint64_t txg = dr->dr_txg;
-       boolean_t release;
 
        ASSERT(MUTEX_HELD(&db->db_mtx));
        /*
@@ -1940,7 +1939,10 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
        if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite)
                zio_free(db->db_objset->os_spa, txg, bp);
 
-       release = !dr->dt.dl.dr_brtwrite;
+       if (dr->dt.dl.dr_brtwrite) {
+               ASSERT0P(dr->dt.dl.dr_data);
+               dr->dt.dl.dr_data = db->db_buf;
+       }
        dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
        dr->dt.dl.dr_nopwrite = B_FALSE;
        dr->dt.dl.dr_brtwrite = B_FALSE;
@@ -1954,7 +1956,7 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
         * the buf thawed to save the effort of freezing &
         * immediately re-thawing it.
         */
-       if (release)
+       if (dr->dt.dl.dr_data)
                arc_release(dr->dt.dl.dr_data, db);
 }