aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2012-07-03 07:55:37 -0400
committerAlasdair G Kergon <agk@redhat.com>2012-07-03 07:55:37 -0400
commitb0239faaf87c38bb419c9264bf20817438ddc3a9 (patch)
treecc91fa9575c0900e5e26a0aa5edca2dc29cd37ca /drivers/md
parent62662303e7f590fdfbb0070ab820a0ad4267c119 (diff)
dm persistent data: fix allocation failure in space map checker init
If CONFIG_DM_DEBUG_SPACE_MAPS is enabled and memory is fragmented and a sufficiently-large metadata device is used in a thin pool then the space map checker will fail to allocate the memory it requires. Switch from kmalloc to vmalloc to allow larger virtually contiguous allocations for the space map checker's internal count arrays. Reported-by: Vivek Goyal <vgoyal@redhat.com> Cc: stable@kernel.org Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/persistent-data/dm-space-map-checker.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c
index 6d7c8329250..fc90c11620a 100644
--- a/drivers/md/persistent-data/dm-space-map-checker.c
+++ b/drivers/md/persistent-data/dm-space-map-checker.c
@@ -8,6 +8,7 @@
8 8
9#include <linux/device-mapper.h> 9#include <linux/device-mapper.h>
10#include <linux/export.h> 10#include <linux/export.h>
11#include <linux/vmalloc.h>
11 12
12#ifdef CONFIG_DM_DEBUG_SPACE_MAPS 13#ifdef CONFIG_DM_DEBUG_SPACE_MAPS
13 14
@@ -89,13 +90,23 @@ static int ca_create(struct count_array *ca, struct dm_space_map *sm)
89 90
90 ca->nr = nr_blocks; 91 ca->nr = nr_blocks;
91 ca->nr_free = nr_blocks; 92 ca->nr_free = nr_blocks;
92 ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL); 93
93 if (!ca->counts) 94 if (!nr_blocks)
94 return -ENOMEM; 95 ca->counts = NULL;
96 else {
97 ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks);
98 if (!ca->counts)
99 return -ENOMEM;
100 }
95 101
96 return 0; 102 return 0;
97} 103}
98 104
105static void ca_destroy(struct count_array *ca)
106{
107 vfree(ca->counts);
108}
109
99static int ca_load(struct count_array *ca, struct dm_space_map *sm) 110static int ca_load(struct count_array *ca, struct dm_space_map *sm)
100{ 111{
101 int r; 112 int r;
@@ -126,12 +137,14 @@ static int ca_load(struct count_array *ca, struct dm_space_map *sm)
126static int ca_extend(struct count_array *ca, dm_block_t extra_blocks) 137static int ca_extend(struct count_array *ca, dm_block_t extra_blocks)
127{ 138{
128 dm_block_t nr_blocks = ca->nr + extra_blocks; 139 dm_block_t nr_blocks = ca->nr + extra_blocks;
129 uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL); 140 uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks);
130 if (!counts) 141 if (!counts)
131 return -ENOMEM; 142 return -ENOMEM;
132 143
133 memcpy(counts, ca->counts, sizeof(*counts) * ca->nr); 144 if (ca->counts) {
134 kfree(ca->counts); 145 memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
146 ca_destroy(ca);
147 }
135 ca->nr = nr_blocks; 148 ca->nr = nr_blocks;
136 ca->nr_free += extra_blocks; 149 ca->nr_free += extra_blocks;
137 ca->counts = counts; 150 ca->counts = counts;
@@ -151,11 +164,6 @@ static int ca_commit(struct count_array *old, struct count_array *new)
151 return 0; 164 return 0;
152} 165}
153 166
154static void ca_destroy(struct count_array *ca)
155{
156 kfree(ca->counts);
157}
158
159/*----------------------------------------------------------------*/ 167/*----------------------------------------------------------------*/
160 168
161struct sm_checker { 169struct sm_checker {