diff options
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r-- | module/zfs/dbuf.c | 103 |
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)); |