Chinaunix首页 | 论坛 | 博客
  • 博客访问: 301700
  • 博文数量: 71
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 564
  • 用 户 组: 普通用户
  • 注册时间: 2014-07-20 18:15
个人简介

用编程改变大众。。。

文章分类

全部博文(71)

文章存档

2016年(7)

2015年(54)

2014年(10)

我的朋友

分类: 嵌入式

2015-04-25 13:53:32

近日在对坏块驱动的坏块检测及标记等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) |
给主人留下些什么吧!~~