免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3313 | 回复: 5
打印 上一主题 下一主题

明明白白我的心--fs series [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-17 20:16 |只看该作者 |倒序浏览
明明白白我的心--fs series

文章地址: http://blog.chinaunix.net/u3/114767/showart_2292149.html

作者:GTT
本文档归属http://oldtown.cublog.cn/.转载请注明出处!
请提出宝贵意见Mail:mtloveft@hotmail.com
Linux Version:2.6.33
提示:本文是关于file system 实现的介绍!

明明白白我的心--fs series系列是关于介绍linux文件系统的。学习linux文件系统普通都是从
VFS下手,然后再学习具体的文件系统,其实顺序有点问题,如果按照linux文件系统的发展学习,对
VFS可以很容易掌握的。

先整体看看文件系统的构成图


可以看出VSF在文件系统中是出于中心位置。VSF-即Virtual File System ,其它实际的文件系统可以看作是VFS的实例,而VSF可以看作是FS的抽象。

论坛徽章:
0
2 [报告]
发表于 2010-08-17 20:19 |只看该作者
明明白白我的心--fs series(2)


文章地址:http://blog.chinaunix.net/u3/114767/showart_2292171.html

提起文件系统,基本都会想到harddisk上的文件系统,harddisk可以分区,每个分区可以安装一个文件系统,
关于分区,请参看下图


最初的一个扇区是启动扇区,只有512 Byte的大小。其中就有关于分区的信息,还有OS的引导代码。
minixFS的format如下


分区被分成Block进行管理,也就是块管理。
boot Block           :引导块,负者OS的引导。
super Block      :超级块,管理整个FS的信息
inode bitMaps    :i节点位图块,可以有n个块,块数据中,每个bit位代表一个inode,1代表inode使用,0代表未使用
block bitMaps   :数据块位图,可以有n个块,块数据中,每个bit位代表一个数据块,1代表数据块使用,0代表未使用
inodes blocks   :inode数据结构占有的块,
data blocks       :数据块,实际文件的数据,或者目录的子文件名和子目录名

再来看看ext2Fs的format



是不是MinixFS和Ext2FS很像啊,其实Ext2名字就能看出来,他是根据minix进行的第二次扩展。所以叫ext2,在minixFS的基础上又包了一层BlockGroup。其它没有什么特别的了。
上一篇介绍的VSF就是在这些文件系统之后抽象出来的,不是先有VSF的。最初是用minix1.0, 后来进行扩展,再扩展,再再扩展,又再再扩展,即ext,ext2,ext3, ext4。

论坛徽章:
0
3 [报告]
发表于 2010-08-17 20:25 |只看该作者
明明白白我的心--fs series(3)

文章地址:http://blog.chinaunix.net/u3/114767/showart_2292187.html

先来看看minix在早期linux版本中的实现,以下代码是linux0.11版本的。


超级块的定义如下
  1. struct super_block {
  2.     unsigned short s_ninodes;
  3.     unsigned short s_nzones;
  4.     unsigned short s_imap_blocks;
  5.     unsigned short s_zmap_blocks;
  6.     unsigned short s_firstdatazone;
  7.     unsigned short s_log_zone_size;
  8.     unsigned long s_max_size;
  9.     unsigned short s_magic;
  10. /* These are only in memory */
  11.     struct buffer_head * s_imap[8];
  12.     struct buffer_head * s_zmap[8];
  13.     unsigned short s_dev;
  14.     struct m_inode * s_isup;
  15.     struct m_inode * s_imount;
  16.     unsigned long s_time;
  17.     struct task_struct * s_wait;
  18.     unsigned char s_lock;
  19.     unsigned char s_rd_only;
  20.     unsigned char s_dirt;
  21. }
复制代码
相关说明如下
字段名称            説明

s_ninodes               i节点数
s_nzones                数据块数
s_imap_blocks i      节点位图占有的块数
s_zmap_blocks       数据块位图占有的块数
s_firstdatazone      数据块中第一个数据块的块号
s_log_zone_size    disk块数/逻辑块
s_max_size            最大文件长度
s_magic                  文件系统的幻数

所以super block 对于FS来说是最重要的数据结构了。
通过SB可以知道Block的安排了。当然就知道了FS的大小了。通过inode bitmaps 就可以知道那个inode还没有被使用,通过block bitmaps就知道数据块中还有哪块没有被使用。整个文件系统就可以被管理了。

i节点的定义如下
  1. struct m_inode {
  2.     unsigned short i_mode;
  3.     unsigned short i_uid;
  4.     unsigned long i_size;
  5.     unsigned long i_mtime;
  6.     unsigned char i_gid;
  7.     unsigned char i_nlinks;
  8.     unsigned short i_zone[9];
  9. /* these are in memory also */
  10.     struct task_struct * i_wait;
  11.     unsigned long i_atime;
  12.     unsigned long i_ctime;
  13.     unsigned short i_dev;
  14.     unsigned short i_num;
  15.     unsigned short i_count;
  16.     unsigned char i_lock;
  17.     unsigned char i_dirt;
  18.     unsigned char i_pipe;
  19.     unsigned char i_mount;
  20.     unsigned char i_seek;
  21.     unsigned char i_update;
  22. }
复制代码
   
相关说明如下

字段名称   説明

i_mode    文件类型和属性
i_uid        用户 id
i_size      文件长度
i_mtime   修改时间
i_gid       组id
i_nlinks   链接数
i_zone[9] 文件占用的逻辑快数组
           zone[0]-zone[6]是直接块号
           zone[7]是一次间接块号
           zone[8]是二次间接块号


根据i_zone, 知道了i节点,就知道了对应的数据放到了什么位置。

还有关于目录项的定义
  1. struct dir_entry {
  2.     unsigned short inode;
  3.     char name[NAME_LEN];
  4. }

复制代码
文件的定义如下
  1. struct file {
  2.     unsigned short f_mode;
  3.     unsigned short f_flags;
  4.     unsigned short f_count;
  5.     struct m_inode * f_inode;
  6.     off_t f_pos;
  7. }

复制代码
看到了什么,文件中有inode的指针。对文件的动作,最好都会根据inode来对实际数据进行操作。

再来看看minixFS是如何进行数据管理的



i3 即inode3如果他是个目录节点的话,它的i_zone[0]将是一个目录数据块号,数据内容将是dir_entry数据结构的数组。这样目录下的
文件名和目录名将全部能产看到。如果目录下文件或者子目录很多的话,可以通过i_zone[7]继续查找到,还有根多的子文件或者
子目录的话,就通过i_zone[8]进行2次间接查找。
D3 即dir_entry3 它的inode 指向i2, 而i2是个二进制文件,那么i_zone[0]将指向一个有实际数据的数据块。

如果知道根节点,那么顺着根节点,可以找到所有的文件和目录,所以根节点是必须设定的。
给定一个i节点,这个i节点下的文件和目录也将可以查找到。有了理论,程序就很容易实现了。
而文件的数据结构struct file根inode关联起来,这样文件的读,写就根据inode可以找到数据的位置了。
minix得结构还是比较简单的,如果了解了minix,其他再复杂的文件系统,也会很快理解的了。
data block 的号码是逻辑号码,读写数据就直接交给harddisk的驱动程序处理,驱动程序根据分区和data block 的号码算出实际的扇区号进行读写。
读出的数据先放到buffer cache,写入的数据也是先放到buffer cache.这样,文件系统就只要和buffer cache 交互就可以了,可以提高工作效率。

我认为minix的几个问题是文件放置的效率,还有,如果super block坏了的话文件系统就崩溃了,可以说无法修复的。因为无法知道根接点的数据
放到什么位置了。安区性问题很严重。当然minixFS 得容量也很小。不过对于教学研究,是很值得研究的文件系统。

论坛徽章:
0
4 [报告]
发表于 2010-08-17 20:29 |只看该作者
明明白白我的心--fs series(4)

文章地址:http://blog.chinaunix.net/u3/114767/showart_2292196.html

再来看看linux 2.6.33中ext2的结构图
  

super block的定义如下
  1. struct ext2_super_block {
  2.     __le32 s_inodes_count; /* Inodes count */
  3.     __le32 s_blocks_count; /* Blocks count */
  4.     __le32 s_r_blocks_count; /* Reserved blocks count */
  5.     __le32 s_free_blocks_count; /* Free blocks count */
  6.     __le32 s_free_inodes_count; /* Free inodes count */
  7.     __le32 s_first_data_block; /* First Data Block */
  8.     __le32 s_log_block_size; /* Block size */
  9.     __le32 s_log_frag_size; /* Fragment size */
  10.     __le32 s_blocks_per_group; /* # Blocks per group */
  11.     __le32 s_frags_per_group; /* # Fragments per group */
  12.     __le32 s_inodes_per_group; /* # Inodes per group */
  13.     __le32 s_mtime; /* Mount time */
  14.     __le32 s_wtime; /* Write time */
  15.     __le16 s_mnt_count; /* Mount count */
  16.     __le16 s_max_mnt_count; /* Maximal mount count */
  17.     __le16 s_magic; /* Magic signature */
  18.     __le16 s_state; /* File system state */
  19.     __le16 s_errors; /* Behaviour when detecting errors */
  20.     __le16 s_minor_rev_level; /* minor revision level */
  21.     __le32 s_lastcheck; /* time of last check */
  22.     __le32 s_checkinterval; /* max. time between checks */
  23.     __le32 s_creator_os; /* OS */
  24.     __le32 s_rev_level; /* Revision level */
  25.     __le16 s_def_resuid; /* Default uid for reserved blocks */
  26.     __le16 s_def_resgid; /* Default gid for reserved blocks */
  27.     __le32 s_first_ino; /* First non-reserved inode */
  28.     __le16 s_inode_size; /* size of inode structure */
  29.     __le16 s_block_group_nr; /* block group # of this superblock */
  30.     __le32 s_feature_compat; /* compatible feature set */
  31.     __le32 s_feature_incompat; /* incompatible feature set */
  32.     __le32 s_feature_ro_compat; /* readonly-compatible feature set */
  33.     __u8 s_uuid[16]; /* 128-bit uuid for volume */
  34.     char s_volume_name[16]; /* volume name */
  35.     char s_last_mounted[64]; /* directory where last mounted */
  36.     __le32 s_algorithm_usage_bitmap;/* For compression */
  37.     __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
  38.     __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
  39.     __u16 s_padding1;
  40.     __u8 s_journal_uuid[16]; /* uuid of journal superblock */
  41.     __u32 s_journal_inum; /* inode number of journal file */
  42.     __u32 s_journal_dev; /* device number of journal file */
  43.     __u32 s_last_orphan; /* start of list of inodes to delete */
  44.     __u32 s_hash_seed[4]; /* HTREE hash seed */
  45.     __u8 s_def_hash_version; /* Default hash version to use */
  46.     __u8 s_reserved_char_pad;
  47.     __u16 s_reserved_word_pad;
  48.     __le32 s_default_mount_opts;
  49.     __le32 s_first_meta_bg; /* First metablock block group */
  50.     __u32 s_reserved[190]; /* Padding to the end of the block */
  51. };

复制代码
inode的定义如下
  1. struct ext2_inode {
  2.     __le16 i_mode; /* File mode */
  3.     __le16 i_uid; /* Low 16 bits of Owner Uid */
  4.     __le32 i_size; /* Size in bytes */
  5.     __le32 i_atime; /* Access time */
  6.     __le32 i_ctime; /* Creation time */
  7.     __le32 i_mtime; /* Modification time */
  8.     __le32 i_dtime; /* Deletion Time */
  9.     __le16 i_gid; /* Low 16 bits of Group Id */
  10.     __le16 i_links_count; /* Links count */
  11.     __le32 i_blocks; /* Blocks count */
  12.     __le32 i_flags; /* File flags */
  13.     union {
  14.         struct {
  15.             __le32 l_i_reserved1;
  16.         } linux1;
  17.         struct {
  18.             __le32 h_i_translator;
  19.         } hurd1;
  20.         struct {
  21.             __le32 m_i_reserved1;
  22.         } masix1;
  23.     } osd1; /* OS dependent 1 */
  24.     __le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
  25.     __le32 i_generation; /* File version (for NFS) */
  26.     __le32 i_file_acl; /* File ACL */
  27.     __le32 i_dir_acl; /* Directory ACL */
  28.     __le32 i_faddr; /* Fragment address */
  29.     union {
  30.         struct {
  31.             __u8 l_i_frag; /* Fragment number */
  32.             __u8 l_i_fsize; /* Fragment size */
  33.             __u16 i_pad1;
  34.             __le16 l_i_uid_high; /* these 2 fields */
  35.             __le16 l_i_gid_high; /* were reserved2[0] */
  36.             __u32 l_i_reserved2;
  37.         } linux2;
  38.         struct {
  39.             __u8 h_i_frag; /* Fragment number */
  40.             __u8 h_i_fsize; /* Fragment size */
  41.             __le16 h_i_mode_high;
  42.             __le16 h_i_uid_high;
  43.             __le16 h_i_gid_high;
  44.             __le32 h_i_author;
  45.         } hurd2;
  46.         struct {
  47.             __u8 m_i_frag; /* Fragment number */
  48.             __u8 m_i_fsize; /* Fragment size */
  49.             __u16 m_pad1;
  50.             __u32 m_i_reserved2[2];
  51.         } masix2;
  52.     } osd2; /* OS dependent 2 */
  53. };

复制代码
而目录项的定义如下
  1. struct ext2_dir_entry_2 {
  2.     __le32 inode;   /* Inode number */
  3.     __le16 rec_len; /* Directory entry length */
  4.     __u8 name_len; /* Name length */
  5.     __u8 file_type;
  6.     char name[EXT2_NAME_LEN]; /* File name */
  7. };
复制代码
再来看看ext2FS是如何进行数据管理的



看上去只是比minixFS,多了一个3次间接索引。这样ext2FS的单个文件的Size可以更大。
上图中b-no等我就是随便起的名字,意思就是数据块的内容是block number.

追加一些内容,忘了写了,就是在现在版本中对文件的定义,因为不说这个队VFS的实现就有点困难了。

定义如下
  1. struct file {
  2.     /* fu_list becomes invalid after file_free is called and queued via fu_rcuhead for RCU freeing */
  3.     union {
  4.         struct list_head fu_list;
  5.         struct rcu_head fu_rcuhead;
  6.     } f_u;
  7.     struct path f_path;
  8. #define f_dentry f_path.dentry
  9. #define f_vfsmnt f_path.mnt
  10.     const struct file_operations *f_op;
  11.     spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
  12.     atomic_long_t f_count;
  13.     unsigned int f_flags;
  14.     fmode_t f_mode;
  15.     loff_t f_pos;
  16.     struct fown_struct f_owner;
  17.     const struct cred *f_cred;
  18.     struct file_ra_state f_ra;

  19.     u64 f_version;
  20. #ifdef CONFIG_SECURITY
  21.     void *f_security;
  22. #endif
  23.     /* needed for tty driver, and maybe others */
  24.     void *private_data;

  25. #ifdef CONFIG_EPOLL
  26.     /* Used by fs/eventpoll.c to link all the hooks to this file */
  27.     struct list_head f_ep_links;
  28. #endif /* #ifdef CONFIG_EPOLL */
  29.     struct address_space *f_mapping;
  30. #ifdef CONFIG_DEBUG_WRITECOUNT
  31.     unsigned long f_mnt_write_state;
  32. #endif
  33. }
复制代码
其它Field可以先不考虑,但是struct path f_path这项得关注。

他的定义如下
  1. struct path {
  2.     struct vfsmount *mnt;
  3.     struct dentry *dentry;
  4. };
复制代码
为什么要提这个呢,因为他包含了一个dentry的指针,而dentry又有inode的指针。

这样有和早期MinixFS的实现基本对应上了,早期MinixFS的文件结构中直接放的inode指针。其实就是换汤不换药。这样对以后抽象出来VFS很关键的。

论坛徽章:
0
5 [报告]
发表于 2010-08-17 20:31 |只看该作者
本帖最后由 mtloveft 于 2010-08-24 19:23 编辑

明明白白我的心--fs series(5)

文章地址:http://blog.chinaunix.net/u3/114767/showart_2300161.html

根据minix和ext2文件系统结构知识我们可以抽象出以下概念。
对文件操作最终会转化为对inode得操作,因为inode才知道数据放置什么位置,
目录也是文件,是特殊的文件,他的inode对应的数据内容是目录数据的集合。
也就是dentry,通过dentry就可以知道子目录和子文件的名称和对应的inode了。
而inode又被super block来管理,super block 可以知道还有多少inode没被使用,同时可以分配inode,销毁inode.
只要知道了root inode ,文件系统下的所有文件和目录都可以顺着root inode找到。
所以现在版本的linux kernel 就是按照这么个逻辑抽象出来了几个数据结构。
file_system_type  :文件系统
super_block          :超级块
inode                    :i节点
dentry                   :目录项
file                         :文件
早期的linux 只有一个文件系统,当然也就无文件系统下再安装文件系统的概念了。
而现在版本linux都可以在文件系统下再安装文件系统。也就是mount命令。
这就出现了有一个概念,vfsmount, 为什么会有这个数据结构,
其实就是为了管理安装了的文件系统,file_system_type只是定义了文件系统,
每个安装的文件系统可以看作是file_system_type的instance。
先来看看整体概念图

俺的系统中,EA有时候简体中文会乱码。只能用日文的。NND。
这样文件系统的结构定义不用说你也知道他怎么定义的啦,
上定义:
  1. struct file_system_type {
  2.     const char *name;
  3.     int        fs_flags;
  4.     int  (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *);
  5.     void (*kill_sb) (struct super_block *);
  6.     struct module           *owner;
  7.     struct file_system_type *next;
  8.     struct list_head        fs_supers;

  9.     struct lock_class_key   s_lock_key;
  10.     struct lock_class_key   s_umount_key;

  11.     struct lock_class_key   i_lock_key;
  12.     struct lock_class_key   i_mutex_key;
  13.     struct lock_class_key   i_mutex_dir_key;
  14.     struct lock_class_key   i_alloc_sem_key;
  15. };
复制代码
稍微解释一下,
get_sb, kill_sb当然就是为了得到和销毁super block 了。name是unique的,因为文件系统可以mount多次,所以,
对于一个文件系统,要管理n个super block,所以这些super block 就被fs_supers这个链表链接起来,方便查找。
Linux系统中有多个文件系统,为了对文件系统的管理,注册文件系统时,把所有的文件系统都链接到file_systems
这个结构上,通过next连接的。其他字段可以先不用考虑,影响不大。
结构关系图如下

下面说说文件系统注册,
为了使用文件系统,必须要进行文件系统注册。注册的过程比较简单,就是把
定义的file_system_type结构链接到file_systems上。
根据name 到file_systems上查找,没找到的话,把file_system_type结构加入到file_systems这个所谓的链上,
当然找到了的话就说明是重复注册了。
注册的代码如下
  1. int register_filesystem(struct file_system_type * fs)
  2. {
  3.     int res = 0;
  4.     struct file_system_type ** p;

  5.     BUG_ON(strchr(fs->name, '.'));
  6.     if (fs->next)
  7.         return -EBUSY;
  8.     INIT_LIST_HEAD(&fs->fs_supers);
  9.     write_lock(&file_systems_lock);
  10.     p = find_filesystem(fs->name, strlen(fs->name));
  11.     if (*p)
  12.         res = -EBUSY;
  13.     else
  14.         *p = fs;
  15.     write_unlock(&file_systems_lock);
  16.     return res;
  17. }
复制代码
find_filesystem的代码如下,比较简单,不废话了。
  1. static struct file_system_type **find_filesystem(const char *name, unsigned len)
  2. {
  3.     struct file_system_type **p;
  4.     for (p=&file_systems; *p; p=&(*p)->next)
  5.         if (strlen((*p)->name) == len &&
  6.             strncmp((*p)->name, name, len) == 0)
  7.             break;
  8.     return p;
  9. }
复制代码
注销文件系统的代码就更简单了。就不贴出来了。

论坛徽章:
0
6 [报告]
发表于 2010-08-24 19:19 |只看该作者
明明白白我的心--fs series

文章地址


明明白白我的心--fs series(1)   : http://blog.chinaunix.net/u3/114767/showart_2292149.html
明明白白我的心--fs series(2)   : http://blog.chinaunix.net/u3/114767/showart_2292171.html
明明白白我的心--fs series(3)   : http://blog.chinaunix.net/u3/114767/showart_2292187.html
明明白白我的心--fs series(4)   : http://blog.chinaunix.net/u3/114767/showart_2292196.html
明明白白我的心--fs series(5)   : http://blog.chinaunix.net/u3/114767/showart_2300161.html
明明白白我的心--fs series(6)   : http://blog.chinaunix.net/u3/114767/showart_2300171.html
明明白白我的心--fs series(7)   : http://blog.chinaunix.net/u3/114767/showart_2300174.html
明明白白我的心--fs series( 8 ) : http://blog.chinaunix.net/u3/114767/showart_2300176.html
明明白白我的心--fs series(9)   : http://blog.chinaunix.net/u3/114767/showart_2300215.html
明明白白我的心--fs series(10) : http://blog.chinaunix.net/u3/114767/showart_2301357.html
明明白白我的心--fs series(11) : http://blog.chinaunix.net/u3/114767/showart_2306935.html
明明白白我的心--fs series(12) : http://blog.chinaunix.net/u3/114767/showart_2306955.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP