当前位置:   article > 正文

深入linux文件系统--VFS主要数据结构及之间的关系_linux i_mapping

linux i_mapping

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信息都链接到超级块上, 如下所示是超级块的数据结构,下面节选某些关键信息。

  1. struct super_block {
  2. struct list_head s_list; /* Keep this first */
  3. dev_t s_dev; /* search index; _not_ kdev_t */
  4. unsigned char s_blocksize_bits;
  5. unsigned long s_blocksize;
  6. loff_t s_maxbytes; /* Max file size */
  7. struct file_system_type *s_type;
  8. ………..
  9. unsigned int s_quota_types; /* Bitmask of supported quota types */
  10. struct quota_info s_dquot; /* Diskquota specific options */
  11. struct sb_writers s_writers;
  12. void *s_fs_info; /* Filesystem private info */
  13. /* Granularity of c/m/atime in ns (cannot be worse than a second) */
  14. u32 s_time_gran;
  15. #ifdef CONFIG_FSNOTIFY
  16. __u32 s_fsnotify_mask;
  17. struct fsnotify_mark_connector __rcu *s_fsnotify_marks;
  18. #endif
  19. char s_id[32]; /* Informational name */
  20. uuid_t s_uuid; /* UUID */
  21. unsigned int s_max_links;
  22. fmode_t s_mode;
  23. struct mutex s_vfs_rename_mutex; /* Kludge */
  24. char *s_subtype;
  25. const struct dentry_operations *s_d_op; /* default d_op for dentries */
  26. struct user_namespace *s_user_ns;
  27. struct list_head s_inodes; /* all inodes */
  28. spinlock_t s_inode_wblist_lock;
  29. struct list_head s_inodes_wb; /* writeback inodes */
  30. }

s_blocksize 代表文件系统的大小。

s_inodes 代表了所有的inode。

s_type 代表文件系统的类型。

Inode

代表一个具体的文件, 包含文件的大小,创建时间,文件的块大小等数据,以及对文件的读写函数,文件的读写缓存信息等。看一下inode的数据结构,这里只保留一些关键的数据信息,其他一些都去掉了。

  1. struct inode {
  2. umode_t i_mode;
  3. unsigned short i_opflags;
  4. kuid_t i_uid;
  5. kgid_t i_gid;
  6. unsigned int i_flags;
  7. const struct inode_operations *i_op;
  8. struct super_block *i_sb;
  9. struct address_space *i_mapping;
  10. unsigned long i_ino;
  11. {
  12. const unsigned int i_nlink;
  13. unsigned int __i_nlink;
  14. };
  15. /* Misc */
  16. unsigned long i_state;
  17. struct rw_semaphore i_rwsem;
  18. unsigned long dirtied_when; /* jiffies of first dirtying */
  19. unsigned long dirtied_time_when;
  20. struct hlist_node i_hash;
  21. struct list_head i_io_list; /* backing dev IO list */
  22. struct list_head i_lru; /* inode LRU list */
  23. struct list_head i_sb_list;
  24. struct list_head i_wb_list; /* backing dev writeback list */
  25. const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
  26. struct file_lock_context *i_flctx;
  27. struct address_space i_data;
  28. struct list_head i_devices;
  29. union {
  30. struct pipe_inode_info *i_pipe;
  31. struct block_device *i_bdev;
  32. struct cdev *i_cdev;
  33. char *i_link;
  34. unsigned i_dir_seq;
  35. };
  36. __u32 i_generation;
  37. void *i_private; /* fs or device private pointer */
  38. 。。。。。。。
  39. }

链表其实是linux中组织数据非常常用的数据结构,这个结构里面有三个链表头。

i_mapping是非常重要的一个结构,描述了文件地址。

block_device描述对应的块设备(块设备可以被看作一个文件系统来处理)。

inode_operations,该结构体定义了对文件的操作(如下代码所示),可以看到有获取属性,设置属性,重新命名等操作

i_mode,主要作用是用来区分文件类型,比如块设备,字符设备,目录, socket等。

super_block,指向超级块,也就是表示文件系统基本信息的数据结构。

  1. struct inode_operations {
  2. struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
  3. const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
  4. int (*permission) (struct inode *, int);
  5. struct posix_acl * (*get_acl)(struct inode *, int);
  6. int (*readlink) (struct dentry *, char __user *,int);
  7. int (*create) (struct inode *,struct dentry *, umode_t, bool);
  8. int (*link) (struct dentry *,struct inode *,struct dentry *);
  9. int (*unlink) (struct inode *,struct dentry *);
  10. int (*symlink) (struct inode *,struct dentry *,const char *);
  11. int (*mkdir) (struct inode *,struct dentry *,umode_t);
  12. int (*rmdir) (struct inode *,struct dentry *);
  13. int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
  14. int (*rename) (struct inode *, struct dentry *,
  15. struct inode *, struct dentry *, unsigned int);
  16. int (*setattr) (struct dentry *, struct iattr *);
  17. int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
  18. ssize_t (*listxattr) (struct dentry *, char *, size_t);
  19. int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
  20. u64 len);
  21. int (*update_time)(struct inode *, struct timespec64 *, int);
  22. int (*atomic_open)(struct inode *, struct dentry *,
  23. struct file *, unsigned open_flag,
  24. umode_t create_mode);
  25. int (*tmpfile) (struct inode *, struct dentry *, umode_t);
  26. int (*set_acl)(struct inode *, struct posix_acl *, int);
  27. }
【文章福利】小编推荐自己的Linux内核技术交流群: 【977878001】整理一些个人觉得比较好得学习书籍、视频资料!进群私聊管理领取 内核资料包(含视频教程、电子书、实战项目及代码)

内核资料直通车:Linux内核源码技术学习路线+视频教程代码资料

学习直通车:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈

dentry

目录项对象,代表一个目录项。目录项反应了文件系统的树状结构,目前主流的操作系统基本都是用树状结构来组织文件的。linux也不例外。dentry表示一个目录项,目录项下面又有子目录。

  1. struct dentry {
  2. /* RCU lookup touched fields */
  3. unsigned int d_flags; /* protected by d_lock */
  4. seqcount_t d_seq; /* per dentry seqlock */
  5. struct hlist_bl_node d_hash; /* lookup hash list */
  6. struct dentry *d_parent; /* parent directory */
  7. struct qstr d_name;
  8. struct inode *d_inode; /* Where the name belongs to - NULL is
  9. * negative */
  10. unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
  11. /* Ref lookup also touches following */
  12. struct lockref d_lockref; /* per-dentry lock and refcount */
  13. const struct dentry_operations *d_op;
  14. struct super_block *d_sb; /* The root of the dentry tree */
  15. unsigned long d_time; /* used by d_revalidate */
  16. void *d_fsdata; /* fs-specific data */
  17. union {
  18. struct list_head d_lru; /* LRU list */
  19. wait_queue_head_t *d_wait; /* in-lookup ones only */
  20. };
  21. struct list_head d_child; /* child of parent list */
  22. struct list_head d_subdirs; /* our children */
  23. /*
  24. * d_alias and d_rcu can share memory
  25. */
  26. union {
  27. struct hlist_node d_alias; /* inode alias list */
  28. struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */
  29. struct rcu_head d_rcu;
  30. } d_u;
  31. }

d_inode 这个成员志向inode,

super_block 指向对应的超级块。

dentry_operations 这个成员指向dentry对应的操作,如下所示

  1. struct dentry_operations {
  2. int (*d_revalidate)(struct dentry *, unsigned int);
  3. int (*d_weak_revalidate)(struct dentry *, unsigned int);
  4. int (*d_hash)(const struct dentry *, struct qstr *);
  5. int (*d_compare)(const struct dentry *,
  6. unsigned int, const char *, const struct qstr *);
  7. int (*d_delete)(const struct dentry *);
  8. int (*d_init)(struct dentry *);
  9. void (*d_release)(struct dentry *);
  10. void (*d_prune)(struct dentry *);
  11. void (*d_iput)(struct dentry *, struct inode *);
  12. char *(*d_dname)(struct dentry *, char *, int);
  13. struct vfsmount *(*d_automount)(struct path *);
  14. int (*d_manage)(const struct path *, bool);
  15. struct dentry *(*d_real)(struct dentry *, const struct inode *);
  16. }

File

文件对象,代表进程打开的文件,描述的是进程和文件之间的关系。一个文件,在不同的进程中有不同的文件对象,如下图是文件的数据结构

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

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

参考资料:

文件系统详解

《鸟哥的linux私房菜》

《深入linux内核架构》

《linux内核探秘》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/160938
推荐阅读
相关标签
  

闽ICP备14008679号