1、struct jffs_control /* A struct for the overall file system control. Pointers to jffs_control structs are named `c' in the source code. */ struct jffs_control { struct super_block *sb; /* Reference to the VFS super block. */ struct jffs_file *root; /* The root directory file. */ struct list_head *hash; /* Hash table for finding files by ino. */ struct jffs_fmcontrol *fmc; /* Flash memory control structure. */ __u32 hash_len; /* The size of the hash table. */ __u32 next_ino; /* Next inode number to use for new files. */ __u16 building_fs; /* Is the file system being built right now? */ struct jffs_delete_list *delete_list; /* Track deleted files. */ pid_t thread_pid; /* GC thread's PID */ struct task_struct *gc_task; /* GC task struct */ struct completion gc_thread_comp; /* GC thread exit mutex */ __u32 gc_minfree_threshold; /* GC trigger thresholds */ __u32 gc_maxdirty_threshold; __u16 gc_background; /* GC currently running in background */ }; 解释: (1)为了快速由inode num找到文件的struct jffs_file结构,所以建立了长度为hash_len的哈西表,hash指向了该哈西表 (2)在jffs中,不论目录还是普通文件,都有一个struct jffs_file结构表示,成员变量root代表根文件。 (3)成员变量delete_list是为了删除文件而建立,只是在将文件系统mount到设备上而扫描flash的时候使用。
2、struct jffs_fmcontrol 很显然,这是一个描述整个flash使用情况的结构 struct jffs_fmcontrol { __u32 flash_size; __u32 used_size; __u32 dirty_size; __u32 free_size; __u32 sector_size; __u32 min_free_size; /* The minimum free space needed to be able to perform garbage collections. */ __u32 max_chunk_size; /* The maximum size of a chunk of data. */ struct mtd_info *mtd; //指向mtd设备 struct jffs_control *c; struct jffs_fm *head; struct jffs_fm *tail; struct jffs_fm *head_extra; struct jffs_fm *tail_extra; struct semaphore biglock; }; 解释: (1)整个flash上的空间=flash_size,已经使用了used_size的空间,在used_size中一共有dirty_size是dirty的,dirty也就是说在垃圾回收的时候可以回收的空间,free_size是你能够使用的flash上的空间 (2)整个flash上的所有used_size是通过一个struct jffs_fm的链表来管理的,head和tail分别指向了最老和最新的flash chunk (3)head_extra和tail_extra是在扫描flash的时候使用 (4)jffs中,对一个节点的数据块的大小是有限制的,最大是max_chunk_size
3、struct jffs_fm /* The struct jffs_fm represents a chunk of data in the flash memory. */ struct jffs_fm { __u32 offset; //在flash中的偏移 __u32 size; //大小 struct jffs_fm *prev; //形成双向链表 struct jffs_fm *next; struct jffs_node_ref *nodes; /* USED if != 0. */ }; 解释: (1)由于对文件的多次读写,一个struct jffs_fm可能会属于多个struct jffs_node结构,所以成员变量nodes代表了所有属于同一个jffs_fm的jffs_node的链表 (2)如果nodes==NULL,说明该jffs_fm不和任何node关联,也就是说该fm表示的区域是dirty的。
4、struct jffs_node 不论文件或是目录,flash上都是用jffs_raw_inode来表示,而struct jffs_node则是其在内存中的体现 /* The RAM representation of the node. The names of pointers to jffs_nodes are very often just called `n' in the source code. */ struct jffs_node { __u32 ino; /* Inode number. */ __u32 version; /* Version number. */ __u32 data_offset; /* Logic location of the data to insert. */ __u32 data_size; /* The amount of data this node inserts. */ __u32 removed_size; /* The amount of data that this node removes. */ __u32 fm_offset; /* Physical location of the data in the actual flash memory data chunk. */ __u8 name_size; /* Size of the name. */ struct jffs_fm *fm; /* Physical memory information. */ struct jffs_node *version_prev; struct jffs_node *version_next; struct jffs_node *range_prev; struct jffs_node *range_next; }; 解释: (1)每一次对文件的写操作都会形成一个新的version的节点,成员变量version表明了该节点的版本号 (2)一个文件是由若干节点组成,这些节点组成双象链表,所以该结构中的struct jffs_node *得成员变量都是为这些双向链表而设立的 (3)data_offset是逻辑偏移,也就是文件中的偏移,而fm_offset表明该节点的数据在jffs_fm上的偏移
5、struct jffs_file 该结构代表一个文件或者目录 /* The RAM representation of a file (plain files, directories, links, etc.). Pointers to jffs_files are normally named `f' in the JFFS source code. */ struct jffs_file { __u32 ino; /* Inode number. */ __u32 pino; /* Parent's inode number. */ __u32 mode; /* file_type, mode */ __u16 uid; /* owner */ __u16 gid; /* group */ __u32 atime; /* Last access time. */ __u32 mtime; /* Last modification time. */ __u32 ctime; /* Creation time. */ __u8 nsize; /* Name length. */ __u8 nlink; /* Number of links. */ __u8 deleted; /* Has this file been deleted? */ char *name; /* The name of this file; NULL-terminated. */ __u32 size; /* The total size of the file's data. */ __u32 highest_version; /* The highest version number of this file. */ struct jffs_control *c; struct jffs_file *parent; /* Reference to the parent directory. */ struct jffs_file *children; /* Always NULL for plain files. */ struct jffs_file *sibling_prev; /* Siblings in the same directory. */ struct jffs_file *sibling_next; struct list_head hash; /* hash list. */ struct jffs_node *range_head; /* The final data. */ struct jffs_node *range_tail; /* The first data. */ struct jffs_node *version_head; /* The youngest node. */ struct jffs_node *version_tail; /* The oldest node. */ }; 解释: (1)一个文件是由一系列不同的版本的节点组成的,而highest_version是最高版本 (2)一个文件维护两个双向链表,一个反映版本的情况,一个反映文件的区域,version_head和version_tail分别指向了最老和最新的节点,range_head指向文件中逻辑偏移为0的节点,沿着该链表,可以读出整个文件的内容。 (3)在jffs中,所有的文件形成一个树,树的根是jffs_control结构中的root,它是唯一的。通过每个jffs_file中的parent,children,sibling_prev,sibling_next指针可以把所有文件(包括目录)形成一个树
6、struct jffs_raw_inode 这是真正写到flash上的一个表示文件(目录)的一个节点的结构 /* The JFFS raw inode structure: Used for storage on physical media. */ /* Perhaps the uid, gid, atime, mtime and ctime members should have more space due to future changes in the Linux kernel. Anyhow, since a user of this filesystem probably have to fix a large number of other things, we have decided to not be forward compatible. */ struct jffs_raw_inode { __u32 magic; /* A constant magic number. */ __u32 ino; /* Inode number. */ __u32 pino; /* Parent's inode number. */ __u32 version; /* Version number. */ __u32 mode; /* The file's type or mode. */ __u16 uid; /* The file's owner. */ __u16 gid; /* The file's group. */ __u32 atime; /* Last access time. */ __u32 mtime; /* Last modification time. */ __u32 ctime; /* Creation time. */ __u32 offset; /* Where to begin to write. */ __u32 dsize; /* Size of the node's data. */ __u32 rsize; /* How much are going to be replaced? */ __u8 nsize; /* Name length. */ __u8 nlink; /* Number of links. */ __u8 spare : 6; /* For future use. */ __u8 rename : 1; /* Rename to a name of an already existing file? */ __u8 deleted : 1; /* Has this file been deleted? */ __u8 accurate; /* The inode is obsolete if accurate == 0. */ __u32 dchksum; /* Checksum for the data. */ __u16 nchksum; /* Checksum for the name. */ __u16 chksum; /* Checksum for the raw inode. */ };
二、注册文件系统 tatic int __init init_jffs_fs(void) 这个函数主要是建立struct jffs_fm 和 struct jffs_node的专用的缓冲区队列,然后通过register_filesystem(&jffs_fs_type)注册jffs文件系统。
三、jffs的挂接
1、read super 当通过命令mount -t jffs /dev/mtdblock0 /mnt/flash将文件系统mount到设备上的时候,通过sys_mount系统调用进入内核,并通过具体的文件系统的read_super函数建立起vfs的各种数据结构。 /* Called by the VFS at mount time to initialize the whole file system. */ static struct super_block * jffs_read_super(struct super_block *sb, void *data, int silent) { kdev_t dev = sb->s_dev; struct inode *root_inode; struct jffs_control *c; //jffs文件系统要求mount的设备必须是mtd if (MAJOR(dev) != MTD_BLOCK_MAJOR) { printk(KERN_WARNING "JFFS: Trying to mount a " "non-mtd device.\n"); return 0; }
sb->s_blocksize = PAGE_CACHE_SIZE; //设定块的大小 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->u.generic_sbp = (void *) 0; sb->s_maxbytes = 0xFFFFFFFF; //Maximum size of the files
//通过jffs_build_fs扫描整个flash,然后通过flash上的内容建立完整的文件树,对于jffs文件系统,所有的文件都在ram中有对应的结构,不论该文件是否打开 /* Build the file system. */ if (jffs_build_fs(sb) < 0) { //该函数下面具体分析 goto jffs_sb_err1; }
/* * set up enough so that we can read an inode */ sb->s_magic = JFFS_MAGIC_SB_BITMASK; //设置文件系统魔术 sb->s_op = &jffs_ops; //设置super block的操作方法
//这里建立根的dentry结构 /* Get the root directory of this file system. */ if (!(sb->s_root = d_alloc_root(root_inode))) { goto jffs_sb_err3; }
//获得sb中jffs_control的指针 c = (struct jffs_control *) sb->u.generic_sbp;
/* Set the Garbage Collection thresholds */ //当flash上的free size小于gc_minfree_threshold的时候,会启动垃圾回收,以便释放一些空间 /* GC if free space goes below 5% of the total size */ c->gc_minfree_threshold = c->fmc->flash_size / 20;
if (c->gc_minfree_threshold < c->fmc->sector_size) c->gc_minfree_threshold = c->fmc->sector_size; //当flash上的dirty size大于gc_maxdirty_threshold的时候,会启动垃圾回收,以便释放一些空间 /* GC if dirty space exceeds 33% of the total size. */ c->gc_maxdirty_threshold = c->fmc->flash_size / 3;
if (c->gc_maxdirty_threshold < c->fmc->sector_size) c->gc_maxdirty_threshold = c->fmc->sector_size;
jffs_sb_err3: iput(root_inode); jffs_sb_err2: jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp); jffs_sb_err1: printk(KERN_WARNING "JFFS: Failed to mount device %s.\n", kdevname(dev)); return 0; }
2、初始化fs,建立文件树 /* This is where the file system is built and initialized. */ int jffs_build_fs(struct super_block *sb) { struct jffs_control *c; int err = 0;
//从当前位置读从一个u32 switch (flash_read_u32(fmc->mtd, pos)) { case JFFS_EMPTY_BITMASK: 如果读到的字节是JFFS_EMPTY_BITMASK也就是0xffffffff,那么该位置上flash是free的,我们还没有使用它,接着就会用一个4k的buffer去读直到不是JFFS_EMPTY_BITMASK的位置停止。 case JFFS_DIRTY_BITMASK: 如果读到的字节是JFFS_DIRTY_BITMASK也就是0x00000000,那么读出所有的连续的0x00000000,分配一个jffs_fm结构表示该区域,但是jffs_fm->nodes为空,也就是标示该区域为dirty,并把该jffs_fm连接到jffs_fmcontrol的双向链表中。一般这种区域是由于到了flash的末尾,剩余的空间不够写一个jffs_raw_inode结构,所以全部写0
case JFFS_MAGIC_BITMASK: 找到一个真正的jffs_raw_inode结构,将该raw indoe 读出来,如果是一个bad raw inode(例如校验错误等等),那么分配一个jffs_fm结构表示该区域,但是jffs_fm->nodes为空,也就是标示该区域为dirty;如果是一个good inode,那么建立jffs_node结构和jffs_fm结构,并把该jffs_fm连接到jffs_fmcontrol的双向链表中,然后把jffs_node插入到jffs_file的version list中,表明该node的文件的jffs_file结构先通过哈西表查找,如果没有则创建,一般来说,如果这个jffs_node是扫描到的该文件的第一个节点,那么就需要创建jffs_file结构,此后就可以通过哈西表找到该jffs_file结构。
用户1053025 2006-10-20 09:54