mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
mtdblock: modify for squashfs mount [1/2]
PD#SWPL-116004 PD#SWPL-157951 PD#SWPL-168212 PD#SWPL-169271 Problem: 1.squashfs don't handle bad block 2.partition size returned from mtdblock is incorrect 3.mtdblock io performance 4.mtdblock report partition size wrong when meet bad block 5.wrong poniter reference is used in container_of() Solution: 1.mtdblock handle bad block 2.fix mtdblock size 3.mtd disk block size set to mtd writesize 4.correct the decrease size when meet bad block 5.fix the wrong poniter reference Verify: s4_aq2432 AT301_962D4-K35(1.5G) #256 C3_C308L_AW419_SOCKET_V01_R05 s1a_bg201 Change-Id: Icbaec2b6679727ebe0d12fd92bf4d21cc4d5f3fe Signed-off-by: Feng Chen <feng.chen@amlogic.com> Signed-off-by: zhikui.cui <zhikui.cui@amlogic.com> Signed-off-by: Liang Yang <liang.yang@amlogic.com>
This commit is contained in:
@@ -31,6 +31,14 @@ struct mtdblk_dev {
|
||||
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
struct mtdblk_pbbt {
|
||||
struct mtdblk_dev mb;
|
||||
unsigned int bad_cnt;
|
||||
unsigned short *part_bbt;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Cache stuff...
|
||||
*
|
||||
@@ -101,11 +109,41 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
|
||||
* written to the device. Clear cache_state to avoid writing to
|
||||
* bad blocks repeatedly.
|
||||
*/
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
if (!ret && ret != EIO)
|
||||
return ret;
|
||||
mtdblk->cache_state = STATE_EMPTY;
|
||||
return ret;
|
||||
#else
|
||||
if (ret == 0 || ret == -EIO)
|
||||
mtdblk->cache_state = STATE_EMPTY;
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
static unsigned long map_block(struct mtdblk_dev *mtdblk, unsigned long pos)
|
||||
{
|
||||
struct mtd_info *mtd = mtdblk->mbd.mtd;
|
||||
struct mtdblk_pbbt *pbbt = container_of(mtdblk, struct mtdblk_pbbt, mb);
|
||||
int block, i;
|
||||
|
||||
if (!pbbt->part_bbt)
|
||||
return pos;
|
||||
|
||||
block = (int)(pos >> mtd->erasesize_shift);
|
||||
for (i = 0; i < pbbt->bad_cnt; i++) {
|
||||
if (block >= pbbt->part_bbt[i])
|
||||
block++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* form actual position */
|
||||
return ((unsigned long)block * mtd->erasesize) |
|
||||
(pos & (mtd->erasesize - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||
int len, const char *buf)
|
||||
@@ -118,6 +156,10 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||
pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
|
||||
mtd->name, pos, len);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
pos = map_block(mtdblk, pos);
|
||||
#endif
|
||||
|
||||
if (!sect_size)
|
||||
return mtd_write(mtd, pos, len, &retlen, buf);
|
||||
|
||||
@@ -187,7 +229,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
|
||||
|
||||
pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
|
||||
mtd->name, pos, len);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
pos = map_block(mtdblk, pos);
|
||||
#endif
|
||||
if (!sect_size) {
|
||||
ret = mtd_read(mtd, pos, len, &retlen, buf);
|
||||
if (ret && !mtd_is_bitflip(ret))
|
||||
@@ -231,7 +275,14 @@ static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
|
||||
unsigned long block, char *buf)
|
||||
{
|
||||
struct mtdblk_dev *mtdblk = container_of(dev, struct mtdblk_dev, mbd);
|
||||
|
||||
#if (IS_ENABLED(CONFIG_AMLOGIC_MTD_NAND) || \
|
||||
IS_ENABLED(CONFIG_AMLOGIC_MTD_SPI_NAND))
|
||||
return do_cached_read(mtdblk, block << dev->tr->blkshift,
|
||||
dev->tr->blksize, buf);
|
||||
#else
|
||||
return do_cached_read(mtdblk, block<<9, 512, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
|
||||
@@ -247,12 +298,23 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
|
||||
* return -EAGAIN sometimes, but why bother?
|
||||
*/
|
||||
}
|
||||
|
||||
#if (IS_ENABLED(CONFIG_AMLOGIC_MTD_NAND) || \
|
||||
IS_ENABLED(CONFIG_AMLOGIC_MTD_SPI_NAND))
|
||||
return do_cached_write(mtdblk, block << dev->tr->blkshift,
|
||||
dev->tr->blksize, buf);
|
||||
#else
|
||||
return do_cached_write(mtdblk, block<<9, 512, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mtdblock_open(struct mtd_blktrans_dev *mbd)
|
||||
{
|
||||
struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd);
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
int block_cnt, i, bad_cnt = 0;
|
||||
struct mtdblk_pbbt *pbbt = container_of(mtdblk, struct mtdblk_pbbt, mb);
|
||||
#endif
|
||||
|
||||
pr_debug("mtdblock_open\n");
|
||||
|
||||
@@ -274,6 +336,35 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
|
||||
mtdblk->cache_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
pbbt->part_bbt = NULL;
|
||||
if (!mtd_can_have_bb(mbd->mtd))
|
||||
goto _ok;
|
||||
|
||||
block_cnt = mbd->mtd->size >> mbd->mtd->erasesize_shift;
|
||||
for (i = 0; i < block_cnt; i++)
|
||||
/*
|
||||
* A valid judgment is made before calling this function.
|
||||
*/
|
||||
/* coverity[divide_by_zero:SUPPRESS] */
|
||||
if (mtd_block_isbad(mbd->mtd, i * mbd->mtd->erasesize))
|
||||
bad_cnt++;
|
||||
pbbt->bad_cnt = bad_cnt;
|
||||
if (bad_cnt) {
|
||||
pbbt->part_bbt =
|
||||
kmalloc_array(block_cnt, sizeof(*pbbt->part_bbt), GFP_KERNEL);
|
||||
bad_cnt = 0;
|
||||
for (i = 0; i < block_cnt; i++)
|
||||
/*
|
||||
* A valid judgment is made before calling this function.
|
||||
*/
|
||||
/* coverity[divide_by_zero:SUPPRESS] */
|
||||
if (mtd_block_isbad(mbd->mtd, i * mbd->mtd->erasesize))
|
||||
pbbt->part_bbt[bad_cnt++] = i;
|
||||
}
|
||||
|
||||
_ok:
|
||||
#endif
|
||||
pr_debug("ok\n");
|
||||
|
||||
return 0;
|
||||
@@ -311,27 +402,67 @@ static int mtdblock_flush(struct mtd_blktrans_dev *dev)
|
||||
ret = write_cached_data(mtdblk);
|
||||
mutex_unlock(&mtdblk->cache_mutex);
|
||||
mtd_sync(dev->mtd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
|
||||
{
|
||||
struct mtdblk_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
int i = 0;
|
||||
struct mtdblk_pbbt *pbbt;
|
||||
#endif
|
||||
struct mtdblk_dev *dev;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
pbbt = kzalloc(sizeof(*pbbt), GFP_KERNEL);
|
||||
if (!pbbt)
|
||||
return;
|
||||
dev = &pbbt->mb;
|
||||
#else
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return;
|
||||
#endif
|
||||
|
||||
dev->mbd.mtd = mtd;
|
||||
dev->mbd.devnum = mtd->index;
|
||||
|
||||
#if (IS_ENABLED(CONFIG_AMLOGIC_MTD_NAND) || \
|
||||
IS_ENABLED(CONFIG_AMLOGIC_MTD_SPI_NAND))
|
||||
tr->blksize = mtd->writesize;
|
||||
tr->blkshift = ffs(tr->blksize) - 1;
|
||||
dev->mbd.size = mtd->size >> tr->blkshift;
|
||||
#else
|
||||
dev->mbd.size = mtd->size >> 9;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
if (!mtd_can_have_bb(mtd))
|
||||
goto _ok;
|
||||
|
||||
for (i = 0; i < (mtd->size >> mtd->erasesize_shift); i++)
|
||||
if (mtd_block_isbad(mtd, i * mtd->erasesize))
|
||||
#if (IS_ENABLED(CONFIG_AMLOGIC_MTD_NAND) || \
|
||||
IS_ENABLED(CONFIG_AMLOGIC_MTD_SPI_NAND))
|
||||
dev->mbd.size -= (mtd->erasesize >> tr->blkshift);
|
||||
#else
|
||||
dev->mbd.size -= (mtd->erasesize >> 9);
|
||||
#endif
|
||||
_ok:
|
||||
#endif
|
||||
dev->mbd.tr = tr;
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
dev->mbd.readonly = 1;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_NAND
|
||||
if (add_mtd_blktrans_dev(&dev->mbd))
|
||||
kfree(pbbt);
|
||||
#else
|
||||
if (add_mtd_blktrans_dev(&dev->mbd))
|
||||
kfree(dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
|
||||
|
||||
Reference in New Issue
Block a user