Chinaunix首页 | 论坛 | 博客
  • 博客访问: 118144
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 85
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-30 13:49
文章分类
文章存档

2017年(3)

2016年(1)

2015年(3)

2014年(20)

我的朋友

分类: LINUX

2014-08-30 13:53:24

一. mkyaffs2image 是如何生成的
我们往往用 mkyaffs2image把文件系统打包成yaffs.bin格式,然后在u-boot 中用 nand.write.yaffs2 把文件系统烧到nand flash的指定位置上
但是mkyaffs2image是如何编译出来的呢? 其实mkyaffs2image是在yaffs文件系统的utils目录下,
只把其中的chunkSize  spareSize  与 pagesPerBlock几个变量,按照nand_flash中的改一下就可以用

  1. // Adjust these to match your NAND LAYOUT:
  2. //#define chunkSize 8192
  3. //#define spareSize 232
  4. #define chunkSize 4096
  5. //#define spareSize 218
  6. #define spareSize 128
  7. #define pagesPerBlock 128
我这儿只是改了 chunkSize 与 spareSize.但是貌似datasheet上的spareSize=218. 莫非datasheet也可以骗人?



二. mkyaffs2image分析
2. 下面是mkyaffs2image的main, 很简单的一个函数吧
其中, argc必须大于3     
     argv[1] = dir                  //文件系统的path
     argv[2] = image_file      //打包后生成yaffs.bin的路径
  1. int main(int argc, char *argv[])   
  2. {
  3.     struct stat stats;
  4.     stat(argv[1],&stats);  
  5.     if(!S_ISDIR(stats.st_mode))              //保证argv[1]必须是一个目录  
            exit(1);   
  6.     outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);  //写入到镜像yaffs.bin的fd保存在一个全局变量outFile中
  7.     process_directory(YAFFS_OBJECTID_ROOT,argv[1]);                            //1. 依次读取目录中的文件,写到yaffs.bin中
  8.     pad_image();                                                               //2. 将yaffs.bin扩充到block对齐                       
  9.     close(outFile);
  10. }
2.1 对目录的处理过程
  1. static int process_directory(int parent, const char *path)
  2. {
  3.     DIR *dir;
  4.     char full_name[500];
  5.     struct stat stats;
  6.     int equivalentObj;
  7.     int newObj;
  8.     struct dirent *entry;
  9.     nDirectories++;
  10.     dir = opendir(path);                      //打开目录
  11.     while((entry = readdir(dir)) != NULL)     //遍历目录中的所有文件
  12.     {
  13.         if(strcmp(entry->d_name,".") || strcmp(entry->d_name,".."))         //如果是 . 或者 .. 则直接跳过
  14.             continue;
  15.         snprintf(full_name,sizeof(full_name),"%s/%s",path,entry->d_name);    //构造文件的路径,存于full_name中        
  16.         lstat(full_name,&stats);                                             //获取目录下该文件的stat信息

  17.         if(!S_ISLNK(stats.st_mode) && !S_ISREG(stats.st_mode) && ! S_ISDIR(stats.st_mode) &&
  18.          !S_ISFIFO(stats.st_mode) && !S_ISBLK(stats.st_mode) && ! S_ISCHR(stats.st_mode) &&
  19.          !S_ISSOCK(stats.st_mode))
  20.             continue ;                                                        //不知道这TMD是什么类型的文件则跳过

  21.         newObj = obj_id++;
  22.         n_obj++;                
  23.         if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
  24.         {
  25.             write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
  26.         }
  27.         else
  28.         {
  29.             add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
  30.             if(S_ISLNK(stats.st_mode))
  31.             {
  32.                 char symname[500];
  33.                 memset(symname,0, sizeof(symname));
  34.                 readlink(full_name,symname,sizeof(symname) -1);
  35.                 write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);

  36.             }
  37.             else if(S_ISREG(stats.st_mode))             //如果是普通文件
  38.             {                        
  39.                 if(write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL) == 0)  //1.先写入文件头
  40.                 {
  41.                     int h;
  42.                     u8 bytes[chunkSize];
  43.                     int n_bytes;
  44.                     int chunk = 0;

  45.                     h = open(full_name,O_RDONLY);                            
  46.                     memset(bytes,0xff,sizeof(bytes));
  47.                     while((n_bytes = read(h,bytes,sizeof(bytes))) > 0)
  48.                     {
  49.                         chunk++;
  50.                         write_chunk(bytes,newObj,chunk,n_bytes);                                            //2.再写入文件内容
  51.                         memset(bytes,0xff,sizeof(bytes));
  52.                     }
  53.                     close(h);
  54.                 }
  55.             }
  56.             else if(S_ISSOCK(stats.st_mode))                                    //如果是socket文件                   
  57.                 write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);  //只写入文件头                  
  58.             else if(S_ISFIFO(stats.st_mode))                                    //如果是FIFO文件                   
  59.                 write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头                   
  60.             else if(S_ISCHR(stats.st_mode))                                     //如果是字符设备文件                  
  61.                 write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);  //只写入文件头                  
  62.             else if(S_ISBLK(stats.st_mode))                                     //如果是块设备文件                  
  63.                 write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头                   
  64.             else if(S_ISDIR(stats.st_mode))                                     //如果是目录文件                   
  65.                 if (write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL) == 0) //只写入文件头
  66.                     process_directory(newObj,full_name);                       //并把这次的newObj作为parent,继续             
  67.         }    
  68.     }
  69.     closedir(dir);
  70.     return 0;
  71. }
2.1.1
  1. static int write_object_header(int id, enum yaffs_obj_type t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
  2. {
  3.     u8 bytes[chunkSize];


  4.     struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)bytes;

  5.     memset(bytes,0xff,sizeof(bytes));

  6.     oh->type = t;

  7.     oh->parent_obj_id = parent;

  8.     if (strlen(name)+1 > sizeof(oh->name))
  9.     {
  10.         errno = ENAMETOOLONG;
  11.         return warn("object name");
  12.     }
  13.     memset(oh->name,0,sizeof(oh->name));
  14.     strcpy(oh->name,name);

  15.     if(t != YAFFS_OBJECT_TYPE_HARDLINK)
  16.     {
  17.         oh->yst_mode = s->st_mode;
  18.         oh->yst_uid = s->st_uid;
  19.         oh->yst_gid = s->st_gid;
  20.         oh->yst_atime = s->st_atime;
  21.         oh->yst_mtime = s->st_mtime;
  22.         oh->yst_ctime = s->st_ctime;
  23.         oh->yst_rdev = s->st_rdev;
  24.     }

  25.     if(t == YAFFS_OBJECT_TYPE_FILE)
  26.     {
  27.         oh->file_size = s->st_size;
  28.     }

  29.     if(t == YAFFS_OBJECT_TYPE_HARDLINK)
  30.     {
  31.         oh->equiv_id = equivalentObj;
  32.     }

  33.     if(t == YAFFS_OBJECT_TYPE_SYMLINK)
  34.     {
  35.         if (strlen(alias)+1 > sizeof(oh->alias))
  36.         {
  37.             errno = ENAMETOOLONG;
  38.             return warn("object alias");
  39.         }
  40.         memset(oh->alias,0,sizeof(oh->alias));
  41.         strcpy(oh->alias,alias);
  42.     }
  43.     return write_chunk(bytes,id,0,0xffff);

  44. }

  1. static int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes)
  2. {
  3.     struct yaffs_ext_tags t;
  4.     struct yaffs_packed_tags2 pt;
  5.     char spareData[spareSize];

  6.     if (write(outFile,data,chunkSize) != chunkSize)                //写4K
  7.         fatal("write");

  8.     memset(&t, 0, sizeof(t));

  9.     t.chunk_id = chunk_id;
  10.     t.serial_number = 1;    // **CHECK**
  11.     t.n_bytes = n_bytes;
  12.     t.obj_id = id;
  13.     t.seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
  14.     t.chunk_used = 1;

  15.     nPages++;

  16.     memset(&pt, 0, sizeof(pt));                        //函数将 yaffs_ext_tags转为yaffs_packed_tags2,并生成校验信息,
  17.     yaffs_pack_tags2(&pt,&t,0);                        //但最后一个函数是0,所以只转化保存校验信息
  18.     memset(spareData, 0xff, sizeof(spareData));             
  19.     shuffle_oob(spareData, &pt);

  20.     if (write(outFile,spareData,sizeof(spareData)) != sizeof(spareData))  //写oob
  21.         fatal("write");

  22.     return 0;
  23. }
注:
struct yaffs_packed_tags2 {
    struct yaffs_packed_tags2_tags_only t;     //数据
    struct yaffs_ecc_other ecc;                       //校验信息
}
;
yaffs_packed_tags2是由数据和校难信息两部分组成的,但是这儿只用了数据不进行校验,所以内核里面也只是读出数据不校验
2.2 扩充yaffs.bin到一个block
  1. static void pad_image(void)
  2. {
  3.     u8 data[chunkSize + spareSize];
  4.     int padPages = (nPages % pagesPerBlock);

  5.     if (padPages)
  6.     {
  7.         memset(data, 0xff, sizeof(data));
  8.         for (padPages = pagesPerBlock-padPages; padPages; padPages--)
  9.         {
  10.             if (write(outFile, data, sizeof(data)) != sizeof(data))
  11.                 fatal("write");
  12.         }
  13.     }
  14. }
d
三. 实验一下
3.1 实验
a.新建目录fs_test,在fs_test新建一文件222.txt, 内空是"bbbcc"
  1. sun@ubuntu:/tmp/mkyaffs/utils/test$ tree
  2. .
  3. └── fs_test
  4.     └── 222.txt

  5. 1 directory, 1 file
  6. sun@ubuntu:/tmp/mkyaffs/utils/test$ cat fs_test/222.txt
  7. bbbccc
b. 利用mkyaffs2image生成yaffs的打包文件fs.yaffs
  1. sun@ubuntu:/tmp/mkyaffs/utils/test$ ../mkyaffs2image fs_test/ fs.yaffs
  2.     main[432]: mkyaffs2image: image building tool for YAFFS2 built Jul 3 2013
  3.     main[464]: Processing directory fs_test/ into image file fs.yaffs
  4.     Object 257, fs_test//222.txt is a
  5.     file,
  6.     1 data chunks written
  7.     pad_image[255]: nPages=2
  8.     main[480]: Operation complete.
  9.     2 objects in 1 directories
  10.     2 NAND pages
  11. sun@ubuntu:/tmp/mkyaffs/utils/test$ ll
  12. total 540
  13. drwxrwxr-x 3 sun sun 4096 Jul 3 16:36 ./
  14. drwxrwxr-x 5 sun sun 4096 Jul 3 15:36 ../
  15. drwxrwxr-x 2 sun sun 4096 Jul 3 15:06 fs_test/
  16. -rw------- 1 sun sun 540672 Jul 3 16:36 fs.yaffs
可以看出fs.yaffs的大小是540672=128×(4096+128)
c. 分析一下fs.yaffs
按page的记录内容,可以分为两种,一个是oh_page另一个是data_page
其中普通文件,需要一个oh_page,如果有内容还需要一个或多个data_page
其它的文件,则只需要一个oh_page就够了.
   oh_page:

data_page:


sizeof(yaffs_obj_hdr)=0x200=512B
28B的信息就是结构体 yaffs_packed_tags2
  1. struct yaffs_packed_tags2_tags_only {
  2.     unsigned seq_number;
  3.     unsigned obj_id;
  4.     unsigned chunk_id;
  5.     unsigned n_bytes;
  6. };
  7. struct yaffs_ecc_other {
  8.     unsigned char col_parity;
  9.     unsigned line_parity;
  10.     unsigned line_parity_prime;
  11. };
  12. struct yaffs_packed_tags2 {
  13.     struct yaffs_packed_tags2_tags_only t;
  14.     struct yaffs_ecc_other ecc;
  15. };
3.2 oh_page与data_page的根本区别
int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes);
write_chunk(bytes,id,0,0xffff);                         //写oh_page    chunk_id=0,写入oob
write_chunk(bytes,newObj,chunk,n_bytes);     //写data_page  chunk_id!=0,写入oob

其中 write_chunk的第2个参数id, oh_page与data_page相等的话说明这是同一个文件的头与数据区
其中 write_chunk的第3个参数chunk_id, 区分oh_page与data_page,  oh_page的chunk_id=0


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