diff options
author | Brian Behlendorf <[email protected]> | 2018-10-08 14:58:21 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-10-09 10:05:48 -0700 |
commit | d7e4b30a672c1d7eb77dbbe2cdcf14cac102839a (patch) | |
tree | e9d61baf611a5479fd047b7170b67ea57dd2abf7 /module/zfs/arc.c | |
parent | 4cbde2ecbf7c6478bac106fadd6a23f53d538262 (diff) |
Add zfs_refcount_transfer_ownership_many()
When debugging is enabled and a zfs_refcount_t contains multiple holders
using the same key, but different ref_counts, the wrong reference_t may
be transferred. Add a zfs_refcount_transfer_ownership_many() function,
like the existing zfs_refcount_*_many() functions, to match and transfer
the correct refcount_t;
This issue may occur when using encryption with refcount debugging
enabled. An arc_buf_hdr_t can have references for both the
hdr->b_l1hdr.b_pabd and hdr->b_crypt_hdr.b_rabd both of which use
the hdr as the reference holder. When unsharing the buffer the
p_abd should be transferred.
This issue does not impact production builds because refcount holders
are not tracked.
Reviewed-by: Matthew Ahrens <[email protected]>
Signed-off-by: Tom Caputi <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #7219
Closes #8000
Diffstat (limited to 'module/zfs/arc.c')
-rw-r--r-- | module/zfs/arc.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c index ae912ee6e..e5d88fe5d 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -3081,8 +3081,8 @@ arc_share_buf(arc_buf_hdr_t *hdr, arc_buf_t *buf) * refcount ownership to the hdr since it always owns * the refcount whenever an arc_buf_t is shared. */ - zfs_refcount_transfer_ownership(&hdr->b_l1hdr.b_state->arcs_size, - buf, hdr); + zfs_refcount_transfer_ownership_many(&hdr->b_l1hdr.b_state->arcs_size, + arc_hdr_size(hdr), buf, hdr); hdr->b_l1hdr.b_pabd = abd_get_from_buf(buf->b_data, arc_buf_size(buf)); abd_take_ownership_of_buf(hdr->b_l1hdr.b_pabd, HDR_ISTYPE_METADATA(hdr)); @@ -3110,8 +3110,8 @@ arc_unshare_buf(arc_buf_hdr_t *hdr, arc_buf_t *buf) * We are no longer sharing this buffer so we need * to transfer its ownership to the rightful owner. */ - zfs_refcount_transfer_ownership(&hdr->b_l1hdr.b_state->arcs_size, - hdr, buf); + zfs_refcount_transfer_ownership_many(&hdr->b_l1hdr.b_state->arcs_size, + arc_hdr_size(hdr), hdr, buf); arc_hdr_clear_flags(hdr, ARC_FLAG_SHARED_DATA); abd_release_ownership_of_buf(hdr->b_l1hdr.b_pabd); abd_put(hdr->b_l1hdr.b_pabd); |