Skip to content

Commit e829a86

Browse files
authored
Use more atomics in refcounts
Use atomic_load_64() for zfs_refcount_count() to prevent torn reads on 32-bit platforms. On 64-bit ones it should not change anything. When built with ZFS_DEBUG but running without tracking enabled use atomics instead of mutexes same as for builds without ZFS_DEBUG. Since rc_tracked can't change live we can check it without lock. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Matthew Ahrens <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored-By: iXsystems, Inc. Closes #12420
1 parent 5bfc3a9 commit e829a86

File tree

2 files changed

+26
-33
lines changed

2 files changed

+26
-33
lines changed

include/sys/zfs_refcount.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,22 +96,22 @@ typedef struct refcount {
9696
#define zfs_refcount_create_tracked(rc) ((rc)->rc_count = 0)
9797
#define zfs_refcount_destroy(rc) ((rc)->rc_count = 0)
9898
#define zfs_refcount_destroy_many(rc, number) ((rc)->rc_count = 0)
99-
#define zfs_refcount_is_zero(rc) ((rc)->rc_count == 0)
100-
#define zfs_refcount_count(rc) ((rc)->rc_count)
99+
#define zfs_refcount_is_zero(rc) (zfs_refcount_count(rc) == 0)
100+
#define zfs_refcount_count(rc) atomic_load_64(&(rc)->rc_count)
101101
#define zfs_refcount_add(rc, holder) atomic_inc_64_nv(&(rc)->rc_count)
102102
#define zfs_refcount_remove(rc, holder) atomic_dec_64_nv(&(rc)->rc_count)
103103
#define zfs_refcount_add_many(rc, number, holder) \
104104
atomic_add_64_nv(&(rc)->rc_count, number)
105105
#define zfs_refcount_remove_many(rc, number, holder) \
106106
atomic_add_64_nv(&(rc)->rc_count, -number)
107107
#define zfs_refcount_transfer(dst, src) { \
108-
uint64_t __tmp = (src)->rc_count; \
108+
uint64_t __tmp = zfs_refcount_count(src); \
109109
atomic_add_64(&(src)->rc_count, -__tmp); \
110110
atomic_add_64(&(dst)->rc_count, __tmp); \
111111
}
112112
#define zfs_refcount_transfer_ownership(rc, ch, nh) ((void)0)
113113
#define zfs_refcount_transfer_ownership_many(rc, nr, ch, nh) ((void)0)
114-
#define zfs_refcount_held(rc, holder) ((rc)->rc_count > 0)
114+
#define zfs_refcount_held(rc, holder) (zfs_refcount_count(rc) > 0)
115115
#define zfs_refcount_not_held(rc, holder) (B_TRUE)
116116

117117
#define zfs_refcount_init()

module/zfs/refcount.c

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ zfs_refcount_destroy(zfs_refcount_t *rc)
112112
int
113113
zfs_refcount_is_zero(zfs_refcount_t *rc)
114114
{
115-
return (rc->rc_count == 0);
115+
return (zfs_refcount_count(rc) == 0);
116116
}
117117

118118
int64_t
119119
zfs_refcount_count(zfs_refcount_t *rc)
120120
{
121-
return (rc->rc_count);
121+
return (atomic_load_64(&rc->rc_count));
122122
}
123123

124124
int64_t
@@ -127,15 +127,18 @@ zfs_refcount_add_many(zfs_refcount_t *rc, uint64_t number, const void *holder)
127127
reference_t *ref = NULL;
128128
int64_t count;
129129

130-
if (rc->rc_tracked) {
131-
ref = kmem_cache_alloc(reference_cache, KM_SLEEP);
132-
ref->ref_holder = holder;
133-
ref->ref_number = number;
130+
if (!rc->rc_tracked) {
131+
count = atomic_add_64_nv(&(rc)->rc_count, number);
132+
ASSERT3U(count, >=, number);
133+
return (count);
134134
}
135+
136+
ref = kmem_cache_alloc(reference_cache, KM_SLEEP);
137+
ref->ref_holder = holder;
138+
ref->ref_number = number;
135139
mutex_enter(&rc->rc_mtx);
136140
ASSERT3U(rc->rc_count, >=, 0);
137-
if (rc->rc_tracked)
138-
list_insert_head(&rc->rc_list, ref);
141+
list_insert_head(&rc->rc_list, ref);
139142
rc->rc_count += number;
140143
count = rc->rc_count;
141144
mutex_exit(&rc->rc_mtx);
@@ -156,16 +159,14 @@ zfs_refcount_remove_many(zfs_refcount_t *rc, uint64_t number,
156159
reference_t *ref;
157160
int64_t count;
158161

159-
mutex_enter(&rc->rc_mtx);
160-
ASSERT3U(rc->rc_count, >=, number);
161-
162162
if (!rc->rc_tracked) {
163-
rc->rc_count -= number;
164-
count = rc->rc_count;
165-
mutex_exit(&rc->rc_mtx);
163+
count = atomic_add_64_nv(&(rc)->rc_count, -number);
164+
ASSERT3S(count, >=, 0);
166165
return (count);
167166
}
168167

168+
mutex_enter(&rc->rc_mtx);
169+
ASSERT3U(rc->rc_count, >=, number);
169170
for (ref = list_head(&rc->rc_list); ref;
170171
ref = list_next(&rc->rc_list, ref)) {
171172
if (ref->ref_holder == holder && ref->ref_number == number) {
@@ -242,12 +243,10 @@ zfs_refcount_transfer_ownership_many(zfs_refcount_t *rc, uint64_t number,
242243
reference_t *ref;
243244
boolean_t found = B_FALSE;
244245

245-
mutex_enter(&rc->rc_mtx);
246-
if (!rc->rc_tracked) {
247-
mutex_exit(&rc->rc_mtx);
246+
if (!rc->rc_tracked)
248247
return;
249-
}
250248

249+
mutex_enter(&rc->rc_mtx);
251250
for (ref = list_head(&rc->rc_list); ref;
252251
ref = list_next(&rc->rc_list, ref)) {
253252
if (ref->ref_holder == current_holder &&
@@ -279,13 +278,10 @@ zfs_refcount_held(zfs_refcount_t *rc, const void *holder)
279278
{
280279
reference_t *ref;
281280

282-
mutex_enter(&rc->rc_mtx);
283-
284-
if (!rc->rc_tracked) {
285-
mutex_exit(&rc->rc_mtx);
286-
return (rc->rc_count > 0);
287-
}
281+
if (!rc->rc_tracked)
282+
return (zfs_refcount_count(rc) > 0);
288283

284+
mutex_enter(&rc->rc_mtx);
289285
for (ref = list_head(&rc->rc_list); ref;
290286
ref = list_next(&rc->rc_list, ref)) {
291287
if (ref->ref_holder == holder) {
@@ -307,13 +303,10 @@ zfs_refcount_not_held(zfs_refcount_t *rc, const void *holder)
307303
{
308304
reference_t *ref;
309305

310-
mutex_enter(&rc->rc_mtx);
311-
312-
if (!rc->rc_tracked) {
313-
mutex_exit(&rc->rc_mtx);
306+
if (!rc->rc_tracked)
314307
return (B_TRUE);
315-
}
316308

309+
mutex_enter(&rc->rc_mtx);
317310
for (ref = list_head(&rc->rc_list); ref;
318311
ref = list_next(&rc->rc_list, ref)) {
319312
if (ref->ref_holder == holder) {

0 commit comments

Comments
 (0)