Merge branch 'for-4.14-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 3 Oct 2017 17:05:12 +0000 (10:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 3 Oct 2017 17:05:12 +0000 (10:05 -0700)
Pull percpu fixes from Tejun Heo:
 "Rather important fixes this time.

   - The new percpu area allocator had a subtle bug in how it iterates
     the memory regions and could skip viable areas, which led to
     allocation failures for module static percpu variables. Dennis
     fixed the bug and another non-critical one in stat calculation.

   - Mark noticed that the generic implementations of percpu local
     atomic reads aren't properly protected against irqs and there's a
     (slim) chance for split reads on some 32bit systems. Generic
     implementations are updated to disable irq when read size is larger
     than ulong size. This may have made some 32bit archs which can do
     atomic local 64bit accesses generate sub-optimal code. We need to
     find them out and implement arch-specific overrides"

* 'for-4.14-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu:
  percpu: fix iteration to prevent skipping over block
  percpu: fix starting offset for chunk statistics traversal
  percpu: make this_cpu_generic_read() atomic w.r.t. interrupts

include/asm-generic/percpu.h
mm/percpu-stats.c
mm/percpu.c

index 0504ef8f3aa31d5e7a9f0d86d1cb3fc130fee9e0..976f8ac26665b3f4f03cbbfe5222277d9827d847 100644 (file)
@@ -115,15 +115,35 @@ do {                                                                      \
        (__ret);                                                        \
 })
 
-#define this_cpu_generic_read(pcp)                                     \
+#define __this_cpu_generic_read_nopreempt(pcp)                         \
 ({                                                                     \
        typeof(pcp) __ret;                                              \
        preempt_disable_notrace();                                      \
-       __ret = raw_cpu_generic_read(pcp);                              \
+       __ret = READ_ONCE(*raw_cpu_ptr(&(pcp)));                        \
        preempt_enable_notrace();                                       \
        __ret;                                                          \
 })
 
+#define __this_cpu_generic_read_noirq(pcp)                             \
+({                                                                     \
+       typeof(pcp) __ret;                                              \
+       unsigned long __flags;                                          \
+       raw_local_irq_save(__flags);                                    \
+       __ret = raw_cpu_generic_read(pcp);                              \
+       raw_local_irq_restore(__flags);                                 \
+       __ret;                                                          \
+})
+
+#define this_cpu_generic_read(pcp)                                     \
+({                                                                     \
+       typeof(pcp) __ret;                                              \
+       if (__native_word(pcp))                                         \
+               __ret = __this_cpu_generic_read_nopreempt(pcp);         \
+       else                                                            \
+               __ret = __this_cpu_generic_read_noirq(pcp);             \
+       __ret;                                                          \
+})
+
 #define this_cpu_generic_to_op(pcp, val, op)                           \
 do {                                                                   \
        unsigned long __flags;                                          \
index 6142484e88f79c3e946b30de136a2886c075ffe7..7a58460bfd27a303c7ab4d3c4f10abac02c15603 100644 (file)
@@ -73,7 +73,7 @@ static void chunk_map_stats(struct seq_file *m, struct pcpu_chunk *chunk,
                     last_alloc + 1 : 0;
 
        as_len = 0;
-       start = chunk->start_offset;
+       start = chunk->start_offset / PCPU_MIN_ALLOC_SIZE;
 
        /*
         * If a bit is set in the allocation map, the bound_map identifies
index 59d44d61f5f198b26be07ff264395a6b30cc091d..aa121cef76de338441f3dbcf5e3e0d1de9f0aebf 100644 (file)
@@ -353,6 +353,8 @@ static void pcpu_next_md_free_region(struct pcpu_chunk *chunk, int *bit_off,
                                        block->contig_hint_start);
                        return;
                }
+               /* reset to satisfy the second predicate above */
+               block_off = 0;
 
                *bits = block->right_free;
                *bit_off = (i + 1) * PCPU_BITMAP_BLOCK_BITS - block->right_free;
@@ -407,6 +409,8 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits,
                        *bit_off = pcpu_block_off_to_off(i, block->first_free);
                        return;
                }
+               /* reset to satisfy the second predicate above */
+               block_off = 0;
 
                *bit_off = ALIGN(PCPU_BITMAP_BLOCK_BITS - block->right_free,
                                 align);