[PATCH 3.4 012/107] dm thin: allocate the cell_sort_array dynamically

From: lizf
Date: Wed Mar 16 2016 - 04:07:50 EST


From: Joe Thornber <ejt@xxxxxxxxxx>

3.4.111-rc1 review patch. If anyone has any objections, please let me know.

------------------


commit a822c83e47d97cdef38c4352e1ef62d9f46cfe98 upstream.

Given the pool's cell_sort_array holds 8192 pointers it triggers an
order 5 allocation via kmalloc. This order 5 allocation is prone to
failure as system memory gets more fragmented over time.

Fix this by allocating the cell_sort_array using vmalloc.

Signed-off-by: Joe Thornber <ejt@xxxxxxxxxx>
Signed-off-by: Mike Snitzer <snitzer@xxxxxxxxxx>
[lizf: Backported 3.4: it's prinson_{create,destroy}() that need fixing]
Signed-off-by: Zefan Li <lizefan@xxxxxxxxxx>
---
drivers/md/dm-thin.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index e811e44..862612e 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>

#define DM_MSG_PREFIX "thin"

@@ -149,9 +150,7 @@ static struct bio_prison *prison_create(unsigned nr_cells)
{
unsigned i;
uint32_t nr_buckets = calc_nr_buckets(nr_cells);
- size_t len = sizeof(struct bio_prison) +
- (sizeof(struct hlist_head) * nr_buckets);
- struct bio_prison *prison = kmalloc(len, GFP_KERNEL);
+ struct bio_prison *prison = kmalloc(sizeof(*prison), GFP_KERNEL);

if (!prison)
return NULL;
@@ -164,9 +163,15 @@ static struct bio_prison *prison_create(unsigned nr_cells)
return NULL;
}

+ prison->cells = vmalloc(sizeof(*prison->cells) * nr_buckets);
+ if (!prison->cells) {
+ mempool_destroy(prison->cell_pool);
+ kfree(prison);
+ return NULL;
+ }
+
prison->nr_buckets = nr_buckets;
prison->hash_mask = nr_buckets - 1;
- prison->cells = (struct hlist_head *) (prison + 1);
for (i = 0; i < nr_buckets; i++)
INIT_HLIST_HEAD(prison->cells + i);

@@ -175,6 +180,7 @@ static struct bio_prison *prison_create(unsigned nr_cells)

static void prison_destroy(struct bio_prison *prison)
{
+ vfree(prison->cells);
mempool_destroy(prison->cell_pool);
kfree(prison);
}
--
1.9.1