现在的位置: 首页 > 综合 > 正文

cramfs文件系统识别nand坏块

2013年11月05日 ⁄ 综合 ⁄ 共 4205字 ⁄ 字号 评论关闭
          
1.内核支持:
   CONFIG_CRAMFS=y

2.制作文件
   1)获取mkcramfs工具
     如果是ubuntu的话: apt-get install mkcramfs
     否则从 http://sourceforge.net/projects/cramfs/ 下载源码编译
   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 <linux/mtd/mtd.h>

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;
    }

}

//------------------------------ 在文件中修改以下内容 --------------------------------
/************** 修改function : cramfs_fill_super **************/
-    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;

+    /* add patch for skipping bad nand block */
+    cramfs_fill_nand(sb);

    /* Invalidate the read buffers on mount: think disk change.. */
    mutex_lock(&read_mutex);
    for (i = 0; i < READ_BUFFERS; i++)
        buffer_blocknr[i] = -1;

/************** 修改function : cramfs_read  **************/
    if (!len)
        return NULL;

+    /* calc the real offset in nand */
+    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 这个函数来解决。
    

参考文件: http://www.unixresources.net/linux/clf/embedded/archive/00/00/67/70/677041.html  --  <cramfs问题请教>

抱歉!评论已关闭.