Chinaunix首页 | 论坛 | 博客
  • 博客访问: 752216
  • 博文数量: 79
  • 博客积分: 2671
  • 博客等级: 少校
  • 技术积分: 1247
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-02 15:26
个人简介

宅男

文章分类

全部博文(79)

文章存档

2017年(11)

2016年(12)

2015年(6)

2012年(10)

2011年(33)

2010年(7)

分类: LINUX

2011-04-18 15:06:48

这几天在调研yaffs在SEP0611上的可行性。由于当前开发板上使用的NAND芯片是K9HCG08U1M,是4K页,128字节OOB区的M芯片。因为yaffs2中要写入至少16字节的tags,而0611的BCH16模式会产生28bytes/K的ECC码,所以在这种芯片上不能实现yaffs。(OOB区的前2个字节要留下来,给坏块判断用)
TCC8900上是采用的yaffs文件系统(依稀记得也是采用的K9HCG08U1M,恨哪,没看清楚),而且spare data为32字节。ECC为160字节。所以一直不知道它是怎么处理这些数据的。而且ECC的代码写的极其繁琐复杂,研究了一天半才发现TCC采用的NAND芯片为K9LBG08U0D,是4K页,218字节00B区的MLC芯片。oh ,my GOD。疯了,都怪开始没看仔细。

2011.04.20:
昨天发现yaffs上存在的一个bug。是关于inband-tags的使用。
那么什么是yaffs的inband-tags呢?我们知道yaffs是在OOB区中存放tags信息的。但是会不会出现OOB区中空间不够,无法完整的存放tags信息的情况呢?(SEP0611上就出现了这种情况,因为ECC控制模块的最小为BCH16)。

出现这种情况怎么办呢?是不是就不能使用yaffs呢?事实上yaffs的开发者已经考虑到了这种情况,如果OOB区中空间不够的话,那么yaffs会将这些tags信息保存在数据的末尾(其实就是缩短了数据区的长度),这种情况在yaffs称为inband-tags

static int yaffs_CreateInitialDirectories(yaffs_Device *dev)函数中:

  1. /* Sort out space for inband tags, if required */
  2.     if (dev->inbandTags)
  3.     dev->nDataBytesPerChunk=dev->totalBytesPerChunk-sizeof(yaffs_PackedTags2TagsPart);
  4.     else
  5.         dev->nDataBytesPerChunk = dev->totalBytesPerChunk;

来设定nDataBytesPerChunk的数值,显然如果是inbandtags的话,就需要从数据区中预留出tags的空间。

在函数yaffs_internal_read_super中有:

dev->inbandTags = options.inband_tags;

可知inbandTags 是由options.inband_tags的值觉得的。那么下一步就是去找options.inband_tags了。

事实上我为了偷工减料。直接在初始化函数中设置dev->inbandTags = 1了。然后挂载yaffs文件系统使用iozone来进行性能的测试。挂载的时候会出现下面的打印信息(打印信息是我添加的。)

yaffs_GutsInitialise:ndatabytesperchunk:4080

说明此事每个chunk的数据长度为4080个字节(page大小为4096字节)。

但是在测试的过程中发现了文件系统老是报Erasure failed的错误,通过跟踪代码发现是在下面的一段代码发生错误的。

  1. erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
  2.             if (!erasedOk) {
  3.                 dev->nErasureFailures++;
  4.                 T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
  5.                  (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
  6.             }

反正是由擦除失败造成的错误的错误。

  1. int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
  2.     {
  3.         struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  4.         __u32 addr =
  5.          ((loff_t) blockNumber) * dev->nDataBytesPerChunk
  6.             * dev->nChunksPerBlock;
  7.         struct erase_info ei;
  8.         int retval = 0;
  9.     
  10.         ei.mtd = mtd;
  11.         ei.addr = addr;
  12.         ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
  13.         ei.time = 1000;
  14.         ei.retries = 2;
  15.         ei.callback = NULL;
  16.         ei.priv = (u_long) dev;
  17.         sema_init(&dev->sem, 0);
  18.         retval = mtd->erase(mtd, &ei);

我看到这段代码的时候就感觉上面红色字体的部分不太对,因为在inband-tags的时候,dev->nDataBytesPerChunk不等于pagesize,所以这样计算需要擦除的地址就会算错。

mtd->erase函数指针最终指向nand_erase函数。

nand_erase ->nand_erase_nand;

  1. int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
  2.              int allowbbt)
  3.     {
  4.         int page, status, pages_per_block, ret, chipnr;
  5.         struct nand_chip *chip = mtd->priv;
  6.         loff_t rewrite_bbt[NAND_MAX_CHIPS]={0};
  7.         unsigned int bbt_masked_page = 0xffffffff;
  8.         loff_t len;
  9.     
  10.         DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n",
  11.          (unsigned long long)instr->addr, (unsigned long long)instr->len);
  12.     
  13.         /* Start address must align on block boundary */
  14.         if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
  15.             DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
  16.             return -EINVAL;
  17.         }
  18.     
  19.         /* Length must align on block boundary */
  20.         if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
  21.             DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
  22.              "Length not block aligned\n");
  23.             return -EINVAL;
  24.         }

注意上述代码中红色字体部分,这段代码检查addr是不是blocksize对齐的,同时也检查要擦除的长度len是不是blocksize对齐的。如果按照nandmtd_EraseBlockInNAND中那么写的话,addr以及len都不可能对齐的。

今天下载了最新的yaffs的代码,发现这个bug已经被修正了。

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