Linux文件系统原理.doc

上传人:豆**** 文档编号:17418922 上传时间:2022-05-24 格式:DOC 页数:23 大小:213KB
返回 下载 相关 举报
Linux文件系统原理.doc_第1页
第1页 / 共23页
Linux文件系统原理.doc_第2页
第2页 / 共23页
点击查看更多>>
资源描述

《Linux文件系统原理.doc》由会员分享,可在线阅读,更多相关《Linux文件系统原理.doc(23页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流Linux文件系统原理.精品文档.Linux文件系统原理第1章 概述要理解linux的文件系统,要从理解虚拟文件系统(VFS,Virtual Filesystem)开始。其结构可以用图表1来描述。图表 1第2章 虚拟文件系统2.1 它到底是什么?虚拟文件系统是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口。它也提供了内核中的一个抽象功能,允许不同的文件系统共存。2.2 工作方式概述2.2.1 注册和安装一个文件系统如果你想在内核中支持一种新的文件系统的话,你所需要做的仅仅是调用函数register_filesystem()

2、。你向内核中传递一个描述文件系统实现 的结构(struct filesystem), 此结构将被加入到内核的支持文件系统表中去。你可以运行下面的命令:% cat /proc/filesystems这样可以看到你的系统支持哪些文件系统。 内核模块必须提供两个用于加载和卸载时调用的接口,这两个接口由两个固定的宏引出,分别为module_init(),module_exit()。文件系统在作为模块被加载到内核时,调用register_filesystem(),把自己注册为一种文件系统。在模块被卸载时,调用unregister_filesystem()从内核中注消。以JFFS为例:/ 定义一种文件系统

3、jffs_fs_type,其名称为“JFFS”static DECLARE_FSTYPE_DEV(jffs_fs_type, jffs, jffs_read_super);static int _initinit_jffs_fs(void)printk(KERN_INFO JFFS version JFFS_VERSION_STRING, (C) 1999, 2000 Axis Communications ABn);#ifdef CONFIG_JFFS_PROC_FSjffs_proc_root = proc_mkdir(jffs, proc_root_fs);#endiffm_cache

4、= kmem_cache_create(jffs_fm, sizeof(struct jffs_fm), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);node_cache = kmem_cache_create(jffs_node,sizeof(struct jffs_node), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);/ 注册文件系统return register_filesystem(&jffs_fs_type); static void _exitexit_jffs_fs(void)/ 注消文件系统unregister_files

5、ystem(&jffs_fs_type);kmem_cache_destroy(fm_cache);kmem_cache_destroy(node_cache);/ 引出模块的加载和卸载时调用的接口module_init(init_jffs_fs)module_exit(exit_jffs_fs)当一个mount请求出现时,VFS将会为特定的文件系统调用相应的方法。安装点的dentry结构将会被改为指向新文件系统的根i节点。 2.2.2 打开一个文件VFS实现了open系统调用。路径参数被VFS用来在目录入口缓存(dentry cache or dcache)。这提供了一个将路径名转化为特定的

6、dentry的一个快的查找机制。 一个单独的dentry通常包含一个指向i节点(inode)的指针。i节点存在于磁盘驱动器上,它可以是一个规则文件,目录,FIFO文 件,等等。Dentry存在于RAM中,并且永远不会被存到磁盘上:它们仅仅为了提高系统性能而存在。i节点存在于磁盘上,当需要时被拷入内存中,之后对 它的任何改变将被写回磁盘。存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是它。dcache是你的整个文件空间的观察点。大多数情况下不可能有足够的RAM空间来放我们的文件空间的所有文件的目录入口缓存(dentry),所以我们的dcache会有缺少的项。为了将路径

7、名转换为一个dentry,VFS不得不采取创建dentry的方式,并在创建dentry时将指针指向相应的i节点。这是通过对i节点的查找完成的。 为了查找一个文件的i节点(通常从磁盘上读),VFS需要调用该文件的父目录的lookup()方法,此方法是特定的文件系统所设置的。后面对此将会有更详尽的描述。 一旦VFS得到了所需要的dentry(同时也得到了相应的i节点),我们就能够对文件做想要的操作:打开文件,或者用stat来看 i节点中的数据。stat的操作非常简单:在VFS得到dentry之后,它取得inode中的一些数据并将其中的一部分送回用户空间。打开一个文件需要其它的操作:分配一个stru

8、ct file(定义于linux/fs.h,这是内核中的文件描述)结构。新分配的struct file结构被指向dentry的指针和对文件进行操作的函数集合所初始化,这些都是从i节点中得到的。通过这种方式,特定的文件系统实现才能起作用。文件结构(struct file)被放在进程的文件描述符表中。 读,写和关闭文件(或者其它的VFS操作)是通过使用用户空间的文件描述符找到相应的文件结构(struct file),然后调用所需要的方法函数来实现的。 当文件处于打开状态时,系统保持相应的dentry为open状态(正在使用),这表示相应的i节点在被使用。 2.3 主要结构说明2.3.1 struc

9、t file_system_type此结构描述了文件系统。在内核2.4.18中,此结构的定义如下:struct file_system_type const char *name;int fs_flags;struct super_block *(*read_super) (struct super_block *, void *, int);struct module *owner;struct file_system_type * next;struct list_head fs_supers;其中各个域的意义:name:文件系统的类型名称,如vfat,ext2,等等。fs_flags:变

10、量标志,如FS_REQUIRES_DEV, FS_NO_DCACHE,等等。read_super:当此种文件系统的一个新的实例要被安装时,此方法会被调用。owner:实例所在的模块,通常默认为THIS_MODULE。next:被内部的VFS实现所使用,你只需要将其初始化为NULL。 fs_supers:超级块链表,初始化为NULL即可。函数read_super具有以下的参数:struct super_block *sb:超级块结构。此结构的一部分被VFS初始化,余下的部分必须被函数read_super初始化。void * data:任意的安装选项,通常是ASCII的字符串。在JFFS中没有使用

11、。int silent:表示当出现错误时是否保持安静。(不报警?) 在JFFS中没有使用。read_super方法必须确定指定的块设备是否包含了一个所支持的文件系统。当成功时返回超级块结构的指针,错误时返回NULL。 read_super方法填充进超级块结构(struct super_block)的最有用的域是s_op域。这是一个指向struct super_operations的指针,此结构描述了文件系统实现的下一层细节。 2.3.2 struct super_operations此结构描述了VFS对文件系统的超级块所能进行的操作。在内核2.4.18中,此结构的定义如下:struct sup

12、er_operations void (*read_inode) (struct inode *); void (*read_inode2) (struct inode *, void *) ; void (*dirty_inode) (struct inode *);void (*write_inode) (struct inode *, int);void (*put_inode) (struct inode *);void (*delete_inode) (struct inode *);void (*put_super) (struct super_block *);void (*wr

13、ite_super) (struct super_block *);void (*write_super_lockfs) (struct super_block *);void (*unlockfs) (struct super_block *);int (*statfs) (struct super_block *, struct statfs *);int (*remount_fs) (struct super_block *, int *, char *);void (*clear_inode) (struct inode *);void (*umount_begin) (struct

14、super_block *);struct dentry * (*fh_to_dentry)(struct super_block *sb, _u32 *fh, int len, int fhtype, int parent);int (*dentry_to_fh)(struct dentry *, _u32 *fh, int *lenp, int need_parent);int (*show_options)(struct seq_file *, struct vfsmount *);除非特别提出,所有的方法都在未加锁的情况下被调用,这意味着大多数方法都可以安全的被阻塞。所有的方法都仅仅在

15、进程空间被调用(例如,在中断处理程序和底半部中不能调用它们) read_inode:从一个文件系统中读取一个特定的i节点时调用此方法。i节点中的域i_ino被VFS初始化为指向所读的i节点,其余的域被此方法所填充。 read_inode2:专为reiserfs留的,其它文件系统现在用不到。write_inode:当VFS需要向磁盘上的一个i节点写时调用。 put_inode:当VFS的i节点被从i节点缓冲池移走时被调用。此方法是可选的。 delete_inode:当VFS想删除一个i节点时调用次方法。 notify_change:当VFS的i节点的属性被改变时调用。若此域为NULL则VFS会调

16、用rite_inode。此方法调用时需要锁住内核。put_super:当VFS要释放超级块时调用(umount一个文件系统)。此方法调用时需要锁住内核。 write_super:当VFS超级块需要被写入磁盘时被调用。此方法为可选的。 statfs:当VFS需要得到文件系统的统计数据时调用。此方法调用时需要锁住内核。 remount_fs:当文件系统被重新安装时调用。此方法调用时需要锁住内核。 clear_inode:当VFS清除i节点时调用。可选项。 以上方法中,read_inode需要填充i_op域,此域为一个指向struct inode_operations结构的指针,它描述了能够对一个单

17、独的i节点所能进行的操作。 其它的一些域在很多文件系统里都没有使用,可以不用关心。2.3.3 struct inode_operations此结构描述了VFS能够对文件系统的一个i节点所能进行的操作。在内核2.4.18中,此结构的定义如下: struct inode_operations int (*create) (struct inode *,struct dentry *,int);struct dentry * (*lookup) (struct inode *,struct dentry *);int (*link) (struct dentry *,struct inode *,s

18、truct dentry *);int (*unlink) (struct inode *,struct dentry *);int (*symlink) (struct inode *,struct dentry *,const char *);int (*mkdir) (struct inode *,struct dentry *,int);int (*rmdir) (struct inode *,struct dentry *);int (*mknod) (struct inode *,struct dentry *,int,int);int (*rename) (struct inod

19、e *, struct dentry *,struct inode *, struct dentry *);int (*readlink) (struct dentry *, char *,int);int (*follow_link) (struct dentry *, struct nameidata *);void (*truncate) (struct inode *);int (*permission) (struct inode *, int);int (*revalidate) (struct dentry *);int (*setattr) (struct dentry *,

20、struct iattr *);int (*getattr) (struct dentry *, struct iattr *);create:被open和creat所调用,仅仅在你要支持普通文件时才需要。参数中的dentry不应该包含有i节点的指 针(即应该为一个negative dentry)。这里你可能需要对传入的dentry和i节点调用函数d_instantiate。 lookup:当VFS要在一个父目录中查找一个i节点时调用。待查找的文件名在dentry中。此方法必须调用d_add函数把找到的 i节点插入到dentry中,i节点的i_count域要加一。若指定的i节点不存在的话,一个

21、NULL的i节点指针将被插入到dentry中去(这 种情况的dentry被称为negative dentry)。link:被link所调用。仅在你需要支持hard link时才需要它。跟create方法相同的原因,你可能在此方法中也需要调用d_instantiate()函数来验证。 unlink:被unlink所调用。仅在你要支持对i节点的删除时才需要它。 symlink:被symlink调用。仅在需要支持符号链接时才需要它。通上面两处,你需要对传入的参数进行验证,要调用d_instantiate()函数。 mkdir:被mkdir调用。仅在你要支持建立子目录时才需要它。同上,你需要调用d_i

22、nstantiate()函数进行验证。 rmdir:被rmdir所调用。仅在你要支持对子目录的删除时才需要它。 mknod:被mknod所调用,用于建立一个设备i节点,或者FIFO,或socket。仅当你需要支持对这些类型的i节点的建立时才需要此方法。同上面几个,你可能也需要调用_instantiate来验证参数。 rename:被rename调用。仅在你要支持对文件和目录改名时才需要它。readlink:被readlink调用。仅当你要支持对符号链接的读取才需要它。 follow_link:被VFS调用,用以从一个符号链接找到相应的i节点。仅当你需要支持符号链接时才需要此方法。 2.3.4

23、struct file_operations结构file_operations包含了VFS对一个已打开文件的操作。在内核2.4.18中,此结构的定义如下:struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t, loff_t *);int (*read

24、dir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct fil

25、e *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*write

26、v) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);llseek:当VFS需要移动文件指针的位置时调用。 read:被read所调用。 wri

27、te:被write所调用。 readdir:当VFS需要读取目录中的内容时被调用。 poll:当一个进程想知道文件是否可用是调用,进程可以一直休眠等待文件可用。功能有点类似SOCKET中的select。 ioctl:被ioctl所调用。 mmap:被mmap所调用。 open:当VFS要打开一个i节点时调用它。当VFS打开一个文件时,它建立一个新的struct file结构,并用i节点中的default_file_ops来初始化其中的f_op域,然后对新分配的文件结构调用open方法。你可以认为 open方法实际上属于struct inode_operations。open方法是一个很好的初始

28、化文件结构中的private_data域的的地方。 release:当没有对被打开文件的引用时调用此方法。 fsync:被fsync所调用。 fasync:当用fcntl激活一个文件的异步模式时此方法被调用。 这些文件操作是由i节点所在的特定文件系统所实现的。当打开一个设备节点时(字符或块设备特殊文件),大多数文件系统会调用VFS中的特定支持例程,由此来找到所需要的设备驱动信息; 这些支持例程用设备驱动程序的方法来代替文件系统的文件操作,然后继续对文件调用新的open方法。这就是为什么当你打开文件系统上的一个 设备特殊文件时,最后被调用的却是设备驱动程序的open方法。另外,devfs(Dev

29、ice Filesystem)有一个从设备节点到设备驱动程序的更直接的方式(这是非官方的内核补丁) 2.3.5 struct dentry_operationsoperations.Dentries和dcache是属于VFS和单个文件系统实现的,设备驱动与此无关。在内核2.4.18中,此结构的定义如下:struct dentry_operations int (*d_revalidate)(struct dentry *, int);int (*d_hash) (struct dentry *, struct qstr *);int (*d_compare) (struct dentry *,

30、 struct qstr *, struct qstr *);int (*d_delete)(struct dentry *);void (*d_release)(struct dentry *);void (*d_iput)(struct dentry *, struct inode *);d_revalidate:当VFS要使一个dentry重新生效时被调用。 d_hash:当VFS向哈希表中加入一个dentry时被调用。 d_compare:当指向一个dentry的最后的引用被去除时此方法被调用,因为这意味这没有人在使用此dentry;当然,此dentry仍然有效,并且仍然在dcache

31、中。 d_release: 当一个dentry被清除时调用此方法。 d_iput:当一个dentry释放它的i节点时(在dentry被清除之前)此方法被调用。为空时自动调用VFS的input(),如果定义了这个函数,那要自己调用input()。每个dentry都有一个指向其父目录dentry的指针,一个子dentry的哈希列表。子dentry基本上就是目录中的文件。 dget:为一个已经存在的dentry打开一个新的句柄(这仅仅增加引用计数) dput:关闭一个dentry的句柄(减少引用计数)。如果引用计数减少为0,d_delete方法将会被调用;并且,如果此 dentry仍然在其父目录的哈

32、希列表中的话,此dentry将被放置于一个未被使用的列表中。将dentry放置于未使用表中意味着当系统需要更多的 RAM时,将会遍历未使用的dentry的列表,并回收其内存空间。假如当detry的引用计数为0时,它已经没有在父目录的哈希表中的话,在 d_delete方法被调用之后系统就会回收起内存空间。 d_drop: 此方法将一个dentry从其父目录的哈希列表中去掉。如果被去掉的dentry的引用计数降为0的话,系统会马上调用d_put来去掉此dentry。 d_delete:删除一个dentry。如果没有别的对此dentry的打开引用的话,此dentry会变成一个negative den

33、try(d_iput方法会被调用);如果有别的对此dentry的引用的话,将会调用d_drop。 d_add:向父目录的哈希列表中加入一个dentry,然后调用d_instantiate()。 d_instantiate:把一个dentry加入别名哈希列表中,并更新其d_inode域为所给的i节点。i节点中的i_count 域加一。假如i节点的指针为NULL,此dentry就被称为negative dentry。此函数通常在为一个已存在的negative dentry建立i节点时被调用。 第3章 JFFS3.1 jffs体系结构介绍 3.1.1 存储结构 在jffs中,所有的文件和目录是一样对

34、待的,都是用一个jffs_raw_inode来表示 整个flash上就是由一个一个的raw inode排列组成,一个目录只有一个raw inode,对于文件则是由一个或多个raw inode组成。 3.1.2 文件组成 在文件系统mount到flash设备上的时候,会扫描flash,从而根据flash上的所有属于一个文件的raw inode建立一个jffs_file结构以及node list。 下面的图显示了一个文件的组成 一个文件是由若干个jffs_node组成,每一个jffs_node是根据flash上得jffs_raw_inode而建立的,jffs_file主要维护两个链表 版本链表:主

35、要是描述该node创建的早晚,就是说version_head指向的是一个最老的node,也就意味着垃圾回收的时候最该回收的就是这个最老的node。 区域链表:这个链表主要是为读写文件创建的,version_head指向的node代表的文件数据区域是0n-1 之后依次的节点分别是 nm-1 mo-1 .其中nmo .。当你从文件的0位置读的话,那么定位到verision_head指向的第一个node,当你从文件的中间位置读的话,那么定位到区域链表的某一个中间的node上。 3.1.3 操作 对文件的读操作应该是比较简单,但是写操作,包括更改文件名等操作都是引起一个新的jffs_node的诞生,同

36、时要写一个相映的raw inode到flash上,这样的操作有可能导致前面的某个jffs_node上面的数据完全失效,从而导致对应flash上的raw inode的空间成为dirty。 下面举一个例子可能会更清楚一些。 一个文件的range list是由上面的三个jffs_node组成,当我们做如下写操作的时候 lseek( fd, 10, SEEK_SET ); write( fd, buf,40 ); 第一个和最后一个node被截短了,第二个node完全被新数据替换,该node会从链表上摘下来,flash上空间变成dirty。如果做如下写操作的时候 lseek( fd, 23, SEEK_

37、SET ); write( fd, buf,5 ); 此时,第二个node被分裂成两个node,同时产生一个新的node,range链表的元素变成五个。 3.1.4 垃圾回收 我们的flash上的内容基本上是有两种情况,一种是前面一段是used,后面是free的,还有一个是中间一段是used,flash的开始和底部都是free的,但是不管如何,如果符合了垃圾回收的条件,就要启动垃圾回收。Used的空间中,有一部分是我们真正需要的数据,还有一部分由于我们的对文件的写,删除等操作而变成dirty的空间,我们垃圾回收的目标就是把这些dirty的空间变成free的,从而可以继续使用。 Used的空间是

38、有一个个的jffs_fm的链表组成,垃圾回收也总是从used的最顶部开始,如果jffs_fm不和任何的jffs_node相关,那么我们就认为jffs_fm代表的这块flash空间是dirty的,找到了完整的至少一个sector的dirty空间,就可以把这个sector擦掉,从而增加一个sector的free空间。 3.2 数据结构分析 这些结构不会是每一个成员变量都作解释,有的英语注释说的很清楚了,有些会在下面的相关的代码解释 3.2.1 struct jffs_control /* A struct for the overall file system control. Pointers

39、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; /* Flas

40、h 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 thre

41、ads 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 j

42、ffs_file结构,所以建立了长度为hash_len的哈西表,hash指向了该哈西表 (2)在jffs中,不论目录还是普通文件,都有一个struct jffs_file结构表示,成员变量root代表根文件。 (3)成员变量delete_list是为了删除文件而建立,只是在将文件系统mount到设备上而扫描flash的时候使用。 (4)文件号最小是1,分配给了根,此后,每创建一个文件next_no就会加一。当文件删除之后,也不会回收文件号,毕竟当next_no到达最大值的时候,flash恐怕早就挂拉。 3.2.2 struct jffs_fmcontrol 很显然,这是一个描述整个flash使

43、用情况的结构 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; /指

44、向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上的

45、所有used_size是通过一个struct jffs_fm的链表来管理的,head和tail分别指向了最老和最新的flash chunk (3)head_extra和tail_extra是在扫描flash的时候使用 (4)jffs中,对一个节点的数据块的大小是有限制的,最大是max_chunk_size 3.2.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; /

46、大小 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的。 3.2.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

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 小学资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com