Skip to contentSkip to conversation

drivers/mtd/onenand/: unacceptable stack usage

DISCUSSION Adrian Bunk 3 participants 4 messages Dec 16, 2005 – Jan 4, 2006 Memory technology devices (MTD)

lore
Share & tools
lore
#0 lore raw

In 2.6.15-rc, the following driver was added:

include/linux/mtd/onenand.h:
#define MAX_ONENAND_PAGESIZE (2048 + 64)

drivers/mtd/onenand/onenand_base.c:
static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)

{
        struct onenand_chip *this = mtd->priv;
        unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf;

drivers/mtd/onenand/onenand_bbt.c:
static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)

{
        unsigned char data_buf[MAX_ONENAND_PAGESIZE];

These are variables on the stack that are > 2kB which is not acceptable since the complete stack might be only 4kB.

Please either fix this before 2.6.15 or mark the MTD_ONENAND driver as BROKEN until it's fixed.

TIA
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#1 lore raw

Hi

OK. I change the source code.
It is working well on OMAP H4 with 2.6.15-rc4 kernel and LTP fs test is passed.

And please apply the recent onenand patch

- check correct manufacturer
- unlock problem in DDP (Double Density Package)
- add platform_device.h instead of device.h

Thank you

Kyungmin Park

1. check correct manufacturer

Index: drivers/mtd/onenand/onenand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/onenand/onenand_base.c,v retrieving revision 1.8

mtd/onenand/onenand_base.c +9 -5
diff -u -p -r1.8 onenand_base.c
@@ -1346,7 +1346,6 @@ static void onenand_print_device_info(in
 
 static const struct onenand_manufacturers onenand_manuf_ids[] = {
         {ONENAND_MFR_SAMSUNG, "Samsung"},
-        {ONENAND_MFR_UNKNOWN, "Unknown"}
 };
 
 /**
@@ -1357,17 +1356,22 @@ static const struct onenand_manufacturer
  */
 static int onenand_check_maf(int manuf)
 {
+	int size = ARRAY_SIZE(onenand_manuf_ids);
+	char *name;
         int i;
 
-        for (i = 0; onenand_manuf_ids[i].id; i++) {
+        for (i = 0; i < size; i++)
                 if (manuf == onenand_manuf_ids[i].id)
                         break;
-        }
 
-        printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n",
-                onenand_manuf_ids[i].name, manuf);
+	if (i < size)
+		name = onenand_manuf_ids[i].name;
+	else
+		name = "Unknown";
+
+        printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name,

manuf);

- return (i != ONENAND_MFR_UNKNOWN);
+ return (i == size);
}

/**
Index: include/linux/mtd/onenand.h
===================================================================
RCS file: /home/cvs/mtd/include/linux/mtd/onenand.h,v retrieving revision 1.8

linux/mtd/onenand.h +0 -1
diff -u -p -r1.8 onenand.h
@@ -140,7 +140,6 @@ struct onenand_chip {
  * OneNAND Flash Manufacturer ID Codes
  */
 #define ONENAND_MFR_SAMSUNG	0xec
-#define ONENAND_MFR_UNKNOWN	0x00
 
 /**
  * struct nand_manufacturers - NAND Flash Manufacturer ID Structure

2. unlock problem in DDP

Index: drivers/mtd/onenand/onenand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/onenand/onenand_base.c,v retrieving revision 1.9

mtd/onenand/onenand_base.c +3 -0
diff -u -p -r1.9 onenand_base.c
@@ -1296,6 +1296,12 @@ static int onenand_unlock(struct mtd_inf
 
 	/* Block lock scheme */
 	for (block = start; block < end; block++) {
+		/* Set block address */
+		value = onenand_block_address(this, block);
+		this->write_word(value, this->base +

ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this, block);
+ this->write_word(value, this->base +
ONENAND_REG_START_ADDRESS2);
/* Set start block address */ this->write_word(block, this->base +
ONENAND_REG_START_BLOCK_ADDRESS);
/* Write unlock command */
@@ -1309,10 +1315,6 @@ static int onenand_unlock(struct mtd_inf
& ONENAND_CTRL_ONGO)
continue;

- /* Set block address for read block status */
- value = onenand_block_address(this, block);
- this->write_word(value, this->base +
ONENAND_REG_START_ADDRESS1);
-
/* Check lock status */ status = this->read_word(this->base +
ONENAND_REG_WP_STATUS);
if (!(status & ONENAND_WP_US))

# reduce stack usage

Index: drivers/mtd/onenand/onenand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/onenand/onenand_base.c,v retrieving revision 1.10

mtd/onenand/onenand_base.c +2 -2
diff -u -p -r1.10 onenand_base.c
@@ -940,7 +940,7 @@ static int onenand_writev_ecc(struct mtd
 	u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
 	struct onenand_chip *this = mtd->priv;
-	unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf;
+	unsigned char *pbuf;
 	size_t total_len, len;
 	int i, written = 0;
 	int ret = 0;
@@ -975,7 +975,7 @@ static int onenand_writev_ecc(struct mtd
 	/* Loop until all keve's data has been written */
 	len = 0;
 	while (count) {
-		pbuf = buffer;
+		pbuf = this->page_buf;
 		/*
 		 * If the given tuple is >= pagesize then
 		 * write it out from the iov
@@ -995,7 +995,7 @@ static int onenand_writev_ecc(struct mtd
 			int cnt = 0, thislen;
 			while (cnt < mtd->oobblock) {
 				thislen = min_t(int, mtd->oobblock - cnt,

vecs->iov_len - len);
- memcpy(buffer + cnt, vecs->iov_base + len,
thislen);
+ memcpy(this->page_buf + cnt, vecs->iov_base
+ len, thislen);
cnt += thislen;
len += thislen;

@@ -1519,6 +1519,18 @@ int onenand_scan(struct mtd_info *mtd, i
this->read_bufferram = onenand_sync_read_bufferram;
}

+ /* Allocate buffers, if necessary */
+ if (!this->page_buf) {
+ size_t len;
+ len = mtd->oobblock + mtd->oobsize;
+ this->page_buf = kmalloc(len, GFP_KERNEL);
+ if (!this->page_buf) {
+ printk(KERN_ERR "onenand_scan(): Can't allocate
page_buf\n");
+ return -ENOMEM;
+ }
+ this->options |= ONENAND_PAGEBUF_ALLOC;
+ }
+
this->state = FL_READY; init_waitqueue_head(&this->wq); spin_lock_init(&this->chip_lock);
@@ -1580,12 +1592,21 @@ int onenand_scan(struct mtd_info *mtd, i
*/
void onenand_release(struct mtd_info *mtd)
{
+ struct onenand_chip *this = mtd->priv;
+
#ifdef CONFIG_MTD_PARTITIONS
/* Deregister partitions */
del_mtd_partitions (mtd);
#endif
/* Deregister the device */
del_mtd_device (mtd);
+
+ /* Free bad block table memory, if allocated */
+ if (this->bbm)
+ kfree(this->bbm);
+ /* Buffer allocated by onenand_scan */
+ if (this->options & ONENAND_PAGEBUF_ALLOC)
+ kfree(this->page_buf);
}

EXPORT_SYMBOL_GPL(onenand_scan);
Index: drivers/mtd/onenand/onenand_bbt.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/onenand/onenand_bbt.c,v retrieving revision 1.1

mtd/onenand/onenand_bbt.c +0 -0
diff -u -p -r1.1 onenand_bbt.c
@@ -118,10 +118,10 @@ static int create_bbt(struct mtd_info *m
  */
 static inline int onenand_memory_bbt (struct mtd_info *mtd, struct

nand_bbt_descr *bd)
{
- unsigned char data_buf[MAX_ONENAND_PAGESIZE];
+ struct onenand_chip *this = mtd->priv;

         bd->options &= ~NAND_BBT_SCANEMPTY;

- return create_bbt(mtd, data_buf, bd, -1);
+ return create_bbt(mtd, this->page_buf, bd, -1);
}

/**
Index: include/linux/mtd/onenand.h
===================================================================
RCS file: /home/cvs/mtd/include/linux/mtd/onenand.h,v retrieving revision 1.9

linux/mtd/onenand.h +2 -2
diff -u -p -r1.9 onenand.h
@@ -17,7 +17,6 @@
 #include <linux/mtd/bbm.h>
 
 #define MAX_BUFFERRAM		2
-#define MAX_ONENAND_PAGESIZE	(2048 + 64)
 
 /* Scan and identify a OneNAND device */
 extern int onenand_scan(struct mtd_info *mtd, int max_chips);
@@ -110,6 +109,7 @@ struct onenand_chip {
 	spinlock_t		chip_lock;
 	wait_queue_head_t	wq;
 	onenand_state_t		state;
+	unsigned char		*page_buf;
 
 	struct nand_oobinfo	*autooob;
 
@@ -134,7 +134,7 @@ struct onenand_chip {
  * Options bits
  */
 #define ONENAND_CONT_LOCK		(0x0001)
-
+#define ONENAND_PAGEBUF_ALLOC		(0x1000)
 
 /*
  * OneNAND Flash Manufacturer ID Codes

4. Add platform_device.h instead device.h

drivers/mtd/onenand/generic.c +2 -2
@@ -12,9 +12,9 @@
  *   This is a device driver for the OneNAND flash for generic boards.
  */
 
-#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
@@ -39,7 +39,7 @@ static int __devinit generic_onenand_pro
 {
        struct onenand_info *info;
        struct platform_device *pdev = to_platform_device(dev);
-       struct onenand_platform_data *pdata = pdev->dev.platform_data;
+       struct flash_platform_data *pdata = pdev->dev.platform_data;
        struct resource *res = pdev->resource;
        unsigned long size = res->end - res->start + 1;
        int err;

--

Quoted 54 lines

-----Original Message-----
From: Adrian Bunk [mailto:[email protected]]
Sent: Friday, December 16, 2005 9:55 AM
To: Kyungmin Park
Cc: [email protected]; [email protected]; Linus Torvalds; Andrew Morton; [email protected]
Subject: drivers/mtd/onenand/: unacceptable stack usage

In 2.6.15-rc, the following driver was added:

include/linux/mtd/onenand.h:
#define MAX_ONENAND_PAGESIZE (2048 + 64)

drivers/mtd/onenand/onenand_base.c:
static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)

{
        struct onenand_chip *this = mtd->priv;
        unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf;

drivers/mtd/onenand/onenand_bbt.c:
static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)

{
        unsigned char data_buf[MAX_ONENAND_PAGESIZE];

These are variables on the stack that are > 2kB which is not acceptable
since the complete stack might be only 4kB.

Please either fix this before 2.6.15 or mark the MTD_ONENAND driver as
BROKEN until it's fixed.

TIA
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed
#2 lore raw

Review

Quoted 12 lines · Kyungmin Park

OK. I change the source code.
It is working well on OMAP H4 with 2.6.15-rc4 kernel and LTP fs test is passed.

And please apply the recent onenand patch

(quoted diff) +0 -0
 	- check correct manufacturer 
 	- unlock problem in DDP (Double Density Package)
 	- add platform_device.h instead of device.h
 
 Thank you

These patches are wordwrapped and cannot be applied.

You've included three separate patches in the body of a single email. Please don't do that. One patch per email is preferred.

So please redo these patches against 2.6.15 and resend them, as per
http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt, thanks.

#3 lore raw
Quoted 14 lines · Andrew Morton

Review

Quoted 12 lines · Kyungmin Park

OK. I change the source code.
It is working well on OMAP H4 with 2.6.15-rc4 kernel and LTP fs test is passed.

And please apply the recent onenand patch

(quoted diff) +0 -0
 	- check correct manufacturer 
 	- unlock problem in DDP (Double Density Package)
 	- add platform_device.h instead of device.h
 
 Thank you
Quoted 7 lines

These patches are wordwrapped and cannot be applied.

You've included three separate patches in the body of a single email. Please don't do that. One patch per email is preferred.

So please redo these patches against 2.6.15 and resend them, as per
http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt, thanks.

???

The patches are already included in 2.6.15.

cu
Adrian

Signature · 4 lines
       "Is there not promise of rain?" Ling Tan asked suddenly out
        of the darkness. There had been need of rain for many days.
       "Only a promise," Lao Er said.
                                       Pearl S. Buck - Dragon Seed