Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1244578
  • 博文数量: 261
  • 博客积分: 4196
  • 博客等级: 上校
  • 技术积分: 3410
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-17 17:05
文章分类

全部博文(261)

文章存档

2018年(1)

2017年(22)

2016年(2)

2015年(8)

2014年(27)

2013年(40)

2012年(161)

分类: LINUX

2012-08-20 15:55:09

原文地址解决cramfs不识别nand坏块的patch 作者fly123456789


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


//------------------------------ 在文件中修改以下内容 --------------------------------
/************** 修改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 这个函数来解决。

阅读(1311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~