summaryrefslogtreecommitdiffstats
path: root/module/zfs/arc.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/arc.c')
-rw-r--r--module/zfs/arc.c63
1 files changed, 60 insertions, 3 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c
index ab2564841..e49f8a547 100644
--- a/module/zfs/arc.c
+++ b/module/zfs/arc.c
@@ -3512,22 +3512,47 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
arc_buf_hdr_t *nhdr;
arc_buf_t *buf;
kmem_cache_t *ncache, *ocache;
+ unsigned nsize, osize;
+ /*
+ * This function requires that hdr is in the arc_anon state.
+ * Therefore it won't have any L2ARC data for us to worry
+ * about copying.
+ */
ASSERT(HDR_HAS_L1HDR(hdr));
+ ASSERT(!HDR_HAS_L2HDR(hdr));
ASSERT3U(!!HDR_PROTECTED(hdr), !=, need_crypt);
ASSERT3P(hdr->b_l1hdr.b_state, ==, arc_anon);
ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+ ASSERT(!list_link_active(&hdr->b_l2hdr.b_l2node));
+ ASSERT3P(hdr->b_hash_next, ==, NULL);
if (need_crypt) {
ncache = hdr_full_crypt_cache;
+ nsize = sizeof (hdr->b_crypt_hdr);
ocache = hdr_full_cache;
+ osize = HDR_FULL_SIZE;
} else {
ncache = hdr_full_cache;
+ nsize = HDR_FULL_SIZE;
ocache = hdr_full_crypt_cache;
+ osize = sizeof (hdr->b_crypt_hdr);
}
nhdr = kmem_cache_alloc(ncache, KM_PUSHPAGE);
- bcopy(hdr, nhdr, HDR_L2ONLY_SIZE);
+
+ /*
+ * Copy all members that aren't locks or condvars to the new header.
+ * No lists are pointing to us (as we asserted above), so we don't
+ * need to worry about the list nodes.
+ */
+ nhdr->b_dva = hdr->b_dva;
+ nhdr->b_birth = hdr->b_birth;
+ nhdr->b_type = hdr->b_type;
+ nhdr->b_flags = hdr->b_flags;
+ nhdr->b_psize = hdr->b_psize;
+ nhdr->b_lsize = hdr->b_lsize;
+ nhdr->b_spa = hdr->b_spa;
nhdr->b_l1hdr.b_freeze_cksum = hdr->b_l1hdr.b_freeze_cksum;
nhdr->b_l1hdr.b_bufcnt = hdr->b_l1hdr.b_bufcnt;
nhdr->b_l1hdr.b_byteswap = hdr->b_l1hdr.b_byteswap;
@@ -3540,7 +3565,6 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
nhdr->b_l1hdr.b_l2_hits = hdr->b_l1hdr.b_l2_hits;
nhdr->b_l1hdr.b_acb = hdr->b_l1hdr.b_acb;
nhdr->b_l1hdr.b_pabd = hdr->b_l1hdr.b_pabd;
- nhdr->b_l1hdr.b_buf = hdr->b_l1hdr.b_buf;
/*
* This refcount_add() exists only to ensure that the individual
@@ -3548,7 +3572,7 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
* a small race condition that could trigger ASSERTs.
*/
(void) refcount_add(&nhdr->b_l1hdr.b_refcnt, FTAG);
-
+ nhdr->b_l1hdr.b_buf = hdr->b_l1hdr.b_buf;
for (buf = nhdr->b_l1hdr.b_buf; buf != NULL; buf = buf->b_next) {
mutex_enter(&buf->b_evict_lock);
buf->b_hdr = nhdr;
@@ -3557,6 +3581,7 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
refcount_transfer(&nhdr->b_l1hdr.b_refcnt, &hdr->b_l1hdr.b_refcnt);
(void) refcount_remove(&nhdr->b_l1hdr.b_refcnt, FTAG);
+ ASSERT0(refcount_count(&hdr->b_l1hdr.b_refcnt));
if (need_crypt) {
arc_hdr_set_flags(nhdr, ARC_FLAG_PROTECTED);
@@ -3564,6 +3589,38 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
arc_hdr_clear_flags(nhdr, ARC_FLAG_PROTECTED);
}
+ /* unset all members of the original hdr */
+ bzero(&hdr->b_dva, sizeof (dva_t));
+ hdr->b_birth = 0;
+ hdr->b_type = ARC_BUFC_INVALID;
+ hdr->b_flags = 0;
+ hdr->b_psize = 0;
+ hdr->b_lsize = 0;
+ hdr->b_spa = 0;
+ hdr->b_l1hdr.b_freeze_cksum = NULL;
+ hdr->b_l1hdr.b_buf = NULL;
+ hdr->b_l1hdr.b_bufcnt = 0;
+ hdr->b_l1hdr.b_byteswap = 0;
+ hdr->b_l1hdr.b_state = NULL;
+ hdr->b_l1hdr.b_arc_access = 0;
+ hdr->b_l1hdr.b_mru_hits = 0;
+ hdr->b_l1hdr.b_mru_ghost_hits = 0;
+ hdr->b_l1hdr.b_mfu_hits = 0;
+ hdr->b_l1hdr.b_mfu_ghost_hits = 0;
+ hdr->b_l1hdr.b_l2_hits = 0;
+ hdr->b_l1hdr.b_acb = NULL;
+ hdr->b_l1hdr.b_pabd = NULL;
+
+ if (ocache == hdr_full_crypt_cache) {
+ ASSERT(!HDR_HAS_RABD(hdr));
+ hdr->b_crypt_hdr.b_ot = DMU_OT_NONE;
+ hdr->b_crypt_hdr.b_ebufcnt = 0;
+ hdr->b_crypt_hdr.b_dsobj = 0;
+ bzero(hdr->b_crypt_hdr.b_salt, ZIO_DATA_SALT_LEN);
+ bzero(hdr->b_crypt_hdr.b_iv, ZIO_DATA_IV_LEN);
+ bzero(hdr->b_crypt_hdr.b_mac, ZIO_DATA_MAC_LEN);
+ }
+
buf_discard_identity(hdr);
kmem_cache_free(ocache, hdr);