aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-14 19:17:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-14 19:17:18 -0400
commita1240cf74e8228f7c80d44af17914c0ffc5633fb (patch)
treeab8c5841940f9d20e6ffb6c91301a4146b63fdb8
parent1d039859330b874d48080885eb31f4f129c246f1 (diff)
parent7d9ab9b6adffd9c474c1274acb5f6208f9a09cf3 (diff)
Merge branch 'for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu
Pull percpu updates from Dennis Zhou: "This includes changes to let percpu_ref release the backing percpu memory earlier after it has been switched to atomic in cases where the percpu ref is not revived. This will help recycle percpu memory earlier in cases where the refcounts are pinned for prolonged periods of time" * 'for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/dennis/percpu: percpu_ref: release percpu memory early without PERCPU_REF_ALLOW_REINIT md: initialize percpu refcounters using PERCU_REF_ALLOW_REINIT io_uring: initialize percpu refcounters using PERCU_REF_ALLOW_REINIT percpu_ref: introduce PERCPU_REF_ALLOW_REINIT flag
-rw-r--r--drivers/md/md.c3
-rw-r--r--fs/io_uring.c3
-rw-r--r--include/linux/percpu-refcount.h10
-rw-r--r--lib/percpu-refcount.c13
4 files changed, 24 insertions, 5 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index a114b05e3db4..24638ccedce4 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5316,7 +5316,8 @@ int mddev_init_writes_pending(struct mddev *mddev)
5316{ 5316{
5317 if (mddev->writes_pending.percpu_count_ptr) 5317 if (mddev->writes_pending.percpu_count_ptr)
5318 return 0; 5318 return 0;
5319 if (percpu_ref_init(&mddev->writes_pending, no_op, 0, GFP_KERNEL) < 0) 5319 if (percpu_ref_init(&mddev->writes_pending, no_op,
5320 PERCPU_REF_ALLOW_REINIT, GFP_KERNEL) < 0)
5320 return -ENOMEM; 5321 return -ENOMEM;
5321 /* We want to start with the refcount at zero */ 5322 /* We want to start with the refcount at zero */
5322 percpu_ref_put(&mddev->writes_pending); 5323 percpu_ref_put(&mddev->writes_pending);
diff --git a/fs/io_uring.c b/fs/io_uring.c
index 3fd884b4e0be..d682049c07b2 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -399,7 +399,8 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
399 if (!ctx) 399 if (!ctx)
400 return NULL; 400 return NULL;
401 401
402 if (percpu_ref_init(&ctx->refs, io_ring_ctx_ref_free, 0, GFP_KERNEL)) { 402 if (percpu_ref_init(&ctx->refs, io_ring_ctx_ref_free,
403 PERCPU_REF_ALLOW_REINIT, GFP_KERNEL)) {
403 kfree(ctx); 404 kfree(ctx);
404 return NULL; 405 return NULL;
405 } 406 }
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index b297cd1cd4f1..7aef0abc194a 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -75,14 +75,21 @@ enum {
75 * operation using percpu_ref_switch_to_percpu(). If initialized 75 * operation using percpu_ref_switch_to_percpu(). If initialized
76 * with this flag, the ref will stay in atomic mode until 76 * with this flag, the ref will stay in atomic mode until
77 * percpu_ref_switch_to_percpu() is invoked on it. 77 * percpu_ref_switch_to_percpu() is invoked on it.
78 * Implies ALLOW_REINIT.
78 */ 79 */
79 PERCPU_REF_INIT_ATOMIC = 1 << 0, 80 PERCPU_REF_INIT_ATOMIC = 1 << 0,
80 81
81 /* 82 /*
82 * Start dead w/ ref == 0 in atomic mode. Must be revived with 83 * Start dead w/ ref == 0 in atomic mode. Must be revived with
83 * percpu_ref_reinit() before used. Implies INIT_ATOMIC. 84 * percpu_ref_reinit() before used. Implies INIT_ATOMIC and
85 * ALLOW_REINIT.
84 */ 86 */
85 PERCPU_REF_INIT_DEAD = 1 << 1, 87 PERCPU_REF_INIT_DEAD = 1 << 1,
88
89 /*
90 * Allow switching from atomic mode to percpu mode.
91 */
92 PERCPU_REF_ALLOW_REINIT = 1 << 2,
86}; 93};
87 94
88struct percpu_ref { 95struct percpu_ref {
@@ -95,6 +102,7 @@ struct percpu_ref {
95 percpu_ref_func_t *release; 102 percpu_ref_func_t *release;
96 percpu_ref_func_t *confirm_switch; 103 percpu_ref_func_t *confirm_switch;
97 bool force_atomic:1; 104 bool force_atomic:1;
105 bool allow_reinit:1;
98 struct rcu_head rcu; 106 struct rcu_head rcu;
99}; 107};
100 108
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c
index 071a76c7bac0..4f6c6ebbbbde 100644
--- a/lib/percpu-refcount.c
+++ b/lib/percpu-refcount.c
@@ -70,11 +70,14 @@ int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release,
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC; 72 ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC;
73 ref->allow_reinit = flags & PERCPU_REF_ALLOW_REINIT;
73 74
74 if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) 75 if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) {
75 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; 76 ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC;
76 else 77 ref->allow_reinit = true;
78 } else {
77 start_count += PERCPU_COUNT_BIAS; 79 start_count += PERCPU_COUNT_BIAS;
80 }
78 81
79 if (flags & PERCPU_REF_INIT_DEAD) 82 if (flags & PERCPU_REF_INIT_DEAD)
80 ref->percpu_count_ptr |= __PERCPU_REF_DEAD; 83 ref->percpu_count_ptr |= __PERCPU_REF_DEAD;
@@ -120,6 +123,9 @@ static void percpu_ref_call_confirm_rcu(struct rcu_head *rcu)
120 ref->confirm_switch = NULL; 123 ref->confirm_switch = NULL;
121 wake_up_all(&percpu_ref_switch_waitq); 124 wake_up_all(&percpu_ref_switch_waitq);
122 125
126 if (!ref->allow_reinit)
127 percpu_ref_exit(ref);
128
123 /* drop ref from percpu_ref_switch_to_atomic() */ 129 /* drop ref from percpu_ref_switch_to_atomic() */
124 percpu_ref_put(ref); 130 percpu_ref_put(ref);
125} 131}
@@ -195,6 +201,9 @@ static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref)
195 if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) 201 if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC))
196 return; 202 return;
197 203
204 if (WARN_ON_ONCE(!ref->allow_reinit))
205 return;
206
198 atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); 207 atomic_long_add(PERCPU_COUNT_BIAS, &ref->count);
199 208
200 /* 209 /*