]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/dbuf.c
Implement Redacted Send/Receive
[mirror_zfs.git] / module / zfs / dbuf.c
index 28ff5fc7e4ad1565d2035f3fcc3ec7bd186efd53..8afc3df3705506848d5fadf41651464d1b18ffd6 100644 (file)
@@ -1359,6 +1359,20 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
                return (0);
        }
 
+       /*
+        * Any attempt to read a redacted block should result in an error. This
+        * will never happen under normal conditions, but can be useful for
+        * debugging purposes.
+        */
+       if (BP_IS_REDACTED(db->db_blkptr)) {
+               ASSERT(dsl_dataset_feature_is_active(
+                   db->db_objset->os_dsl_dataset,
+                   SPA_FEATURE_REDACTED_DATASETS));
+               DB_DNODE_EXIT(db);
+               mutex_exit(&db->db_mtx);
+               return (SET_ERROR(EIO));
+       }
+
 
        SET_BOOKMARK(&zb, dmu_objset_id(db->db_objset),
            db->db.db_object, db->db_level, db->db_blkid);
@@ -2116,7 +2130,8 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
        if (db->db_level == 0) {
                ASSERT(!db->db_objset->os_raw_receive ||
                    dn->dn_maxblkid >= db->db_blkid);
-               dnode_new_blkid(dn, db->db_blkid, tx, drop_struct_lock);
+               dnode_new_blkid(dn, db->db_blkid, tx,
+                   drop_struct_lock, B_FALSE);
                ASSERT(dn->dn_maxblkid >= db->db_blkid);
        }
 
@@ -2394,11 +2409,23 @@ dmu_buf_set_crypt_params(dmu_buf_t *db_fake, boolean_t byteorder,
        bcopy(mac, dr->dt.dl.dr_mac, ZIO_DATA_MAC_LEN);
 }
 
-#pragma weak dmu_buf_fill_done = dbuf_fill_done
+static void
+dbuf_override_impl(dmu_buf_impl_t *db, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       struct dirty_leaf *dl;
+
+       ASSERT3U(db->db_last_dirty->dr_txg, ==, tx->tx_txg);
+       dl = &db->db_last_dirty->dt.dl;
+       dl->dr_overridden_by = *bp;
+       dl->dr_override_state = DR_OVERRIDDEN;
+       dl->dr_overridden_by.blk_birth = db->db_last_dirty->dr_txg;
+}
+
 /* ARGSUSED */
 void
-dbuf_fill_done(dmu_buf_impl_t *db, dmu_tx_t *tx)
+dmu_buf_fill_done(dmu_buf_t *dbuf, dmu_tx_t *tx)
 {
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;
        mutex_enter(&db->db_mtx);
        DBUF_VERIFY(db);
 
@@ -2453,6 +2480,31 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
        dl->dr_overridden_by.blk_birth = db->db_last_dirty->dr_txg;
 }
 
+void
+dmu_buf_redact(dmu_buf_t *dbuf, dmu_tx_t *tx)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;
+       dmu_object_type_t type;
+       ASSERT(dsl_dataset_feature_is_active(db->db_objset->os_dsl_dataset,
+           SPA_FEATURE_REDACTED_DATASETS));
+
+       DB_DNODE_ENTER(db);
+       type = DB_DNODE(db)->dn_type;
+       DB_DNODE_EXIT(db);
+
+       ASSERT0(db->db_level);
+       dmu_buf_will_not_fill(dbuf, tx);
+
+       blkptr_t bp = { { { {0} } } };
+       BP_SET_TYPE(&bp, type);
+       BP_SET_LEVEL(&bp, 0);
+       BP_SET_BIRTH(&bp, tx->tx_txg, 0);
+       BP_SET_REDACTED(&bp);
+       BPE_SET_LSIZE(&bp, dbuf->db_size);
+
+       dbuf_override_impl(db, &bp, tx);
+}
+
 /*
  * Directly assign a provided arc buf to a given dbuf if it's not referenced
  * by anybody except our caller. Otherwise copy arcbuf's contents to dbuf.
@@ -2465,7 +2517,7 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
        ASSERT(db->db_level == 0);
        ASSERT3U(dbuf_is_metadata(db), ==, arc_is_metadata(buf));
        ASSERT(buf != NULL);
-       ASSERT(arc_buf_lsize(buf) == db->db.db_size);
+       ASSERT3U(arc_buf_lsize(buf), ==, db->db.db_size);
        ASSERT(tx->tx_txg != 0);
 
        arc_return_buf(buf, db);
@@ -2819,6 +2871,36 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
        return (db);
 }
 
+/*
+ * This function returns a block pointer and information about the object,
+ * given a dnode and a block.  This is a publicly accessible version of
+ * dbuf_findbp that only returns some information, rather than the
+ * dbuf.  Note that the dnode passed in must be held, and the dn_struct_rwlock
+ * should be locked as (at least) a reader.
+ */
+int
+dbuf_dnode_findbp(dnode_t *dn, uint64_t level, uint64_t blkid,
+    blkptr_t *bp, uint16_t *datablkszsec, uint8_t *indblkshift)
+{
+       dmu_buf_impl_t *dbp = NULL;
+       blkptr_t *bp2;
+       int err = 0;
+       ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+
+       err = dbuf_findbp(dn, level, blkid, B_FALSE, &dbp, &bp2);
+       if (err == 0) {
+               *bp = *bp2;
+               if (dbp != NULL)
+                       dbuf_rele(dbp, NULL);
+               if (datablkszsec != NULL)
+                       *datablkszsec = dn->dn_phys->dn_datablkszsec;
+               if (indblkshift != NULL)
+                       *indblkshift = dn->dn_phys->dn_indblkshift;
+       }
+
+       return (err);
+}
+
 typedef struct dbuf_prefetch_arg {
        spa_t *dpa_spa; /* The spa to issue the prefetch in. */
        zbookmark_phys_t dpa_zb; /* The target block to prefetch. */
@@ -2836,7 +2918,12 @@ typedef struct dbuf_prefetch_arg {
 static void
 dbuf_issue_final_prefetch(dbuf_prefetch_arg_t *dpa, blkptr_t *bp)
 {
-       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+       ASSERT(!BP_IS_REDACTED(bp) ||
+           dsl_dataset_feature_is_active(
+           dpa->dpa_dnode->dn_objset->os_dsl_dataset,
+           SPA_FEATURE_REDACTED_DATASETS));
+
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp) || BP_IS_REDACTED(bp))
                return;
 
        int zio_flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE;
@@ -2920,7 +3007,11 @@ dbuf_prefetch_indirect_done(zio_t *zio, const zbookmark_phys_t *zb,
        blkptr_t *bp = ((blkptr_t *)abuf->b_data) +
            P2PHASE(nextblkid, 1ULL << dpa->dpa_epbs);
 
-       if (BP_IS_HOLE(bp)) {
+       ASSERT(!BP_IS_REDACTED(bp) ||
+           dsl_dataset_feature_is_active(
+           dpa->dpa_dnode->dn_objset->os_dsl_dataset,
+           SPA_FEATURE_REDACTED_DATASETS));
+       if (BP_IS_HOLE(bp) || BP_IS_REDACTED(bp)) {
                kmem_free(dpa, sizeof (*dpa));
        } else if (dpa->dpa_curlevel == dpa->dpa_zb.zb_level) {
                ASSERT3U(nextblkid, ==, dpa->dpa_zb.zb_blkid);
@@ -3024,7 +3115,10 @@ dbuf_prefetch(dnode_t *dn, int64_t level, uint64_t blkid, zio_priority_t prio,
                ASSERT3U(curblkid, <, dn->dn_phys->dn_nblkptr);
                bp = dn->dn_phys->dn_blkptr[curblkid];
        }
-       if (BP_IS_HOLE(&bp))
+       ASSERT(!BP_IS_REDACTED(&bp) ||
+           dsl_dataset_feature_is_active(dn->dn_objset->os_dsl_dataset,
+           SPA_FEATURE_REDACTED_DATASETS));
+       if (BP_IS_HOLE(&bp) || BP_IS_REDACTED(&bp))
                return;
 
        ASSERT3U(curlevel, ==, BP_GET_LEVEL(&bp));
@@ -3958,7 +4052,7 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
 
        ASSERT(!list_link_active(&dr->dr_dirty_node));
        if (dn->dn_object == DMU_META_DNODE_OBJECT) {
-               list_insert_tail(&dn->dn_dirty_records[txg&TXG_MASK], dr);
+               list_insert_tail(&dn->dn_dirty_records[txg & TXG_MASK], dr);
                DB_DNODE_EXIT(db);
        } else {
                /*