Commit f2badb0c authored by Tejun Heo's avatar Tejun Heo

percpu: make allocation failures more verbose

Warn and dump stack when percpu allocation fails.  percpu allocator is
still young and unchecked NULL percpu pointer usage can result in
random memory corruption when combined with the pointer shifting in
access macros.  Allocation failures should be rare and the warning
message will be disabled after certain times.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent 635b75fc
...@@ -1043,7 +1043,9 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) ...@@ -1043,7 +1043,9 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void)
*/ */
static void *pcpu_alloc(size_t size, size_t align, bool reserved) static void *pcpu_alloc(size_t size, size_t align, bool reserved)
{ {
static int warn_limit = 10;
struct pcpu_chunk *chunk; struct pcpu_chunk *chunk;
const char *err;
int slot, off; int slot, off;
if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) { if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
...@@ -1059,11 +1061,14 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved) ...@@ -1059,11 +1061,14 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
if (reserved && pcpu_reserved_chunk) { if (reserved && pcpu_reserved_chunk) {
chunk = pcpu_reserved_chunk; chunk = pcpu_reserved_chunk;
if (size > chunk->contig_hint || if (size > chunk->contig_hint ||
pcpu_extend_area_map(chunk) < 0) pcpu_extend_area_map(chunk) < 0) {
err = "failed to extend area map of reserved chunk";
goto fail_unlock; goto fail_unlock;
}
off = pcpu_alloc_area(chunk, size, align); off = pcpu_alloc_area(chunk, size, align);
if (off >= 0) if (off >= 0)
goto area_found; goto area_found;
err = "alloc from reserved chunk failed";
goto fail_unlock; goto fail_unlock;
} }
...@@ -1080,6 +1085,7 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved) ...@@ -1080,6 +1085,7 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
case 1: case 1:
goto restart; /* pcpu_lock dropped, restart */ goto restart; /* pcpu_lock dropped, restart */
default: default:
err = "failed to extend area map";
goto fail_unlock; goto fail_unlock;
} }
...@@ -1093,8 +1099,10 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved) ...@@ -1093,8 +1099,10 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
spin_unlock_irq(&pcpu_lock); spin_unlock_irq(&pcpu_lock);
chunk = alloc_pcpu_chunk(); chunk = alloc_pcpu_chunk();
if (!chunk) if (!chunk) {
err = "failed to allocate new chunk";
goto fail_unlock_mutex; goto fail_unlock_mutex;
}
spin_lock_irq(&pcpu_lock); spin_lock_irq(&pcpu_lock);
pcpu_chunk_relocate(chunk, -1); pcpu_chunk_relocate(chunk, -1);
...@@ -1107,6 +1115,7 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved) ...@@ -1107,6 +1115,7 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
if (pcpu_populate_chunk(chunk, off, size)) { if (pcpu_populate_chunk(chunk, off, size)) {
spin_lock_irq(&pcpu_lock); spin_lock_irq(&pcpu_lock);
pcpu_free_area(chunk, off); pcpu_free_area(chunk, off);
err = "failed to populate";
goto fail_unlock; goto fail_unlock;
} }
...@@ -1119,6 +1128,13 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved) ...@@ -1119,6 +1128,13 @@ static void *pcpu_alloc(size_t size, size_t align, bool reserved)
spin_unlock_irq(&pcpu_lock); spin_unlock_irq(&pcpu_lock);
fail_unlock_mutex: fail_unlock_mutex:
mutex_unlock(&pcpu_alloc_mutex); mutex_unlock(&pcpu_alloc_mutex);
if (warn_limit) {
pr_warning("PERCPU: allocation failed, size=%zu align=%zu, "
"%s\n", size, align, err);
dump_stack();
if (!--warn_limit)
pr_info("PERCPU: limit reached, disable warning\n");
}
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment