]> granicus.if.org Git - zfs/commitdiff
Add ASSERT to debug encryption key mapping issues
authorTom Caputi <tcaputi@datto.com>
Mon, 18 Jun 2018 21:10:54 +0000 (17:10 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 18 Jun 2018 21:10:54 +0000 (14:10 -0700)
This patch simply adds an ASSERT that confirms that the last
decrypting reference on a dataset waits until the dataset is
no longer dirty. This should help to debug issues where the
ZIO layer cannot find encryption keys after a dataset has been
disowned.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #7637

include/sys/dmu.h
module/zfs/dbuf.c
module/zfs/dsl_dataset.c

index e5950be93b9ab1089699ebf322d0e183fb4d002c..44c026286dd2dfc6a78e37af2e70c7c877609cb0 100644 (file)
@@ -557,6 +557,7 @@ boolean_t dmu_buf_try_add_ref(dmu_buf_t *, objset_t *os, uint64_t object,
 
 void dmu_buf_rele(dmu_buf_t *db, void *tag);
 uint64_t dmu_buf_refcount(dmu_buf_t *db);
+uint64_t dmu_buf_user_refcount(dmu_buf_t *db);
 
 /*
  * dmu_buf_hold_array holds the DMU buffers which contain all bytes in a
index 2411c8d4f3e088d779001d4d7e2a7449387ec17f..e3738db525e8e0db610758798ad5ef9e1009d3ac 100644 (file)
@@ -3306,6 +3306,20 @@ dbuf_refcount(dmu_buf_impl_t *db)
        return (refcount_count(&db->db_holds));
 }
 
+uint64_t
+dmu_buf_user_refcount(dmu_buf_t *db_fake)
+{
+       uint64_t holds;
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+       mutex_enter(&db->db_mtx);
+       ASSERT3U(refcount_count(&db->db_holds), >=, db->db_dirtycnt);
+       holds = refcount_count(&db->db_holds) - db->db_dirtycnt;
+       mutex_exit(&db->db_mtx);
+
+       return (holds);
+}
+
 void *
 dmu_buf_replace_user(dmu_buf_t *db_fake, dmu_buf_user_t *old_user,
     dmu_buf_user_t *new_user)
index 7a4721e17f1c0a8cfe7b57a8cb432e0e29b2ef5e..9db6d1e0be0fd8c4978b5d6ecf7d948a2f0da6ce 100644 (file)
@@ -791,6 +791,15 @@ dsl_dataset_rele_flags(dsl_dataset_t *ds, ds_hold_flags_t flags, void *tag)
            (flags & DS_HOLD_FLAG_DECRYPT)) {
                (void) spa_keystore_remove_mapping(ds->ds_dir->dd_pool->dp_spa,
                    ds->ds_object, ds);
+
+               /*
+                * Encrypted datasets require that users only release their
+                * decrypting reference after the dirty data has actually
+                * been written out. This ensures that the mapping exists
+                * when it is needed to write out dirty data.
+                */
+               ASSERT(dmu_buf_user_refcount(ds->ds_dbuf) != 0 ||
+                   !dsl_dataset_is_dirty(ds));
        }
 
        dmu_buf_rele(ds->ds_dbuf, tag);