+#include <sys/zfeature.h>
+#include <sys/zap.h>
+
+/*
+ * Return an empty bpobj, preferably the empty dummy one (dp_empty_bpobj).
+ */
+uint64_t
+bpobj_alloc_empty(objset_t *os, int blocksize, dmu_tx_t *tx)
+{
+ zfeature_info_t *empty_bpobj_feat =
+ &spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
+ spa_t *spa = dmu_objset_spa(os);
+ dsl_pool_t *dp = dmu_objset_pool(os);
+
+ if (spa_feature_is_enabled(spa, empty_bpobj_feat)) {
+ if (!spa_feature_is_active(spa, empty_bpobj_feat)) {
+ ASSERT3U(dp->dp_empty_bpobj, ==, 0);
+ dp->dp_empty_bpobj =
+ bpobj_alloc(os, SPA_MAXBLOCKSIZE, tx);
+ VERIFY(zap_add(os,
+ DMU_POOL_DIRECTORY_OBJECT,
+ DMU_POOL_EMPTY_BPOBJ, sizeof (uint64_t), 1,
+ &dp->dp_empty_bpobj, tx) == 0);
+ }
+ spa_feature_incr(spa, empty_bpobj_feat, tx);
+ ASSERT(dp->dp_empty_bpobj != 0);
+ return (dp->dp_empty_bpobj);
+ } else {
+ return (bpobj_alloc(os, blocksize, tx));
+ }
+}
+
+void
+bpobj_decr_empty(objset_t *os, dmu_tx_t *tx)
+{
+ zfeature_info_t *empty_bpobj_feat =
+ &spa_feature_table[SPA_FEATURE_EMPTY_BPOBJ];
+ dsl_pool_t *dp = dmu_objset_pool(os);
+
+ spa_feature_decr(dmu_objset_spa(os), empty_bpobj_feat, tx);
+ if (!spa_feature_is_active(dmu_objset_spa(os), empty_bpobj_feat)) {
+ VERIFY3U(0, ==, zap_remove(dp->dp_meta_objset,
+ DMU_POOL_DIRECTORY_OBJECT,
+ DMU_POOL_EMPTY_BPOBJ, tx));
+ VERIFY3U(0, ==, dmu_object_free(os, dp->dp_empty_bpobj, tx));
+ dp->dp_empty_bpobj = 0;
+ }
+}