diff options
author | Roman Gushchin <guro@fb.com> | 2019-05-07 13:01:50 -0400 |
---|---|---|
committer | Dennis Zhou <dennis@kernel.org> | 2019-05-09 13:51:06 -0400 |
commit | 7d9ab9b6adffd9c474c1274acb5f6208f9a09cf3 (patch) | |
tree | 461ee811d60454e5e21fb6f567ec2e2435575a12 | |
parent | ddde2af747ad79010f14691f381522987fbcb860 (diff) |
percpu_ref: release percpu memory early without PERCPU_REF_ALLOW_REINIT
Release percpu memory after finishing the switch to the atomic mode
if only PERCPU_REF_ALLOW_REINIT isn't set.
Signed-off-by: Roman Gushchin <guro@fb.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Dennis Zhou <dennis@kernel.org>
-rw-r--r-- | include/linux/percpu-refcount.h | 1 | ||||
-rw-r--r-- | lib/percpu-refcount.c | 13 |
2 files changed, 12 insertions, 2 deletions
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h index 0f0240af8520..7aef0abc194a 100644 --- a/include/linux/percpu-refcount.h +++ b/include/linux/percpu-refcount.h | |||
@@ -102,6 +102,7 @@ struct percpu_ref { | |||
102 | percpu_ref_func_t *release; | 102 | percpu_ref_func_t *release; |
103 | percpu_ref_func_t *confirm_switch; | 103 | percpu_ref_func_t *confirm_switch; |
104 | bool force_atomic:1; | 104 | bool force_atomic:1; |
105 | bool allow_reinit:1; | ||
105 | struct rcu_head rcu; | 106 | struct rcu_head rcu; |
106 | }; | 107 | }; |
107 | 108 | ||
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index 9877682e49c7..501b517bd3db 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c | |||
@@ -69,11 +69,14 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release, | |||
69 | return -ENOMEM; | 69 | return -ENOMEM; |
70 | 70 | ||
71 | ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC; | 71 | ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC; |
72 | ref->allow_reinit = flags & PERCPU_REF_ALLOW_REINIT; | ||
72 | 73 | ||
73 | if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) | 74 | if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) { |
74 | ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; | 75 | ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; |
75 | else | 76 | ref->allow_reinit = true; |
77 | } else { | ||
76 | start_count += PERCPU_COUNT_BIAS; | 78 | start_count += PERCPU_COUNT_BIAS; |
79 | } | ||
77 | 80 | ||
78 | if (flags & PERCPU_REF_INIT_DEAD) | 81 | if (flags & PERCPU_REF_INIT_DEAD) |
79 | ref->percpu_count_ptr |= __PERCPU_REF_DEAD; | 82 | ref->percpu_count_ptr |= __PERCPU_REF_DEAD; |
@@ -119,6 +122,9 @@ static void percpu_ref_call_confirm_rcu(struct rcu_head *rcu) | |||
119 | ref->confirm_switch = NULL; | 122 | ref->confirm_switch = NULL; |
120 | wake_up_all(&percpu_ref_switch_waitq); | 123 | wake_up_all(&percpu_ref_switch_waitq); |
121 | 124 | ||
125 | if (!ref->allow_reinit) | ||
126 | percpu_ref_exit(ref); | ||
127 | |||
122 | /* drop ref from percpu_ref_switch_to_atomic() */ | 128 | /* drop ref from percpu_ref_switch_to_atomic() */ |
123 | percpu_ref_put(ref); | 129 | percpu_ref_put(ref); |
124 | } | 130 | } |
@@ -194,6 +200,9 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) | |||
194 | if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) | 200 | if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) |
195 | return; | 201 | return; |
196 | 202 | ||
203 | if (WARN_ON_ONCE(!ref->allow_reinit)) | ||
204 | return; | ||
205 | |||
197 | atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); | 206 | atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); |
198 | 207 | ||
199 | /* | 208 | /* |