diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-10 07:26:02 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-10 07:26:02 -0400 |
| commit | c798360cd1438090d51eeaa8e67985da11362eba (patch) | |
| tree | 0107d3b9ee7476264c3357287787d393545bd2d9 /lib | |
| parent | b211e9d7c861bdb37b86d6384da9edfb80949ceb (diff) | |
| parent | 6ae833c7fe0c6ef1f0ab13cc775da230d6f4c256 (diff) | |
Merge branch 'for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
Pull percpu updates from Tejun Heo:
"A lot of activities on percpu front. Notable changes are...
- percpu allocator now can take @gfp. If @gfp doesn't contain
GFP_KERNEL, it tries to allocate from what's already available to
the allocator and a work item tries to keep the reserve around
certain level so that these atomic allocations usually succeed.
This will replace the ad-hoc percpu memory pool used by
blk-throttle and also be used by the planned blkcg support for
writeback IOs.
Please note that I noticed a bug in how @gfp is interpreted while
preparing this pull request and applied the fix 6ae833c7fe0c
("percpu: fix how @gfp is interpreted by the percpu allocator")
just now.
- percpu_ref now uses longs for percpu and global counters instead of
ints. It leads to more sparse packing of the percpu counters on
64bit machines but the overhead should be negligible and this
allows using percpu_ref for refcnting pages and in-memory objects
directly.
- The switching between percpu and single counter modes of a
percpu_ref is made independent of putting the base ref and a
percpu_ref can now optionally be initialized in single or killed
mode. This allows avoiding percpu shutdown latency for cases where
the refcounted objects may be synchronously created and destroyed
in rapid succession with only a fraction of them reaching fully
operational status (SCSI probing does this when combined with
blk-mq support). It's also planned to be used to implement forced
single mode to detect underflow more timely for debugging.
There's a separate branch percpu/for-3.18-consistent-ops which cleans
up the duplicate percpu accessors. That branch causes a number of
conflicts with s390 and other trees. I'll send a separate pull
request w/ resolutions once other branches are merged"
* 'for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu: (33 commits)
percpu: fix how @gfp is interpreted by the percpu allocator
blk-mq, percpu_ref: start q->mq_usage_counter in atomic mode
percpu_ref: make INIT_ATOMIC and switch_to_atomic() sticky
percpu_ref: add PERCPU_REF_INIT_* flags
percpu_ref: decouple switching to percpu mode and reinit
percpu_ref: decouple switching to atomic mode and killing
percpu_ref: add PCPU_REF_DEAD
percpu_ref: rename things to prepare for decoupling percpu/atomic mode switch
percpu_ref: replace pcpu_ prefix with percpu_
percpu_ref: minor code and comment updates
percpu_ref: relocate percpu_ref_reinit()
Revert "blk-mq, percpu_ref: implement a kludge for SCSI blk-mq stall during probe"
Revert "percpu: free percpu allocation info for uniprocessor system"
percpu-refcount: make percpu_ref based on longs instead of ints
percpu-refcount: improve WARN messages
percpu: fix locking regression in the failure path of pcpu_alloc()
percpu-refcount: add @gfp to percpu_ref_init()
proportions: add @gfp to init functions
percpu_counter: add @gfp to percpu_counter_init()
percpu_counter: make percpu_counters_lock irq-safe
...
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/flex_proportions.c | 8 | ||||
| -rw-r--r-- | lib/percpu-refcount.c | 305 | ||||
| -rw-r--r-- | lib/percpu_counter.c | 20 | ||||
| -rw-r--r-- | lib/proportions.c | 10 |
4 files changed, 238 insertions, 105 deletions
diff --git a/lib/flex_proportions.c b/lib/flex_proportions.c index ebf3bac460b0..8f25652f40d4 100644 --- a/lib/flex_proportions.c +++ b/lib/flex_proportions.c | |||
| @@ -34,13 +34,13 @@ | |||
| 34 | */ | 34 | */ |
| 35 | #include <linux/flex_proportions.h> | 35 | #include <linux/flex_proportions.h> |
| 36 | 36 | ||
| 37 | int fprop_global_init(struct fprop_global *p) | 37 | int fprop_global_init(struct fprop_global *p, gfp_t gfp) |
| 38 | { | 38 | { |
| 39 | int err; | 39 | int err; |
| 40 | 40 | ||
| 41 | p->period = 0; | 41 | p->period = 0; |
| 42 | /* Use 1 to avoid dealing with periods with 0 events... */ | 42 | /* Use 1 to avoid dealing with periods with 0 events... */ |
| 43 | err = percpu_counter_init(&p->events, 1); | 43 | err = percpu_counter_init(&p->events, 1, gfp); |
| 44 | if (err) | 44 | if (err) |
| 45 | return err; | 45 | return err; |
| 46 | seqcount_init(&p->sequence); | 46 | seqcount_init(&p->sequence); |
| @@ -168,11 +168,11 @@ void fprop_fraction_single(struct fprop_global *p, | |||
| 168 | */ | 168 | */ |
| 169 | #define PROP_BATCH (8*(1+ilog2(nr_cpu_ids))) | 169 | #define PROP_BATCH (8*(1+ilog2(nr_cpu_ids))) |
| 170 | 170 | ||
| 171 | int fprop_local_init_percpu(struct fprop_local_percpu *pl) | 171 | int fprop_local_init_percpu(struct fprop_local_percpu *pl, gfp_t gfp) |
| 172 | { | 172 | { |
| 173 | int err; | 173 | int err; |
| 174 | 174 | ||
| 175 | err = percpu_counter_init(&pl->events, 0); | 175 | err = percpu_counter_init(&pl->events, 0, gfp); |
| 176 | if (err) | 176 | if (err) |
| 177 | return err; | 177 | return err; |
| 178 | pl->period = 0; | 178 | pl->period = 0; |
diff --git a/lib/percpu-refcount.c b/lib/percpu-refcount.c index a89cf09a8268..6111bcb28376 100644 --- a/lib/percpu-refcount.c +++ b/lib/percpu-refcount.c | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #define pr_fmt(fmt) "%s: " fmt "\n", __func__ | 1 | #define pr_fmt(fmt) "%s: " fmt "\n", __func__ |
| 2 | 2 | ||
| 3 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/wait.h> | ||
| 4 | #include <linux/percpu-refcount.h> | 6 | #include <linux/percpu-refcount.h> |
| 5 | 7 | ||
| 6 | /* | 8 | /* |
| @@ -11,8 +13,8 @@ | |||
| 11 | * percpu counters will all sum to the correct value | 13 | * percpu counters will all sum to the correct value |
| 12 | * | 14 | * |
| 13 | * (More precisely: because moduler arithmatic is commutative the sum of all the | 15 | * (More precisely: because moduler arithmatic is commutative the sum of all the |
| 14 | * pcpu_count vars will be equal to what it would have been if all the gets and | 16 | * percpu_count vars will be equal to what it would have been if all the gets |
| 15 | * puts were done to a single integer, even if some of the percpu integers | 17 | * and puts were done to a single integer, even if some of the percpu integers |
| 16 | * overflow or underflow). | 18 | * overflow or underflow). |
| 17 | * | 19 | * |
| 18 | * The real trick to implementing percpu refcounts is shutdown. We can't detect | 20 | * The real trick to implementing percpu refcounts is shutdown. We can't detect |
| @@ -25,75 +27,64 @@ | |||
| 25 | * works. | 27 | * works. |
| 26 | * | 28 | * |
| 27 | * Converting to non percpu mode is done with some RCUish stuff in | 29 | * Converting to non percpu mode is done with some RCUish stuff in |
| 28 | * percpu_ref_kill. Additionally, we need a bias value so that the atomic_t | 30 | * percpu_ref_kill. Additionally, we need a bias value so that the |
| 29 | * can't hit 0 before we've added up all the percpu refs. | 31 | * atomic_long_t can't hit 0 before we've added up all the percpu refs. |
| 30 | */ | 32 | */ |
| 31 | 33 | ||
| 32 | #define PCPU_COUNT_BIAS (1U << 31) | 34 | #define PERCPU_COUNT_BIAS (1LU << (BITS_PER_LONG - 1)) |
| 33 | 35 | ||
| 34 | static unsigned __percpu *pcpu_count_ptr(struct percpu_ref *ref) | 36 | static DECLARE_WAIT_QUEUE_HEAD(percpu_ref_switch_waitq); |
| 37 | |||
| 38 | static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref) | ||
| 35 | { | 39 | { |
| 36 | return (unsigned __percpu *)(ref->pcpu_count_ptr & ~PCPU_REF_DEAD); | 40 | return (unsigned long __percpu *) |
| 41 | (ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC_DEAD); | ||
| 37 | } | 42 | } |
| 38 | 43 | ||
| 39 | /** | 44 | /** |
| 40 | * percpu_ref_init - initialize a percpu refcount | 45 | * percpu_ref_init - initialize a percpu refcount |
| 41 | * @ref: percpu_ref to initialize | 46 | * @ref: percpu_ref to initialize |
| 42 | * @release: function which will be called when refcount hits 0 | 47 | * @release: function which will be called when refcount hits 0 |
| 48 | * @flags: PERCPU_REF_INIT_* flags | ||
| 49 | * @gfp: allocation mask to use | ||
| 43 | * | 50 | * |
| 44 | * Initializes the refcount in single atomic counter mode with a refcount of 1; | 51 | * Initializes @ref. If @flags is zero, @ref starts in percpu mode with a |
| 45 | * analagous to atomic_set(ref, 1). | 52 | * refcount of 1; analagous to atomic_long_set(ref, 1). See the |
| 53 | * definitions of PERCPU_REF_INIT_* flags for flag behaviors. | ||
| 46 | * | 54 | * |
| 47 | * Note that @release must not sleep - it may potentially be called from RCU | 55 | * Note that @release must not sleep - it may potentially be called from RCU |
| 48 | * callback context by percpu_ref_kill(). | 56 | * callback context by percpu_ref_kill(). |
| 49 | */ | 57 | */ |
| 50 | int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release) | 58 | int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release, |
| 59 | unsigned int flags, gfp_t gfp) | ||
| 51 | { | 60 | { |
| 52 | atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS); | 61 | size_t align = max_t(size_t, 1 << __PERCPU_REF_FLAG_BITS, |
| 62 | __alignof__(unsigned long)); | ||
| 63 | unsigned long start_count = 0; | ||
| 53 | 64 | ||
| 54 | ref->pcpu_count_ptr = (unsigned long)alloc_percpu(unsigned); | 65 | ref->percpu_count_ptr = (unsigned long) |
| 55 | if (!ref->pcpu_count_ptr) | 66 | __alloc_percpu_gfp(sizeof(unsigned long), align, gfp); |
| 67 | if (!ref->percpu_count_ptr) | ||
| 56 | return -ENOMEM; | 68 | return -ENOMEM; |
| 57 | 69 | ||
| 58 | ref->release = release; | 70 | ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC; |
| 59 | return 0; | ||
| 60 | } | ||
| 61 | EXPORT_SYMBOL_GPL(percpu_ref_init); | ||
| 62 | |||
| 63 | /** | ||
| 64 | * percpu_ref_reinit - re-initialize a percpu refcount | ||
| 65 | * @ref: perpcu_ref to re-initialize | ||
| 66 | * | ||
| 67 | * Re-initialize @ref so that it's in the same state as when it finished | ||
| 68 | * percpu_ref_init(). @ref must have been initialized successfully, killed | ||
| 69 | * and reached 0 but not exited. | ||
| 70 | * | ||
| 71 | * Note that percpu_ref_tryget[_live]() are safe to perform on @ref while | ||
| 72 | * this function is in progress. | ||
| 73 | */ | ||
| 74 | void percpu_ref_reinit(struct percpu_ref *ref) | ||
| 75 | { | ||
| 76 | unsigned __percpu *pcpu_count = pcpu_count_ptr(ref); | ||
| 77 | int cpu; | ||
| 78 | 71 | ||
| 79 | BUG_ON(!pcpu_count); | 72 | if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) |
| 80 | WARN_ON(!percpu_ref_is_zero(ref)); | 73 | ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; |
| 74 | else | ||
| 75 | start_count += PERCPU_COUNT_BIAS; | ||
| 81 | 76 | ||
| 82 | atomic_set(&ref->count, 1 + PCPU_COUNT_BIAS); | 77 | if (flags & PERCPU_REF_INIT_DEAD) |
| 78 | ref->percpu_count_ptr |= __PERCPU_REF_DEAD; | ||
| 79 | else | ||
| 80 | start_count++; | ||
| 83 | 81 | ||
| 84 | /* | 82 | atomic_long_set(&ref->count, start_count); |
| 85 | * Restore per-cpu operation. smp_store_release() is paired with | ||
| 86 | * smp_read_barrier_depends() in __pcpu_ref_alive() and guarantees | ||
| 87 | * that the zeroing is visible to all percpu accesses which can see | ||
| 88 | * the following PCPU_REF_DEAD clearing. | ||
| 89 | */ | ||
| 90 | for_each_possible_cpu(cpu) | ||
| 91 | *per_cpu_ptr(pcpu_count, cpu) = 0; | ||
| 92 | 83 | ||
| 93 | smp_store_release(&ref->pcpu_count_ptr, | 84 | ref->release = release; |
| 94 | ref->pcpu_count_ptr & ~PCPU_REF_DEAD); | 85 | return 0; |
| 95 | } | 86 | } |
| 96 | EXPORT_SYMBOL_GPL(percpu_ref_reinit); | 87 | EXPORT_SYMBOL_GPL(percpu_ref_init); |
| 97 | |||
