[PATCH] Make the mtdblock read/write skip the bad nand sector

Richard Genoud richard.genoud at gmail.com
Thu Nov 21 05:59:44 EST 2013


2013/11/21 Hans Zhang <zhanghonghui at innofidei.com>:
>  When read/write the nandblock device, it will abort writing if
>  there's a bad block, it's reasonable to skip the bad block and
>  finish the data writing.
>  The data reading procedure should also skip the bad block since
>  there's no data write to the block.
>
> --v2:
>  use the wrapped mtd_block_isbad instand of mtd->block_isbad
>
> Signed-off-by: Hans Zhang <zhanghonghui at innofidei.com>
> ---
>  drivers/mtd/mtdblock.c |   17 +++++++++++++++++
>  1 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
> index 485ea75..4f6acd1 100644
> --- a/drivers/mtd/mtdblock.c
> +++ b/drivers/mtd/mtdblock.c
> @@ -124,6 +124,13 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
>                         "at 0x%lx, size 0x%x\n", mtd->name,
>                         mtdblk->cache_offset, mtdblk->cache_size);
>
> +retry:
> +       ret = mtd_block_isbad(mtd, mtdblk->cache_offset);
> +       if (ret > 0) {
> +               mtdblk->cache_offset += mtdblk->cache_size;
> +               goto retry;
> +       }
> +
>         ret = erase_write (mtd, mtdblk->cache_offset,
>                            mtdblk->cache_size, mtdblk->cache_data);
>         if (ret)
> @@ -163,6 +170,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
>                         size = len;
>
>                 if (size == sect_size) {
> +                       ret = mtd_block_isbad(mtd, pos);
> +                       if (ret > 0) {
> +                               pos += sect_size;
> +                               continue;
> +                       }
>                         /*
>                          * We are covering a whole sector.  Thus there is no
>                          * need to bother with the cache while it may still be
> @@ -242,6 +254,11 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
>                     mtdblk->cache_offset == sect_start) {
>                         memcpy (buf, mtdblk->cache_data + offset, size);
>                 } else {
> +                       ret = mtd_block_isbad(mtd, pos);
> +                       if (ret > 0) {
> +                               pos += sect_size;
> +                               continue;
> +                       }
>                         ret = mtd_read(mtd, pos, size, &retlen, buf);
>                         if (ret)
>                                 return ret;
> --
> 1.7.1
>
>

I don't think it's a good idea to skip bad blocks at mtd level.
That will definitely break the userspace.
The nanddump mtd-tool for instance has a bad block handling argument:
--bb=METHOD, where METHOD can be `padbad', `dumpbad', or `skipbad':
    padbad:  dump flash data, substituting 0xFF for any bad blocks
    dumpbad: dump flash data, including any bad blocks
    skipbad: dump good data, completely skipping any bad blocks (default)

The bad block handling is done by the upper layer (UBI/jffs2...) not by mtd.

So, if you really need to read/write the mtd layer from userspace and
jump bad block, you'll have to use the MEMGETBADBLOCK ioctl to check
if the block is bad before reading/writing.

But using UBI is usually a better option.


Richard.



More information about the linux-mtd mailing list