Patchwork [nandsim] Fix RAM wasting via kmalloc (take 2)

login
register
mail settings
Submitter Alexey Korolev
Date Oct. 29, 2008, 1:14 p.m.
Message ID <alpine.LFD.1.10.0810291313140.30280@casper.infradead.org>
Download mbox | patch
Permalink /patch/6249/
State New
Headers show

Comments

Alexey Korolev - Oct. 29, 2008, 1:14 p.m.
Hi All,

Nandsim consumes ~2x more RAM than the density of simulated device. 
It becomes critical if we need to simulate 256MB NAND and run stress tests 
on it.

We investigated the reasons. nandsim allocates space for pages using kmalloc
function. The size of LP nand page is 2112 bytes.
kmalloc gets space from slab pools by chunks 2^n. So if we need to kmalloc
2112 bytes, 4096 bytes will be consumed by system.
The best way to avoid this issue would be using kmem_cache allocations. AFAIK
this mechanism specially designed to handle cases when arrays of allocations
are used.

The following patch solves allocation issues.

Thanks,
Alexey

Patch is also available at: 
http://git.infradead.org/users/akorolev/mtd-fixes.git?a=commit;h=9da3e1fe56a16a4393f4e382075c189e26e0737f 


Signed-off-by: Alexey Korolev <akorolev@infradead.org>
Tested-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Acked-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

---
Artem Bityutskiy - Nov. 1, 2008, 9:35 a.m.
On Wed, 2008-10-29 at 13:14 +0000, Alexey Korolev wrote:
> @@ -437,6 +440,8 @@ static int alloc_device(struct nandsim *ns)
>  	for (i = 0; i < ns->geom.pgnum; i++) {
>  		ns->pages[i].byte = NULL;
>  	}
> +	ns->nand_pages_slab = kmem_cache_create("nandsim",
> +						ns->geom.pgszoob, 0, 0, NULL);

Sorry, but how about checking for errors here?
Artem Bityutskiy - Nov. 13, 2008, 1:06 p.m.
On Wed, 2008-10-29 at 13:14 +0000, Alexey Korolev wrote:
> Hi All,
> 
> Nandsim consumes ~2x more RAM than the density of simulated device. 
> It becomes critical if we need to simulate 256MB NAND and run stress tests 
> on it.
> 
> We investigated the reasons. nandsim allocates space for pages using kmalloc
> function. The size of LP nand page is 2112 bytes.
> kmalloc gets space from slab pools by chunks 2^n. So if we need to kmalloc
> 2112 bytes, 4096 bytes will be consumed by system.
> The best way to avoid this issue would be using kmem_cache allocations. AFAIK
> this mechanism specially designed to handle cases when arrays of allocations
> are used.

Would you please send a version which checks return pointer of
kmem_cache_alloc() for NULL?
Alexey Korolev - Nov. 13, 2008, 1:21 p.m.
Hi,

> 
> Would you please send a version which checks return pointer of
> kmem_cache_alloc() for NULL?
> 
I think it is  unnecessary to add one more check of return pointer for NULL
after kmem_cache_alloc() function.

PLease take a look at these lines of the patch:
----
-		mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
+		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
 		if (mypage->byte == NULL) {
 			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
 			return -1;
----
If I properly understand the code it already performs checking just after attempt of allocation. 
So this patch version should be correct.

Thanks,
Alexey
Alexey Korolev - Nov. 13, 2008, 1:48 p.m.
Hi Artem,


> 
> Would you please send a version which checks return pointer of
> kmem_cache_alloc() for NULL?

Thank for reminder. I've just found your message you sent just before the holidays. It was about kmem_cache_create function. 
Sorry I missed it. I've sent the updated-patch.

Thanks,
Alexey

Patch

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ae7c577..0551cbf 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -295,6 +295,9 @@  struct nandsim {
 	/* The simulated NAND flash pages array */
 	union ns_mem *pages;
 
+	/* Slab allocator for nand pages */
+	struct kmem_cache *nand_pages_slab;
+
 	/* Internal buffer of page + OOB size bytes */
 	union ns_mem buf;
 
@@ -420,8 +423,8 @@  static struct mtd_info *nsmtd;
 static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
 
 /*
- * Allocate array of page pointers and initialize the array to NULL
- * pointers.
+ * Allocate array of page pointers, create slab allocation for an array
+ * and initialize the array by NULL pointers.
  *
  * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
  */
@@ -437,6 +440,8 @@  static int alloc_device(struct nandsim *ns)
 	for (i = 0; i < ns->geom.pgnum; i++) {
 		ns->pages[i].byte = NULL;
 	}
+	ns->nand_pages_slab = kmem_cache_create("nandsim",
+						ns->geom.pgszoob, 0, 0, NULL);
 
 	return 0;
 }
@@ -451,8 +456,10 @@  static void free_device(struct nandsim *ns)
 	if (ns->pages) {
 		for (i = 0; i < ns->geom.pgnum; i++) {
 			if (ns->pages[i].byte)
-				kfree(ns->pages[i].byte);
+				kmem_cache_free(ns->nand_pages_slab,
+						ns->pages[i].byte);
 		}
+		kmem_cache_destroy(ns->nand_pages_slab);
 		vfree(ns->pages);
 	}
 }
@@ -1279,7 +1286,7 @@  static void erase_sector(struct nandsim *ns)
 	for (i = 0; i < ns->geom.pgsec; i++) {
 		if (mypage->byte != NULL) {
 			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
-			kfree(mypage->byte);
+			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
 			mypage->byte = NULL;
 		}
 		mypage++;
@@ -1301,10 +1308,10 @@  static int prog_page(struct nandsim *ns, int num)
 		/*
 		 * We allocate memory with GFP_NOFS because a flash FS may
 		 * utilize this. If it is holding an FS lock, then gets here,
-		 * then kmalloc runs writeback which goes to the FS again
-		 * and deadlocks. This was seen in practice.
+		 * then kernel memory alloc runs writeback which goes to the FS
+		 * again and deadlocks. This was seen in practice.
 		 */
-		mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
+		mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
 		if (mypage->byte == NULL) {
 			NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
 			return -1;