aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/dbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r--module/zfs/dbuf.c103
1 files changed, 98 insertions, 5 deletions
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c
index 07e616f6f..8afc3df37 100644
--- a/module/zfs/dbuf.c
+++ b/module/zfs/dbuf.c
@@ -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);
@@ -2395,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);
@@ -2454,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.
@@ -2820,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. */
@@ -2837,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;
@@ -2921,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);
@@ -3025,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));