diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/percpu.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index 83617ca3ba52..4a048abad043 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -1043,7 +1043,9 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) | |||
1043 | */ | 1043 | */ |
1044 | static void *pcpu_alloc(size_t size, size_t align, bool reserved) | 1044 | static void *pcpu_alloc(size_t size, size_t align, bool reserved) |
1045 | { | 1045 | { |
1046 | static int warn_limit = 10; | ||
1046 | struct pcpu_chunk *chunk; | 1047 | struct pcpu_chunk *chunk; |
1048 | const char *err; | ||
1047 | int slot, off; | 1049 | int slot, off; |
1048 | 1050 | ||
1049 | if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) { | 1051 | 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 | if (reserved && pcpu_reserved_chunk) { | 1061 | if (reserved && pcpu_reserved_chunk) { |
1060 | chunk = pcpu_reserved_chunk; | 1062 | chunk = pcpu_reserved_chunk; |
1061 | if (size > chunk->contig_hint || | 1063 | if (size > chunk->contig_hint || |
1062 | pcpu_extend_area_map(chunk) < 0) | 1064 | pcpu_extend_area_map(chunk) < 0) { |
1065 | err = "failed to extend area map of reserved chunk"; | ||
1063 | goto fail_unlock; | 1066 | goto fail_unlock; |
1067 | } | ||
1064 | off = pcpu_alloc_area(chunk, size, align); | 1068 | off = pcpu_alloc_area(chunk, size, align); |
1065 | if (off >= 0) | 1069 | if (off >= 0) |
1066 | goto area_found; | 1070 | goto area_found; |
1071 | err = "alloc from reserved chunk failed"; | ||
1067 | goto fail_unlock; | 1072 | goto fail_unlock; |
1068 | } | 1073 | } |
1069 | 1074 | ||
@@ -1080,6 +1085,7 @@ restart: | |||
1080 | case 1: | 1085 | case 1: |
1081 | goto restart; /* pcpu_lock dropped, restart */ | 1086 | goto restart; /* pcpu_lock dropped, restart */ |
1082 | default: | 1087 | default: |
1088 | err = "failed to extend area map"; | ||
1083 | goto fail_unlock; | 1089 | goto fail_unlock; |
1084 | } | 1090 | } |
1085 | 1091 | ||
@@ -1093,8 +1099,10 @@ restart: | |||
1093 | spin_unlock_irq(&pcpu_lock); | 1099 | spin_unlock_irq(&pcpu_lock); |
1094 | 1100 | ||
1095 | chunk = alloc_pcpu_chunk(); | 1101 | chunk = alloc_pcpu_chunk(); |
1096 | if (!chunk) | 1102 | if (!chunk) { |
1103 | err = "failed to allocate new chunk"; | ||
1097 | goto fail_unlock_mutex; | 1104 | goto fail_unlock_mutex; |
1105 | } | ||
1098 | 1106 | ||
1099 | spin_lock_irq(&pcpu_lock); | 1107 | spin_lock_irq(&pcpu_lock); |
1100 | pcpu_chunk_relocate(chunk, -1); | 1108 | pcpu_chunk_relocate(chunk, -1); |
@@ -1107,6 +1115,7 @@ area_found: | |||
1107 | if (pcpu_populate_chunk(chunk, off, size)) { | 1115 | if (pcpu_populate_chunk(chunk, off, size)) { |
1108 | spin_lock_irq(&pcpu_lock); | 1116 | spin_lock_irq(&pcpu_lock); |
1109 | pcpu_free_area(chunk, off); | 1117 | pcpu_free_area(chunk, off); |
1118 | err = "failed to populate"; | ||
1110 | goto fail_unlock; | 1119 | goto fail_unlock; |
1111 | } | 1120 | } |
1112 | 1121 | ||
@@ -1119,6 +1128,13 @@ fail_unlock: | |||
1119 | spin_unlock_irq(&pcpu_lock); | 1128 | spin_unlock_irq(&pcpu_lock); |
1120 | fail_unlock_mutex: | 1129 | fail_unlock_mutex: |
1121 | mutex_unlock(&pcpu_alloc_mutex); | 1130 | mutex_unlock(&pcpu_alloc_mutex); |
1131 | if (warn_limit) { | ||
1132 | pr_warning("PERCPU: allocation failed, size=%zu align=%zu, " | ||
1133 | "%s\n", size, align, err); | ||
1134 | dump_stack(); | ||
1135 | if (!--warn_limit) | ||
1136 | pr_info("PERCPU: limit reached, disable warning\n"); | ||
1137 | } | ||
1122 | return NULL; | 1138 | return NULL; |
1123 | } | 1139 | } |
1124 | 1140 | ||