ext2文件系统探秘之一

概述:此系列文章,主要参考《linux内核源代码情景分析》,进行相关笔记总结,剖析ext2文件系统的实现。


1.VFS与文件系统的关系

    如果把内核比作PC的母版,VFS就是上面的插槽,具体的文件系统就是上面的接口卡。其中VFS和具体操作系统之间的界面是有明确定义的,这个界面的主体是一个file_operations的数据结构,其定义在include/linux/fs.h之中。

/*
*NOTE:
*read, write, poll, fsync, readv, writev, unlocked_ioctl andcompat_ioctl
*can be called without the big kernel lock held in all filesystems.
*/
struct file_operations {
struct module *owner;
loff_t(*llseek) (struct file *, loff_t, int);
ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t(*aio_read) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
ssize_t(*aio_write) (struct kiocb *, const struct iovec *, unsigned long,loff_t);
int(*readdir) (struct file *, void *, filldir_t);
unsignedint (*poll) (struct file *, struct poll_table_struct *);
int(*ioctl) (struct inode *, struct file *, unsigned int, unsignedlong);
long(*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long(*compat_ioctl) (struct file *, unsigned int, unsigned long);
int(*mmap) (struct file *, struct vm_area_struct *);
int(*open) (struct inode *, struct file *);
int(*flush) (struct file *, fl_owner_t id);
int(*release) (struct inode *, struct file *);
int(*fsync) (struct file *, struct dentry *, int datasync);
int(*aio_fsync) (struct kiocb *, int datasync);
int(*fasync) (int, struct file *, int);
int(*lock) (struct file *, int, struct file_lock *);
ssize_t(*sendpage) (struct file *, struct page *, int, size_t, loff_t *,int);
unsignedlong (*get_unmapped_area)(struct file *, unsigned long, unsignedlong, unsigned long, unsigned long);
int(*check_flags)(int);
int(*flock) (struct file *, int, struct file_lock *);
ssize_t(*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,size_t, unsigned int);
ssize_t(*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,size_t, unsigned int);
int(*setlease)(struct file *, long, struct file_lock **);
};


          每种文件系统都有自己的file_operations数据结构,它实际上是一个函数跳转表,例如read就指向具体的文件系统实现读操作的入口函数。

     每个进程通过“打开文件”与具体的文件建立连接,或者说简历一个读写的“上下文”。这种连接是以file结构中的f_op指针(它是file_operations类型)来实现的。

     Linux内核中对fs和具体文件系统的关系划分如下:


注:其中,VFS实现的是sys_read()etc;通过file结构中的f_op指针实现的“文件系统总线”。

        进程和文件的连接是通过“打开文件”来实现的。其中,task_struct结构(include/linux/sched.h)中与文件相关的部分如下:

struct task_struct {
1331 /* filesystem information */
1332         struct fs_struct *fs;
1333 /* open file information */
1334         struct files_struct *files;
.......
}

    其中有两个指针, fs 是有关文件系统的信息; files 是有关已经打开文件的信息。其中 fs_struct 定义在 include/linux/fs_struct.h 之中,结构如下

struct fs_struct {
             atomic_t count;
             rwlock_t lock;
   9         int umask;
              struct dentry * root, * pwd, * altroot;
 11         struct vfsmount *rootmnt, * pwdmnt, *altrootmnt;
 12 }; //kernel Version


          (注意2.6.34之中的,和2.4内核已经有一些不同,而下面的文字是按照2.4解释的。)结构中有六个指针。前三个是dentry结构指针,其中dentry结构中记录着文件的各项属性,如文件名/访问权限等。pwd:当前所在目录;root:进程根目录;altroot:替换根目录。后三个指针就各自指向代表着这些“安装”的fsmount数据结构。注意,fs_struct结构中的信息和文件系统和进程相关,与具体打开的文件无关。

    与具体打开文件有关的信息在file结构中,而files_struct结构的主体就是一个file结构数组。

    每次打开一个文件,进程就用fid来访问,fid实际上就是相应file结构在数组中的下标。file结构有个指针f_op,指向对应的file_operations结构。同时,file结构中还有一个指针f_dentry,指向该文件的dentry结构。

    每个文件除了有一个dentry结构以外,还有一个inode数据结构,记载着文件哎你在存储介质上的位置和分布信息。

VFS与具体文件系统之间界面的主体是file_operation数据结构,另有dentry_operationsinode_operations.定义在include/linux/dcache.h之中。

134 struct dentry_operations {
135         int (*d_revalidate)(struct dentry *, struct nameidata *);
136         int (*d_hash) (struct dentry *, struct qstr *);
137         int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
138         int (*d_delete)(struct dentry *);
139         void (*d_release)(struct dentry *);
140         void (*d_iput)(struct dentry *, struct inode *);
141         char *(*d_dname)(struct dentry *, char *, int);
142 };

文件系统逻辑结构图如下:


linux到底支持哪些具体的文件系统呢?inode中有个成分u,是一个union,可以从定义查看linux支持的文件系统。


2.磁盘文件


    一个文件包涵了两方面的信息,一个是数据本身,另一个是组织和管理信息。对于磁盘文件,这两部分都在文件系统之中。其中,后者存在inodedentry之中,它与内存中的inode有些相似。


3.设备文件


    设备文件包涵组织和管理信息,但是不一定存储着数据;根据设备类型和性质的不同,可以是用于读写的磁盘,用于接受和发送的网络卡,用于采集和控制的一些机电设备。


4.特殊文件


    特殊文件在内存中有inodedentry但是不宜定在存储介质上有索引节点和目录项。linux上的特殊文件主要有procsocket和管道文件。

    三个不同类型的特殊文件都有一个共同点:都有一些用于组织和管理的信息。要访问一个文件的时候,需要通过它的索引才知道这种文件类型,组织方式,存储地点,下层驱动位置。(注意:我们要访问文件,是按名称存储的,具体而言,实际上我们给的是逻辑文件,需要的是物理文件)inode定义在include/linux/fs.h之中,具体结构如下

387 struct inode {
 388         struct list_head        i_hash;
 389         struct list_head        i_list;
 390         struct list_head        i_dentry;
 391 
 392         struct list_head        i_dirty_buffers;
 393 
 394         unsigned long           i_ino;
 395         atomic_t                i_count;
 396         kdev_t                  i_dev;
 397         umode_t                 i_mode;
 398         nlink_t                 i_nlink;
 399         uid_t                   i_uid;
 400         gid_t                   i_gid;
 401         kdev_t                  i_rdev;
 402         loff_t                  i_size;
 403         time_t                  i_atime;
 404         time_t                  i_mtime;
 405         time_t                  i_ctime;
 406         unsigned long           i_blksize;
 407         unsigned long           i_blocks;
 408         unsigned long           i_version;
 409         struct semaphore        i_sem;
 410         struct semaphore        i_zombie;
 411         struct inode_operations *i_op;
 412         struct file_operations  *i_fop; /* former ->i_op->default_file_ops */
 413         struct super_block      *i_sb;
 414         wait_queue_head_t       i_wait;
 415         struct file_lock        *i_flock;
 416         struct address_space    *i_mapping;
 417         struct address_space    i_data;
 418         struct dquot            *i_dquot[MAXQUOTAS];
 419         struct pipe_inode_info  *i_pipe;
 420         struct block_device     *i_bdev;
 422         unsigned long           i_dnotify_mask; /* Directory notify events */
 423         struct dnotify_struct   *i_dnotify; /* for directory notifications */
 424 
 425         unsigned long           i_state;
 426 
 427         unsigned int            i_flags;
 428         unsigned char           i_sock;
 429 
 430         atomic_t                i_writecount;
 431         unsigned int            i_attr_flags;
 432         __u32                   i_generation;
 433         union {
 434                 struct minix_inode_info         minix_i;
 435                 struct ext2_inode_info          ext2_i;
 436                 struct hpfs_inode_info          hpfs_i;
 437                 struct ntfs_inode_info          ntfs_i;
 438                 struct msdos_inode_info         msdos_i;
 439                 struct umsdos_inode_info        umsdos_i;
 440                 struct iso_inode_info           isofs_i;
 441                 struct nfs_inode_info           nfs_i;
 442                 struct sysv_inode_info          sysv_i;
 443                 struct affs_inode_info          affs_i;
 444                 struct ufs_inode_info           ufs_i;
 445                 struct efs_inode_info           efs_i;
 446                 struct romfs_inode_info         romfs_i;
 447                 struct shmem_inode_info         shmem_i;
 448                 struct coda_inode_info          coda_i;
 449                 struct smb_inode_info           smbfs_i;
 450                 struct hfs_inode_info           hfs_i;
 451                 struct adfs_inode_info          adfs_i;
 452                 struct qnx4_inode_info          qnx4_i;
 453                 struct bfs_inode_info           bfs_i;
 454                 struct udf_inode_info           udf_i;
 455                 struct ncp_inode_info           ncpfs_i;
 456                 struct proc_inode_info          proc_i;
 457                 struct socket                   socket_i;
 458                 struct usbdev_inode_info        usbdev_i;
 459                 void                            *generic_ip;
 460         } u;
 461 };


    下面,我们再来看看ext2_inode的数据结构:

242 struct ext2_inode {
243         __le16  i_mode;         /* File mode */
244         __le16  i_uid;          /* Low 16 bits of Owner Uid */
245         __le32  i_size;         /* Size in bytes */
246         __le32  i_atime;        /* Access time */
247         __le32  i_ctime;        /* Creation time */
248         __le32  i_mtime;        /* Modification time */
249         __le32  i_dtime;        /* Deletion Time */
250         __le16  i_gid;          /* Low 16 bits of Group Id */
251         __le16  i_links_count;  /* Links count */
252         __le32  i_blocks;       /* Blocks count */
253         __le32  i_flags;        /* File flags */
254         union {
255                 struct {
256                         __le32  l_i_reserved1;
257                 } linux1;
258                 struct {
259                         __le32  h_i_translator;
260                 } hurd1;
261                 struct {
262                         __le32  m_i_reserved1;
263                 } masix1;
264         } osd1;                         /* OS dependent 1 */
265         __le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
266         __le32  i_generation;   /* File version (for NFS) */
267         __le32  i_file_acl;     /* File ACL */
268         __le32  i_dir_acl;      /* Directory ACL */
269         __le32  i_faddr;        /* Fragment address */
270         union {
271                 struct {
272                         __u8    l_i_frag;       /* Fragment number */
273                         __u8    l_i_fsize;      /* Fragment size */
274                         __u16   i_pad1;
275                         __le16  l_i_uid_high;   /* these 2 fields    */
276                         __le16  l_i_gid_high;   /* were reserved2[0] */
277                         __u32   l_i_reserved2;
278                 } linux2;
279                 struct {
283                         __le16  h_i_uid_high;
284                         __le16  h_i_gid_high;
285                         __le32  h_i_author;
286                 } hurd2;
287                 struct {
288                         __u8    m_i_frag;       /* Fragment number */
289                         __u8    m_i_fsize;      /* Fragment size */
290                         __u16   m_pad1;
291                         __u32   m_i_reserved2[2];
292                 } masix2;
293         } osd2;                         /* OS dependent 2 */
294 };


   虽然inode结构包涵了文件的组织和管理信息,但是“文件名”却不在其中。要知道,文件名是存在于dentry结构之中的。下面,我们来看看ext2_dir_entry_2数据结构,它也是在ext2_fs.h中定义的。

542 struct ext2_dir_entry {
543         __le32  inode;                  /* Inode number */
544         __le16  rec_len;                /* Directory entry length */
545         __le16  name_len;               /* Name length */
546         char    name[EXT2_NAME_LEN];    /* File name */
547 };


其中,文件类型的定义为:

563 /*
564  * Ext2 directory file types.  Only the low 3 bits are used.  The
565  * other bits are reserved for now.
566  */
567 enum {
568         EXT2_FT_UNKNOWN         = 0,
569         EXT2_FT_REG_FILE        = 1,
570         EXT2_FT_DIR             = 2,
571         EXT2_FT_CHRDEV          = 3,
572         EXT2_FT_BLKDEV          = 4,
573         EXT2_FT_FIFO            = 5,
574         EXT2_FT_SOCK            = 6,
575         EXT2_FT_SYMLINK         = 7,
576         EXT2_FT_MAX
577 };

同样,我们在这里对比一下ext2_dir_entry_2dentry结构。我们看看dentry数据结构

89 struct dentry {
 90         atomic_t d_count;
 91         unsigned int d_flags;           /* protected by d_lock */
 92         spinlock_t d_lock;              /* per dentry lock */
 93         int d_mounted;
 94         struct inode *d_inode;          /* Where the name belongs to - NULL is
 95                                          * negative */
 96         /*
 97          * The next three fields are touched by __d_lookup.  Place them here
 98          * so they all fit in a cache line.
 99          */
100         struct hlist_node d_hash;       /* lookup hash list */
101         struct dentry *d_parent;        /* parent directory */
102         struct qstr d_name;
103 
104         struct list_head d_lru;         /* LRU list */
105         /*
106          * d_child and d_rcu can share memory
107          */
108         union {
109                 struct list_head d_child;       /* child of parent list */
110                 struct rcu_head d_rcu;
111         } d_u;
112         struct list_head d_subdirs;     /* our children */
113         struct list_head d_alias;       /* inode alias list */
114         unsigned long d_time;           /* used by d_revalidate */
115         const struct dentry_operations *d_op;
116         struct super_block *d_sb;       /* The root of the dentry tree */
117         void *d_fsdata;                 /* fs-specific data */
118 
119         unsigned char d_iname[DNAME_INLINE_LEN_MIN];    /* small names */
120 };


   以看出,inodedentry作为vfs层面的数据结构,和ext2_inode有很大不同,前者包涵了更多的动态信息和对后者的抽象和补充。

   这里有疑问:要找文件,需要先找到对应的目录项,而目录项又存在于目录之中,目录本身也是文件;如此进入循环查找的困境。所以,必然存在这样的一个目录,它的目录项一个固定的位置,这就是根目录。根目录的位置和文件系统的其他一些参数就记录在超级块之中。超级块在设备上的逻辑位置是固定的,总是在第二个逻辑块上(第一个是引导块)。所谓安装,就是从一个存储设备读入超级块,在内存中建立一个super_block结构,进而将设备根目录与文件系统已经存在的空白目录挂钩。

    对于普通文件,文件系统最终要调用驱动程序进行读写,就ext2文件系统而言,从磁盘文件的角度,对存储介质的访问可以涉及到四种不同的目标,那就是

1)文件中的数据

2)文件的组织和管理信息

3)磁盘的超级块(每个分区,即逻辑磁盘都有超级块)

4)引导块


     从磁盘驱动的角度看,文件查找流程如下:逻辑文件名——》索引节点——》磁盘块号和块内位置——》物理块与位置。

     前面我们提到过,接口卡和插槽的关系。,因此,file结构中的f_op就可以看作插槽中的一个触点,并且在dentry/inode等结构中都有类似的触点。除了file以外,这个插槽有很多段,有关的数据结构有:

1)文件操作跳转表,即file_operations数据结构,例如readwrite

2)目录项操作跳转表,即dentry_operation数据结构,例如hashcompare操作。

3)索引节点跳转表,即inode_opertions数据结构,例如mkdirmknod操作。

4)超级块操作跳转表,即super_operations数据结构,例如read_inode操作。

5)超级快本身因为文件系统而不同.

    由此可见,filedentryinodesuper_block已经超级块的位置约定都属于VFS层面。inode结构中还有一个指针i_fop,也指向具体的file_operations数据结构,实际上file结构中的指针f_op只是inode结构中这个指针的一个副本,在打开文件的时候从目标文件的inode结构中复制到file结构中。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值