理解linux文件系统---VFS主要数据结构及之间的关系

1 VFS文件系统
 
计算机体系由三个部分组成:计算,存储,网络,体现了物体流转的三个方面。
 
生产酒也是这样的一个过程,首先是收割小麦,将小麦发酵蒸馏形成了酒(处理),然后装在瓶子里,运送到仓库。(传输),最后将所有的酒存在仓库里。(存储)
 
物理设备比如磁盘可以看作是土地,有了土地之后并不能使用,它还无法存储酒。需要在土地上建立仓库,并给每一个仓库通电,编号。这个过程可以理解为建立
文件系统的过程。文件系统建立以后就可以往里面存酒了。什么样的酒存在哪个仓库需要有管理人员记录在本子上。当然仓库在存储的时候不一定存的都是酒,也
可能存一些箱子,或者是小麦。
 
虚拟文件系统可以理解为建造仓库的标准。建造仓库的时候我们会告诉施工队,我要实现的功能有哪些,比如我希望仓库可以存储5吨的货物,仓库要有一个自动门,汽车来到验证车牌就可以放行,仓库内部的温度要保存在5度左右。只要满足这几个要求和标准即可。至于施工队用什么样的材料建造房屋。用的是铁门还是合金门,都不是使用仓库的人要考虑的。
 
而在VFS则定义了虚拟文件系统,这个东西类似于建造仓库的标准。有了标准之后,所有的文件系统都需要按照这种标准来构建文件系统。
 

 

从上图可以看到,虚拟机文件系统介于具体的文件系统和C语言标准库之间,有了VFS之后,所有按照VFS接口开发的文件系统都可以接入linux,标准的接口提供了标准

的操作,接口的设计理念一致贯穿于整个编程科学的发展。面向对象的设计理念又深化了这个理念。

 

 2 VFS关键数据结构及关系 

 

上面是虚拟文件系统的一个概览,虚拟文件系统定义了通用接口,所有具体的文件系统都必须实现这样的结构。task_struct是进程描述符,里面记录了进程的相关信息。一个进程可能操作某个文件,因此,task_struck成员内部有一个files,filtes对应files_struct里面记录了所有打开的file,file于file之间通过双向链表组织起来。
file内部包含了d_dentry,也就是目录项,通过目录项可以找到对应的inode,inode记录了文件的权限和属性。进程在操作文件的时候需要用到权限和属性,比如判断某个进程对某个文件是不是有写权限。inode里面有一个成员i_mapping,对应address_space。其中的 i_mapping域指向一个address_space结构。这样,一个文件就对应一个address_space结构, 一个 address_space与一个偏移量能够确定一个page cache 或swap cache中的一个页面。至于什么是page cache和swap cache可以
查阅相关知识。以上就是VFS组件相互之间的关系,下面看看每一个具体的组件。
 
super_block
 
是文件系统的心脏,它存储了文件系统的全局信息,如硬盘已用空间,数据块可用空间。
文件系统所有的inode信息都链接到超级块上, 如下所示是超级块的数据结构,下面节选某些关键信息。
struct super_block {
   struct list_head   s_list;       /* Keep this first */
   dev_t        s_dev;    /* search index; _not_ kdev_t */
   unsigned char     s_blocksize_bits;
   unsigned long     s_blocksize;
   loff_t       s_maxbytes;    /* Max file size */
   struct file_system_type    *s_type;
   ………..
   unsigned int      s_quota_types; /* Bitmask of supported quota types */
   struct quota_info  s_dquot;   /* Diskquota specific options */

   struct sb_writers  s_writers;
   void         *s_fs_info;    /* Filesystem private info */

   /* Granularity of c/m/atime in ns (cannot be worse than a second) */
   u32          s_time_gran;
#ifdef CONFIG_FSNOTIFY
   __u32        s_fsnotify_mask;
   struct fsnotify_mark_connector __rcu   *s_fsnotify_marks;
#endif

   char         s_id[32];  /* Informational name */
   uuid_t       s_uuid;       /* UUID */

   unsigned int      s_max_links;
   fmode_t          s_mode;
   struct mutex s_vfs_rename_mutex;   /* Kludge */
   char *s_subtype;

   const struct dentry_operations *s_d_op; /* default d_op for dentries */
   struct user_namespace *s_user_ns;
   struct list_head   s_inodes;  /* all inodes */

   spinlock_t    s_inode_wblist_lock;
   struct list_head   s_inodes_wb;   /* writeback inodes */
}
  • s_blocksize 代表文件系统的大小。
  • s_inodes     代表了所有的inode。
  • s_type   代表文件系统的类型。
Inode

代表一个具体的文件, 包含文件的大小,创建时间,文件的块大小等数据,以及对文件的读写函数,文件的读写缓存信息等。看一下inode的数据结构,这里只保留一些关键的数据信息,其他一些都去掉了。
struct inode {
    umode_t            i_mode;
    unsigned short        i_opflags;
    kuid_t            i_uid;
    kgid_t            i_gid;
    unsigned int        i_flags;
    const struct inode_operations    *i_op;
    struct super_block    *i_sb;
    struct address_space    *i_mapping;
    unsigned long        i_ino;
   {
        const unsigned int i_nlink;
        unsigned int __i_nlink;
    };

    /* Misc */
    unsigned long        i_state;
    struct rw_semaphore    i_rwsem;

    unsigned long        dirtied_when;    /* jiffies of first dirtying */
    unsigned long        dirtied_time_when;

    struct hlist_node    i_hash;
    struct list_head    i_io_list;    /* backing dev IO list */
    struct list_head    i_lru;        /* inode LRU list */
    struct list_head    i_sb_list;
    struct list_head    i_wb_list;    /* backing dev writeback list */
    const struct file_operations    *i_fop;    /* former ->i_op->default_file_ops */
    struct file_lock_context    *i_flctx;
    struct address_space    i_data;
    struct list_head    i_devices;
    union {
        struct pipe_inode_info    *i_pipe;
        struct block_device    *i_bdev;
        struct cdev        *i_cdev;
        char            *i_link;
        unsigned        i_dir_seq;
    };

    __u32            i_generation;

    void            *i_private; /* fs or device private pointer */
。。。。。。。
}
链表其实是linux中组织数据非常常用的数据结构,这个结构里面有三个链表头。
  • i_mapping是非常重要的一个结构,描述了文件地址。
  • block_device描述对应的块设备(块设备可以被看作一个文件系统来处理)。
  • inode_operations,该结构体定义了对文件的操作(如下代码所示),可以看到有获取属性,设置属性,重新命名等操作
  • i_mode,主要作用是用来区分文件类型,比如块设备,字符设备,目录, socket等。
  • super_block,指向超级块,也就是表示文件系统基本信息的数据结构。
struct inode_operations {
   struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
   const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
   int (*permission) (struct inode *, int);
   struct posix_acl * (*get_acl)(struct inode *, int);

   int (*readlink) (struct dentry *, char __user *,int);

   int (*create) (struct inode *,struct dentry *, umode_t, bool);
   int (*link) (struct dentry *,struct inode *,struct dentry *);
   int (*unlink) (struct inode *,struct dentry *);
   int (*symlink) (struct inode *,struct dentry *,const char *);
   int (*mkdir) (struct inode *,struct dentry *,umode_t);
   int (*rmdir) (struct inode *,struct dentry *);
   int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
   int (*rename) (struct inode *, struct dentry *,
         struct inode *, struct dentry *, unsigned int);
   int (*setattr) (struct dentry *, struct iattr *);
   int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
   ssize_t (*listxattr) (struct dentry *, char *, size_t);
   int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
            u64 len);
   int (*update_time)(struct inode *, struct timespec64 *, int);
   int (*atomic_open)(struct inode *, struct dentry *,
            struct file *, unsigned open_flag,
            umode_t create_mode);
   int (*tmpfile) (struct inode *, struct dentry *, umode_t);
   int (*set_acl)(struct inode *, struct posix_acl *, int);
}

dentry 

目录项对象,代表一个目录项。目录项反应了文件系统的树状结构,目前主流的操作系统基本都是用树状结构来组织文件的。linux也不例外。dentry表示一个目录项,目录项下面又有子目录。
struct dentry {
   /* RCU lookup touched fields */
   unsigned int d_flags;     /* protected by d_lock */
   seqcount_t d_seq;     /* per dentry seqlock */
   struct hlist_bl_node d_hash;   /* lookup hash list */
   struct dentry *d_parent;   /* parent directory */
   struct qstr d_name;
   struct inode *d_inode;    /* Where the name belongs to - NULL is
                * negative */
   unsigned char d_iname[DNAME_INLINE_LEN];   /* small names */

   /* Ref lookup also touches following */
   struct lockref d_lockref;  /* per-dentry lock and refcount */
   const struct dentry_operations *d_op;
   struct super_block *d_sb;  /* The root of the dentry tree */
   unsigned long d_time;     /* used by d_revalidate */
   void *d_fsdata;          /* fs-specific data */

   union {
      struct list_head d_lru;       /* LRU list */
      wait_queue_head_t *d_wait; /* in-lookup ones only */
   };
   struct list_head d_child;  /* child of parent list */
   struct list_head d_subdirs;    /* our children */
   /*
    * d_alias and d_rcu can share memory
    */
   union {
      struct hlist_node d_alias; /* inode alias list */
      struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
      struct rcu_head d_rcu;
   } d_u;
}
  • d_inode 这个成员志向inode,
  • super_block 指向对应的超级块。
  • dentry_operations 这个成员指向dentry对应的操作,如下所示
struct dentry_operations {
   int (*d_revalidate)(struct dentry *, unsigned int);
   int (*d_weak_revalidate)(struct dentry *, unsigned int);
   int (*d_hash)(const struct dentry *, struct qstr *);
   int (*d_compare)(const struct dentry *,
         unsigned int, const char *, const struct qstr *);
   int (*d_delete)(const struct dentry *);
   int (*d_init)(struct dentry *);
   void (*d_release)(struct dentry *);
   void (*d_prune)(struct dentry *);
   void (*d_iput)(struct dentry *, struct inode *);
   char *(*d_dname)(struct dentry *, char *, int);
   struct vfsmount *(*d_automount)(struct path *);
   int (*d_manage)(const struct path *, bool);
   struct dentry *(*d_real)(struct dentry *, const struct inode *);
}
File
 
文件对象,代表进程打开的文件,描述的是进程和文件之间的关系。一个文件,在不同的进程中有不同的文件对象,如下图是文件的数据结构

 从文件操作的角度来看文件系统不同结构体之间的关系。

 

文件系统的主要目的是解决用户对文件的操作,包括创建,删除,修改,存放。操作文件需要在内核中创建相对应的进程,有了进程之后,需要知道进程操作的文件是什么。那么反应进程和文件之间关系的就是file。file是实际发生操作时创建出来的对象,存储在内存里。file内部保存着文件的dentry,也就是目录项,除此之外还保存着file_operation,也就是对文件的读写,打开等操作。通过dentry还可以找到inode,那么就可以对inode执行mkdir等操作。super_block代表了一个文件系统,以及文件了解一个文件系统所需的基本数据。

 

参考资料:

   文件系统详解

《鸟哥的linux私房菜》

《深入linux内核架构》

《linux内核探秘》

 

 

 

 

 

转载于:https://www.cnblogs.com/zhouqi0505/p/10572123.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值