Chinaunix首页 | 论坛 | 博客
  • 博客访问: 500280
  • 博文数量: 225
  • 博客积分: 2175
  • 博客等级: 大尉
  • 技术积分: 2443
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-05 22:02
个人简介

目前在一家公司担任软件总监,主要涉及智能手机,笔记本电脑的开发

文章分类

全部博文(225)

文章存档

2024年(6)

2023年(68)

2022年(13)

2021年(7)

2020年(11)

2019年(3)

2018年(10)

2017年(8)

2012年(7)

2011年(4)

2010年(32)

2009年(41)

2008年(6)

2007年(9)

分类: LINUX

2009-02-19 22:03:02

据说Yaffs很好,适合大容量Nand,mount快,比Jaffs好.不过这些都是百闻,我还没一见.对文件系统,还没完整看过一个文件系统的代码.
 不过,现在我们用的jffs2也实在太慢了,整个系统启动起来 ,需要70秒.看来得试试yaffs2
 
Day 1:2009年2月21日 星期四
  今天开始动手porting yaffs2到内核2.6.17上,
  打上patch后,发现mount成功,可读写,但是umount后,文件消失.
  发现在nandmtd2_ReadChunkWithTagsFromNAND中read_oob 直接读出来oob原始数据,没有加上offset
 
 
Day2:
  在add_mtd_partitions函数中加上:
->. = ->;
否则在yaffs中用 mtd->oobavail ,发现等于0
  在yaffs_mtdif2.c中:
_u8   rawOobBuf[64];
在函数nandmtd2_ReadChunkWithTagsFromNAND中
if (!dev->inbandTags && tags)
   {
   retval =
       mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,dev->spareBuffer);
   }
修改为:
if (!dev->inbandTags && tags)
   {
   retval =
       mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
       rawOobBuf);                     
   translateSparetoOOB(mtd,rawOobBuf,dev->spareBuffer);//translate here
   }
static int translateSparetoOOB(struct mtd_info *mtd , const __u8 * spare,   __u8 * oob)
{
     struct nand_oobinfo *oobsel;
 int i, len, ofs,j;
      oobsel = &mtd->oobinfo;
      ofs = 0; 
  for (i = 0, len = 0; len < mtd->oobavail; i++) {
   int from =  oobsel->oobfree[i][0];
   int num = oobsel->oobfree[i][1];
      for(j= 0 ; j    //memcpy (oob, spare[from], num);
   len += num;
   oob += num;
  }
}
很奇怪,在translateSparetoOOB中,用memcpy就不行,必须要一个一个赋值 。
弄了大半天,原来,应该写成:
   memcpy (oob, &spare[from], num);
一个粗心,半天都没查出来 ,很....
这样translateSparetoOOB函数改为:
static int translateSparetoOOB(struct mtd_info *mtd , const __u8 * spare,   __u8 * oob)
{
     struct nand_oobinfo *oobsel;
 int i, len, ofs,j;
      oobsel = &mtd->oobinfo;
      ofs = 0; 
  for (i = 0, len = 0; len < mtd->oobavail; i++) {
   int from =  oobsel->oobfree[i][0];
   int num = oobsel->oobfree[i][1];
     memcpy (oob, &spare[from], num);
   len += num;
   oob += num;
  }
}
看起来简洁了很多,不知道效率是否有提高 ?
这样后,{BANNED}中国第一天出现的问题: mount 后,添加的文件在umount后消失了的问题解决了。
不过在测试中发现:
  cp /etc/welcome .
  然后可以查看文件内容。
umount 再mount 后,ls 发现文件还在,但cat welcome , 文件内容不对 。
看来得好好分析一下文件系统。
 
Day 3: 2009年2月21日 星期六
 今天闲来无事,到上随便翻翻,突然看到一篇文章
文章里写到:对于1K或者2K bytes的Nand ,其 byteCount为2 bytes ,如果这样的话,那么yaffs_PackedTags2TagsPart就可以由16bytes缩减为14bytes .但发现在函数yaffs_UpdateObjectHeader中,byteCount为文件的大小,也就是说对于chunk ,如果是page chunk的话,bytes count表示该chunk中的有效字节,但对header chunk,bytecount表示的却是文件的大小.
不过 chunkID 可以改为unsigned short,这样使得yaffs2支持的文件大小由8G变为128MB .但这已经足够了,我们系统的文件不可能大于128MB .
同时:函数yaffs_ECCCalculateOther是计算tags的ecc,而yaffs_PackedTags2TagsPart为16bytes ,
yaffs_ECCCalculateOther的参数nBytes为16,这样,lineParity和lineParityPrime也只需要16位就可以了,也就是unsigned short类型,如果改为unsigned short类型的话,并加上packed选项,可以让yaffs_ECCOther从12字节减到5字节.
如果这样的话,14+5 =19 bytes ,在我们的项目中,用HW ECC的话,只剩下20 字节,刚好够了.
  另外,我很纳闷,怎么我这次移植Yaffs2费尽周折,是不是因为我用的版本不对?太新了还是太久了?
今天总是上不去.
 
Day 4: 2009年2月22日 星期日
  今天看代码的时候,突然发现chunkID不能边为unsigned short ,因为在函数yaffs_PackTags2TagsPart中:
ptt->chunkId = EXTRA_HEADER_INFO_FLAG | t->extraParentObjectId;
也就是chunkId里面store了parent object ID ,这样chunkID必须也unsigned int 了,否则object ID 也必须限制在unsigned short ,也就是只能支持65535个文件对象(文件+目录+soft link+hard link).这样改动太大了.
   不过这个文章里面
写的是tags 的ecc 为3 bytes .
 在yaffs_ECCCalculateOther中nbytes为16, 这样i就小于16了(0~15),那么line_parity,line_parity_prime完全可以改为unsigned char .
对于line_parity ^=i ,除了低8位,其他的位全为0 ,所以改为unsigned char完全可以.
而line_parity_prime^=~i; 则高24位要么全为1,要么全为0,高24位和第7位一样,因为只要i小于128,那么高25位就为一样的值,那这样的话,也可以用unsigned char来代替,然后根据高7位是0还是1进行扩展.
typedef struct __attribute__((packed)) {
    unsigned char colParity; 
    unsigned char lineParity; 
   unsigned char lineParityPrime;
} yaffs_ECCOther;
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
     yaffs_ECCOther * read_ecc,
     const yaffs_ECCOther * test_ecc)
{
  ..........
 lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
 +++     if(lDeltaPrime&0x80)
 +++         lDeltaPrime |=0xFFFFFF00
..............
 
再仔细分析一下,其实发现yaffs_ECCCorrectOther不用修改也可以.

只需要3bytes了.那么Yaffs的oob就是16+3=19 bytes 了,可以满足要求.
 
 
 Day 5: 2009年2月25日 星期三
      前几天忙于别的事情,不过,这也好,让大脑清静清静,否则总在里面绕不出来。
     今天继续。用了一个老的版本,yaffs_before2.6.18 . 结果还是写大文件的时候出问题。
     在网上看到别人的移植经验:一般yaffs没什么问题,问题主要是出在yaffs和MTD不 match .
     难道我写的MTD 驱动有问题?
    于是好好看了看nand driver . 结果在dw_nand_write_page函数中,
     Block = page /this->pagemask
   修改为 :     Block = page /(this->pagemask+1);
   发现 yaffs 好了 。 哈哈
  不过,发现修改后的MTD驱动比DSPG的慢 ,还得优化一下。主要是多了一次memcpy动作 。
 优化后测试发现MTD驱动读的速度和DSPG的一样,写比人家的慢(基于相同的时序条件下测试)。问题还是出在写多了一些memcpy动作。算了,就这样,以后再说。

 Day 6: 2009年3月17日 星期二
   Yaffs2移植好了,不过前几天有一个驱动的工程师离职了,本来交给他修改的下载yaffs2的工具也就没做了。
  亲自动手吧,这些人做事太慢了。
 {BANNED}中国第一步: mkyaffs2image 工具
  在新的yaffs2代码里有一个目录utils ,里面有mkyaffs2image工具
  修改一下Makefile :
KERNELDIR=/home/lawrencekang/xpndr-multimedia_base_1.1.1_giant/linux-dw

###add a link to yaffs in kernel as we changed the yaffs2 src
YAFFSSRC= $(KERNELDIR)/fs/yaffs2

###CFLAGS =   -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
CFLAGS =   -I/usr/include -I$(YAFFSSRC) -O2 -Wall -DCONFIG_YAFFS_UTIL

$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS):
##      ln -s ../$@ $@
        ln -s $(YAFFSSRC)/$@ $@
也就是把符号链接到正确的kernel source中
注意在 mkyaffs2image.c中
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)

   ......
 //   return write(outFile,&pt,sizeof(yaffs_PackedTags2));
    return write(outFile,&pt,spareSize);
}
这样,生成的文件系统结构为:
  2K data  + 20 个字节的 OOB + 44 无效数据
然后在uboot 中调用 MTD 的 write_ecc函数将 ecc写进去
 然后 make ,就生成了mkyaffs2image

 第二步:修改 u boot 代码
  因为uboot 不支持 HW ECC
  需要加上宏 CFG_DW_HW_ECC。
#define CFG_DW_HW_ECC
在nand_write_opts函数中
#ifdef CFG_DW_HW_ECC
        if (opts->writeoob) {
         memcpy(oob_buf, buffer, meminfo->oobsize); // the oob
         buffer += meminfo->oobsize;
     
      //wrtie the oob and data
      result = meminfo->write_ecc(meminfo, mtdoffset, meminfo->oobblock,
                       &written, data_buf, (__u8 *) oob_buf, NULL);
     
          if (result != 0) {
                printf("\nMTD writeoob failure: %d\n",
                       result);
                goto restoreoob;
            }
            imglen -= meminfo->oobsize;  
                 imglen -= readlen;
            }
      else
           {
    result = meminfo->write(meminfo,
                    mtdoffset,
                    meminfo->oobblock,
                    &written,
                    (unsigned char *) &data_buf);

        if (result != 0) {
            printf("writing NAND page at offset 0x%lx failed\n",
                   mtdoffset);
            goto restoreoob;
        }
         imglen -= readlen;
}
       
#else
        if (opts->writeoob) {
            /* read OOB data from input memory block, exit
             * on failure */
            memcpy(oob_buf, buffer, meminfo->oobsize);
            buffer += meminfo->oobsize;

            /* write OOB data first, as ecc will be placed
             * in there*/
            result = meminfo->write_oob(meminfo,
                            mtdoffset,
                            meminfo->oobsize,
                            &written,
                            (unsigned char *)
                            &oob_buf);

            if (result != 0) {
                printf("\nMTD writeoob failure: %d\n",
                       result);
                goto restoreoob;
            }
            imglen -= meminfo->oobsize;
        }

        /* write out the page data */
        result = meminfo->write(meminfo,
                    mtdoffset,
                    meminfo->oobblock,
                    &written,
                    (unsigned char *) &data_buf);

        if (result != 0) {
            printf("writing NAND page at offset 0x%lx failed\n",
                   mtdoffset);
            goto restoreoob;
        }
        imglen -= readlen;

#endif
同时在 usbdfu.c中
 char *rootfstype = getenv("rootfstype");




   
  
    

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