近日在对坏块驱动的坏块检测及标记等api修改的过程中,发现在cramfs文件系统所在flash中标记多个坏块后,文件系统启动出现问题。提示:
cramfs: bad compressed blocksize 2447430638
cramfs: bad compressed blocksize 2447430638
后在网上找到了一个解决办法,但是在测试时发现,该patch只能解决单个坏块的情况,对于多个坏块连续存在时,文件系统启动仍有问题。从其能解决单个坏块问题的现象分析,说明其基本处理思路是正确的。不能解决多个坏块连续存在的问题,应该是其在计算处理坏块偏移的算法有问题。
这段代码是对坏块映射表进行INIT的,经分析发现,其在检测到坏块后,直接偏移増加一个block给坏块表对应项,但是如果有连续坏块时,下一个坏块其实被赋给了坏块表,这样在cramfs加载时,仍然会read flash错误。
for(i = 0; i < blocks; i++){
if (mtd->block_isbad(mtd, (loff_t)i*mtd->erasesize))
offset += mtd->erasesize;
block_map[i] = offset;
}:
更改如下:
for(i = 0; i < blocks; i++){
while(mtd->block_isbad(mtd, ((loff_t)i*mtd->erasesize + offset)))
offset += mtd->erasesize;
block_map[i] = offset;
}:
即可;
原文如下为转载内容:
-----------------------------------------------------------------》
1.内核支持:
CONFIG_CRAMFS=y
2.制作文件
1)获取mkcramfs工具
如果是ubuntu的话: apt-get install mkcramfs
否则从 下载源码编译
2)制作cramfs文件镜像
mkcramfs ./rootfs rootfs.cramfs
3.uboot烧写cramfs文件到nand的分区
tftp $loadaddr rootfs.cramfs
nand erase [addr] [size]
--- addr 为cramfs分区的起始地址
--- size 为cramfs分区的大小
nand write $loadaddr [addr] $filesize
--- 把文件烧写到nand里面去
setenv bootargs console=ttyS0,115200n8 init=/init rw root=1f04 rootfstype=cramfs
--- 1f04代表nand的第四个分区, 我这使用的是这个分区.
boot
如果运气的好的话,cramfs能起来了。
4. 如果遇到如下错误:
1) cramfs: bad root offset 108
可能是uboot烧写nand使用的ecc与内核使用的ecc不一致造成的。
2) cramfs: bad compressed blocksize 3822651956
cramfs: bad compressed blocksize 3822651956
Failed to execute /init. Attempting defaults...
cramfs: bad compressed blocksize 2447430638
cramfs: bad compressed blocksize 2447430638
Error -3 while decompressing!
c05c7319(1969)->cfff0000(4096)
可能是由于nand有坏块。 uboot烧写时跳过坏块,而cramfs却没有识别到这写坏块。
5) 解决cramfs不识别nand坏块的patch:
本人使用的android的 2.6.32内核
# uname -a
Linux (none) 2.6.32 #25 Tue Jul 12 19:03:04 CST 2011 armv7l GNU/Linux
遵循尽量少该原则,我们只需改动修改 fs/cramfs/inode.c 文件.
//------------------------------ 在文件中添加以下内容 --------------------------------
#include
struct cramfs_nand_info {
unsigned int erasesize_shift;
uint32_t *block_map;
uint32_t size;
};
static unsigned int cramfs_nand_transfer_offset(struct super_block *sb, unsigned int offset)
{
struct cramfs_sb_info *sbi = sb->s_fs_info;
struct cramfs_nand_info *nandinfo;
nandinfo = (struct cramfs_nand_info *)(sbi + 1);
if (!nandinfo->erasesize_shift || !nandinfo->block_map)
return offset;
if (offset > nandinfo->size)
return offset;
return (offset + nandinfo->block_map[offset >> nandinfo->erasesize_shift]);
}
static void cramfs_fill_nand(struct super_block *sb)
{
struct cramfs_sb_info *sbi = sb->s_fs_info;
struct cramfs_nand_info *nandinfo;
uint32_t *block_map = NULL;
uint32_t offset = 0;
nandinfo = (struct cramfs_nand_info *)(sbi + 1);
if(MAJOR(sb->s_dev) == MTD_BLOCK_MAJOR){
struct mtd_info *mtd;
int blocks, i;
mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
if(!mtd)
return;
if(mtd->type != MTD_NANDFLASH)
return;
blocks = mtd->size>>mtd->erasesize_shift;
printk("cramfs_fill_nand blocks is %d-----------------------\n\n\n\n", blocks);
block_map = kmalloc(blocks*sizeof(uint32_t), GFP_KERNEL);
if (!block_map)
return ;
for(i = 0; i < blocks; i++){
if (mtd->block_isbad(mtd, (loff_t)i*mtd->erasesize))
offset += mtd->erasesize;
block_map[i] = offset;
}
nandinfo->erasesize_shift = mtd->erasesize_shift;
nandinfo->block_map = block_map;
nandinfo->size = (uint32_t) mtd->size;
}
}
//------------------------------ 在文件中修改以下内容 --------------------------------
- sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct cramfs_sb_info) + sizeof(struct cramfs_nand_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
+
+ cramfs_fill_nand(sb);
mutex_lock(&read_mutex);
for (i = 0; i < READ_BUFFERS; i++)
buffer_blocknr[i] = -1;
if (!len)
return NULL;
+
+ offset = cramfs_nand_transfer_offset(sb, offset);
blocknr = offset >> PAGE_CACHE_SHIFT;
offset &= PAGE_CACHE_SIZE - 1;
解决方法的原理是: 在nand没有坏块的情况下,cramfs是连续的放在nand的data区域,cramfs文件系统中数据的offset == nand中数据区域的offset。我们暂且把cramfs系统 称作FS(offset), 把nand中数据区域的offset称作 NAND(offset)。 如果说nand存在坏块了,uboot烧写cramfs镜像就不是连续存放了,此时 FS(offset) != NAND(offset)。因此,想要让cramfs对nand的坏块支持,就需要写一个映射函数f把FS(offset)映射到 NAND(offset) 该函数形式为: f(FS(offset)) = NAND(offset)。 映射函数的算法是: 创建一个block的映射表,FS(offset)也以块为单位坐落于block映射表中。 如果FS(offset)坐落的那个block是坏块,则使其映射表及其后的所有block表值都加上块大小。 换算公式为: NAND(offset) = FS(offset) + block_map[ FS(offset) / block_size ];
我们想要的映射函数使用C语言实现出来就是上面的 cramfs_nand_transfer_offset 这个函数。 cramfs_fill_nand只是为映射函数的实现做提前准备的。
注:以上添加的程序有个bug就是umount文件系统的时候 block_map 没释放掉,造成内存泄漏。大家可以修改 cramfs_put_super 这个函数来解决。
阅读(1938) | 评论(0) | 转发(0) |