您的位置:首页 > 运维架构 > Linux

Linux内核---22.mkyaffs2image

2016-07-04 19:23 435 查看
一. mkyaffs2image 是如何生成的
我们往往用 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

我这儿只是改了 chunkSize 与 spareSize.但是貌似datasheet上的spareSize=218. 莫非datasheet也可以骗人?



二. 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);

}

2.1 对目录的处理过程

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;

}

2.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)

{

    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");

        }

    }

}

d
三. 实验一下
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

b. 利用mkyaffs2image生成yaffs的打包文件fs.yaffs

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

可以看出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

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;

};

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: