一. mkyaffs2image 是如何生成的
我们往往用 mkyaffs2image把文件系统打包成yaffs.bin格式,然后在u-boot 中用 nand.write.yaffs2 把文件系统烧到nand flash的指定位置上
但是mkyaffs2image是如何编译出来的呢? 其实mkyaffs2image是在yaffs文件系统的utils目录下,
只把其中的chunkSize spareSize 与 pagesPerBlock几个变量,按照nand_flash中的改一下就可以用
我这儿只是改了 chunkSize 与 spareSize.但是貌似datasheet上的spareSize=218.
莫非datasheet也可以骗人?
二. mkyaffs2image分析
2. 下面是mkyaffs2image的main, 很简单的一个函数吧
其中, argc必须大于3
argv[1] = dir //文件系统的path
argv[2] = image_file //打包后生成yaffs.bin的路径
2.1 对目录的处理过程
2.1.1
注:
struct yaffs_packed_tags2 {
struct yaffs_packed_tags2_tags_only t ; //数据
struct yaffs_ecc_other ecc ; //校验信息
} ;
yaffs_packed_tags2是由数据和校难信息两部分组成的,但是这儿只用了数据不进行校验,所以内核里面也只是读出数据不校验
2.2 扩充yaffs.bin到一个block
d
三. 实验一下
3.1 实验
a. 新建目录fs_test,在fs_test新建一文件222.txt, 内空是"bbbcc"
b. 利用mkyaffs2image生成yaffs的打包文件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
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
我们往往用 mkyaffs2image把文件系统打包成yaffs.bin格式,然后在u-boot 中用 nand.write.yaffs2 把文件系统烧到nand flash的指定位置上
但是mkyaffs2image是如何编译出来的呢? 其实mkyaffs2image是在yaffs文件系统的utils目录下,
只把其中的chunkSize spareSize 与 pagesPerBlock几个变量,按照nand_flash中的改一下就可以用
- // Adjust these to match your NAND LAYOUT:
- //#define chunkSize 8192
- //#define spareSize 232
- #define chunkSize 4096
- //#define spareSize 218
- #define spareSize 128
- #define pagesPerBlock 128
二. mkyaffs2image分析
2. 下面是mkyaffs2image的main, 很简单的一个函数吧
其中, argc必须大于3
argv[1] = dir //文件系统的path
argv[2] = image_file //打包后生成yaffs.bin的路径
- int main(int argc, char *argv[])
- {
- struct stat stats;
- stat(argv[1],&stats);
- if(!S_ISDIR(stats.st_mode)) //保证argv[1]必须是一个目录
exit(1);
- outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); //写入到镜像yaffs.bin的fd保存在一个全局变量outFile中
- process_directory(YAFFS_OBJECTID_ROOT,argv[1]); //1. 依次读取目录中的文件,写到yaffs.bin中
- pad_image(); //2. 将yaffs.bin扩充到block对齐
- close(outFile);
- }
- static int process_directory(int parent, const char *path)
- {
- DIR *dir;
- char full_name[500];
- struct stat stats;
- int equivalentObj;
- int newObj;
- struct dirent *entry;
- nDirectories++;
- dir = opendir(path); //打开目录
- while((entry = readdir(dir)) != NULL) //遍历目录中的所有文件
- {
- if(strcmp(entry->d_name,".") || strcmp(entry->d_name,"..")) //如果是 . 或者 .. 则直接跳过
- continue;
- snprintf(full_name,sizeof(full_name),"%s/%s",path,entry->d_name); //构造文件的路径,存于full_name中
- lstat(full_name,&stats); //获取目录下该文件的stat信息
-
- if(!S_ISLNK(stats.st_mode) && !S_ISREG(stats.st_mode) && ! S_ISDIR(stats.st_mode) &&
- !S_ISFIFO(stats.st_mode) && !S_ISBLK(stats.st_mode) && ! S_ISCHR(stats.st_mode) &&
- !S_ISSOCK(stats.st_mode))
- continue ; //不知道这TMD是什么类型的文件则跳过
-
- newObj = obj_id++;
- n_obj++;
- if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
- {
- write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
- }
- else
- {
- add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
- if(S_ISLNK(stats.st_mode))
- {
- char symname[500];
- memset(symname,0, sizeof(symname));
- readlink(full_name,symname,sizeof(symname) -1);
- write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
-
- }
- else if(S_ISREG(stats.st_mode)) //如果是普通文件
- {
- if(write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL) == 0) //1.先写入文件头
- {
- int h;
- u8 bytes[chunkSize];
- int n_bytes;
- int chunk = 0;
-
- h = open(full_name,O_RDONLY);
- memset(bytes,0xff,sizeof(bytes));
- while((n_bytes = read(h,bytes,sizeof(bytes))) > 0)
- {
- chunk++;
- write_chunk(bytes,newObj,chunk,n_bytes); //2.再写入文件内容
- memset(bytes,0xff,sizeof(bytes));
- }
- close(h);
- }
- }
- else if(S_ISSOCK(stats.st_mode)) //如果是socket文件
- write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头
- else if(S_ISFIFO(stats.st_mode)) //如果是FIFO文件
- write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头
- else if(S_ISCHR(stats.st_mode)) //如果是字符设备文件
- write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头
- else if(S_ISBLK(stats.st_mode)) //如果是块设备文件
- write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); //只写入文件头
- else if(S_ISDIR(stats.st_mode)) //如果是目录文件
- if (write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL) == 0) //只写入文件头
- process_directory(newObj,full_name); //并把这次的newObj作为parent,继续
- }
- }
- closedir(dir);
- return 0;
- }
- 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)
- {
- u8 bytes[chunkSize];
-
-
- struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)bytes;
-
- memset(bytes,0xff,sizeof(bytes));
-
- oh->type = t;
-
- oh->parent_obj_id = parent;
-
- if (strlen(name)+1 > sizeof(oh->name))
- {
- errno = ENAMETOOLONG;
- return warn("object name");
- }
- memset(oh->name,0,sizeof(oh->name));
- strcpy(oh->name,name);
-
- if(t != YAFFS_OBJECT_TYPE_HARDLINK)
- {
- oh->yst_mode = s->st_mode;
- oh->yst_uid = s->st_uid;
- oh->yst_gid = s->st_gid;
- oh->yst_atime = s->st_atime;
- oh->yst_mtime = s->st_mtime;
- oh->yst_ctime = s->st_ctime;
- oh->yst_rdev = s->st_rdev;
- }
-
- if(t == YAFFS_OBJECT_TYPE_FILE)
- {
- oh->file_size = s->st_size;
- }
-
- if(t == YAFFS_OBJECT_TYPE_HARDLINK)
- {
- oh->equiv_id = equivalentObj;
- }
-
- if(t == YAFFS_OBJECT_TYPE_SYMLINK)
- {
- if (strlen(alias)+1 > sizeof(oh->alias))
- {
- errno = ENAMETOOLONG;
- return warn("object alias");
- }
- memset(oh->alias,0,sizeof(oh->alias));
- strcpy(oh->alias,alias);
- }
- return write_chunk(bytes,id,0,0xffff);
-
- }
- static int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes)
- {
- struct yaffs_ext_tags t;
- struct yaffs_packed_tags2 pt;
- char spareData[spareSize];
-
- if (write(outFile,data,chunkSize) != chunkSize) //写4K
- fatal("write");
-
- memset(&t, 0, sizeof(t));
-
- t.chunk_id = chunk_id;
- t.serial_number = 1; // **CHECK**
- t.n_bytes = n_bytes;
- t.obj_id = id;
- t.seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
- t.chunk_used = 1;
-
- nPages++;
-
- memset(&pt, 0, sizeof(pt)); //函数将 yaffs_ext_tags转为yaffs_packed_tags2,并生成校验信息,
- yaffs_pack_tags2(&pt,&t,0); //但最后一个函数是0,所以只转化保存校验信息
- memset(spareData, 0xff, sizeof(spareData));
- shuffle_oob(spareData, &pt);
-
- if (write(outFile,spareData,sizeof(spareData)) != sizeof(spareData)) //写oob
- fatal("write");
-
- return 0;
- }
struct yaffs_packed_tags2 {
struct yaffs_packed_tags2_tags_only t ; //数据
struct yaffs_ecc_other ecc ; //校验信息
} ;
yaffs_packed_tags2是由数据和校难信息两部分组成的,但是这儿只用了数据不进行校验,所以内核里面也只是读出数据不校验
2.2 扩充yaffs.bin到一个block
- static void pad_image(void)
- {
- u8 data[chunkSize + spareSize];
- int padPages = (nPages % pagesPerBlock);
-
- if (padPages)
- {
- memset(data, 0xff, sizeof(data));
- for (padPages = pagesPerBlock-padPages; padPages; padPages--)
- {
- if (write(outFile, data, sizeof(data)) != sizeof(data))
- fatal("write");
- }
- }
- }
三. 实验一下
3.1 实验
a. 新建目录fs_test,在fs_test新建一文件222.txt, 内空是"bbbcc"
- sun@ubuntu:/tmp/mkyaffs/utils/test$ tree
- .
- └── fs_test
- └── 222.txt
-
- 1 directory, 1 file
- sun@ubuntu:/tmp/mkyaffs/utils/test$ cat fs_test/222.txt
- bbbccc
- sun@ubuntu:/tmp/mkyaffs/utils/test$ ../mkyaffs2image fs_test/ fs.yaffs
- main[432]: mkyaffs2image: image building tool for YAFFS2 built Jul 3 2013
- main[464]: Processing directory fs_test/ into image file fs.yaffs
- Object 257, fs_test//222.txt is a
- file,
- 1 data chunks written
- pad_image[255]: nPages=2
- main[480]: Operation complete.
- 2 objects in 1 directories
- 2 NAND pages
- sun@ubuntu:/tmp/mkyaffs/utils/test$ ll
- total 540
- drwxrwxr-x 3 sun sun 4096 Jul 3 16:36 ./
- drwxrwxr-x 5 sun sun 4096 Jul 3 15:36 ../
- drwxrwxr-x 2 sun sun 4096 Jul 3 15:06 fs_test/
- -rw------- 1 sun sun 540672 Jul 3 16:36 fs.yaffs
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
- struct yaffs_packed_tags2_tags_only {
- unsigned seq_number;
- unsigned obj_id;
- unsigned chunk_id;
- unsigned n_bytes;
- };
- struct yaffs_ecc_other {
- unsigned char col_parity;
- unsigned line_parity;
- unsigned line_parity_prime;
- };
- struct yaffs_packed_tags2 {
- struct yaffs_packed_tags2_tags_only t;
- struct yaffs_ecc_other ecc;
- };
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