[MTD] [OneNAND] Classify the page data and oob buffer

Classify the page data and oob buffer
and it prevents the memory fragementation (writesize + oobsize)

Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 6d4e67f..9e14a26 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -836,7 +836,7 @@
 	int readcol = column;
 	int readend = column + thislen;
 	int lastgap = 0;
-	uint8_t *oob_buf = this->page_buf + mtd->writesize;
+	uint8_t *oob_buf = this->oob_buf;
 
 	for (free = this->ecclayout->oobfree; free->length; ++free) {
 		if (readcol >= lastgap)
@@ -1356,7 +1356,7 @@
 	/* Grab the lock and see if the device is available */
 	onenand_get_device(mtd, FL_WRITING);
 
-	oobbuf = this->page_buf + mtd->writesize;
+	oobbuf = this->oob_buf;
 
 	/* Loop until all data write */
 	while (written < len) {
@@ -2332,15 +2332,25 @@
 
 	/* Allocate buffers, if necessary */
 	if (!this->page_buf) {
-		size_t len;
-		len = mtd->writesize + mtd->oobsize;
-		this->page_buf = kmalloc(len, GFP_KERNEL);
+		this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
 		if (!this->page_buf) {
 			printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
 			return -ENOMEM;
 		}
 		this->options |= ONENAND_PAGEBUF_ALLOC;
 	}
+	if (!this->oob_buf) {
+		this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
+		if (!this->oob_buf) {
+			printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n");
+			if (this->options & ONENAND_PAGEBUF_ALLOC) {
+				this->options &= ~ONENAND_PAGEBUF_ALLOC;
+				kfree(this->page_buf);
+			}
+			return -ENOMEM;
+		}
+		this->options |= ONENAND_OOBBUF_ALLOC;
+	}
 
 	this->state = FL_READY;
 	init_waitqueue_head(&this->wq);
@@ -2437,9 +2447,11 @@
 		kfree(bbm->bbt);
 		kfree(this->bbm);
 	}
-	/* Buffer allocated by onenand_scan */
+	/* Buffers allocated by onenand_scan */
 	if (this->options & ONENAND_PAGEBUF_ALLOC)
 		kfree(this->page_buf);
+	if (this->options & ONENAND_OOBBUF_ALLOC)
+		kfree(this->oob_buf);
 }
 
 EXPORT_SYMBOL_GPL(onenand_scan);
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index d8af8a9..a56d24a 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -82,7 +82,8 @@
  * @wq:			[INTERN] wait queue to sleep on if a OneNAND
  *			operation is in progress
  * @state:		[INTERN] the current state of the OneNAND device
- * @page_buf:		data buffer
+ * @page_buf:		[INTERN] page main data buffer
+ * @oob_buf:		[INTERN] page oob data buffer
  * @subpagesize:	[INTERN] holds the subpagesize
  * @ecclayout:		[REPLACEABLE] the default ecc placement scheme
  * @bbm:		[REPLACEABLE] pointer to Bad Block Management
@@ -122,6 +123,7 @@
 	wait_queue_head_t	wq;
 	onenand_state_t		state;
 	unsigned char		*page_buf;
+	unsigned char		*oob_buf;
 
 	int			subpagesize;
 	struct nand_ecclayout	*ecclayout;
@@ -156,6 +158,7 @@
 #define ONENAND_HAS_CONT_LOCK		(0x0001)
 #define ONENAND_HAS_UNLOCK_ALL		(0x0002)
 #define ONENAND_PAGEBUF_ALLOC		(0x1000)
+#define ONENAND_OOBBUF_ALLOC		(0x2000)
 
 /*
  * OneNAND Flash Manufacturer ID Codes