Linux 文件系统

参考文献:
https://blog.csdn.net/tiankong_/article/details/76904222
https://www.cnblogs.com/smartjourneys/p/7260911.html
https://www.cnblogs.com/smartjourneys/p/7260911.html
https://blog.csdn.net/mxgsgtc/article/details/58676106
https://www.linuxidc.com/Linux/2017-06/145065.htm
https://www.cnblogs.com/linghuchong0605/p/4216219.html

1.概述

在LINUX系统中有一个重要的概念:一切都是文件。 其实这是UNIX哲学的一个体现,而Linux是重写UNIX而来,所以这个概念也就传承了下来。在UNIX系统中,把一切资源都看作是文件,包括硬件设备。UNIX系统把每个硬件都看成是一个文件,通常称为设备文件,这样用户就可以用读写文件的方式实现对硬件的访问。

为了支持多种系统,并对上层应用屏蔽底层特性,linux 提供了一个抽象层:VFS。

在这里插入图片描述

2.VFS相关数据结构

2.1 super_block

(1)super_block: 超级块

超级块就是对所有文件系统的管理机构,每种文件系统都要把自己的信息挂到super_blocks这么一个全局链表上。

超级块代表了整个文件系统,超级块是文件系统的控制块,有整个文件系统信息,一个文件系统所有的inode都要连接到超级块上,可以说,一个超级块就代表了一个文件系统。

注意:一个文件系统类型下可以包括很多文件系统即很多的super_block

struct super_block
{

// 连接到系统全局的super_blocks链指针
struct list_head   s_list;/* Keep this first */

//设备标识符
dev_t s_dev;/* search index; _not_ kdev_t */

//块大小、块大小的位数,是否文件系统脏,最大文件大小。
unsignedlong s_blocksize;
unsignedlong s_old_blocksize;
unsignedchar s_blocksize_bits;
unsignedchar s_dirt;


unsignedlonglong s_maxbytes;  /* Max file size */
struct file_system_type *s_type;   // 所表示的文件系统的类型

// 超级块内的指向根目录的dentry结构体
struct dentry *s_root;

// 文件相关操作函数集合表
struct super_operations *s_op;

//文件系统的配额操作函数集合,文件系统的配额控制操作函数集合,网络文件系统的导出操作函数集合。
struct dquot_operations *dq_op;//
struct quotactl_ops *s_qcop;//
struct export_operations *s_export_op;
unsignedlong s_flags;//
unsignedlong s_magic;//

struct rw_semaphore s_umount;//文件系统卸载时候用到的读写信号量。
struct semaphore s_lock;//
int s_count;//
int s_syncing;//
int s_need_sync_fs;//
atomic_t s_active; //
void*s_security;//
struct xattr_handler **s_xattr;//


struct list_head s_inodes;/* all inodes */// 链接文件系统的inode
struct list_head s_dirty;/* dirty inodes */
struct list_head s_io;/* parked for writeback */
struct hlist_head s_anon;/* anonymous dentries for (nfs) exporting */
struct list_head s_files;// 对于每一个打开的文件,由file对象来表示。链接文件系统中file
struct block_device *s_bdev;//
struct list_head s_instances;//
struct quota_info s_dquot;/* Diskquota specific options */
int s_frozen;//
wait_queue_head_t s_wait_unfrozen;//
char s_id[32];/* Informational name */
void*s_fs_info;/* Filesystem private info */
/**
* The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned.
*/
struct semaphore s_vfs_rename_sem;/* Kludge */
/* Granuality of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
};

2.1.1 重要成员分析

(1)基本元数据

  1. long s_blocksize:块大小;
  2. long s_maxbytes:最大文件大小。
  3. char s_blocksize_bits:块大小的位数
  4. long s_magic:每一个超级块有一个唯一的魔术数标记
  5. dev_t s_dev : 对应设备标识;

(2)指针类型,用于作为某种连接的头节点或是 连接到某一链表上的指针

类型成员名称描述
struct list_heads_list连接到系统全局的super_blocks链指针。所有的super_block成员都会挂到super_blocks这么一个全局链表上
struct list_heads_inodes该文件系统上的inode链表头指针;
struct list_heads_dirty该文件系统上 打开的 脏的 inode 链表头指针
struct list_heads_io所有这个文件系统的将要写入的inode都在这个队列上。
list_heads_files打开的文件集合

(3)操作函数型

类型成员名称描述
struct super_operations*s_opsuper_block的操作函数集合。
struct dquot_operations*dq_op文件系统的配额操作函数集合
struct export_operations*s_export_op网络文件系统的导出操作函数集合

(4)同步、引用计数相关

类型成员名称描述
struct rw_semaphores_umount文件系统卸载时候用到的读写信号量。
struct mutexs_lock专用的互斥量
ints_count引用计数
ints_syncing文件系统的同步标记位

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2 inode索引节点

文件系统由子目录和文件构成。每个子目录和文件只能由唯一的inode 描述。inode 是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。

VFS inode的内容取自物理设备上的文件系统,由文件系统指定的操作函数(i_op 属性指定)填写。VFS inode只存在于内存中,可通过inode缓存访问。

inode有两种,一种是VFS的inode,一种是具体文件系统的inode。前者在内存中,后者在磁盘中。所以每次其实是将磁盘中的inode调进填充内存中的inode,这样才是算使用了磁盘文件inode。

这里说的VFS的inode

struct inode {
        struct hlist_node       i_hash;              /* 哈希表 */
        struct list_head        i_list;              /* 索引节点链表 */
        struct list_head        i_dentry;            /* 目录项链表 */
        unsigned long           i_ino;               /* 节点号 */
        atomic_t                i_count;             /* 引用记数 */
        umode_t                 i_mode;              /* 访问权限控制 */
        unsigned int            i_nlink;             /* 硬链接数 */
        uid_t                   i_uid;               /* 使用者id */
        gid_t                   i_gid;               /* 使用者id组 */
        kdev_t                  i_rdev;              /* 实设备标识符 */
        loff_t                  i_size;              /* 以字节为单位的文件大小 */
        struct timespec         i_atime;             /* 最后访问时间 */
        struct timespec         i_mtime;             /* 最后修改(modify)时间 */
        struct timespec         i_ctime;             /* 最后改变(change)时间 */
        unsigned int            i_blkbits;           /* 以位为单位的块大小 */
        unsigned long           i_blksize;           /* 以字节为单位的块大小 */
        unsigned long           i_version;           /* 版本号 */
        unsigned long           i_blocks;            /* 文件的块数 */
        unsigned short          i_bytes;             /* 使用的字节数 */
        spinlock_t              i_lock;              /* 自旋锁 */
        struct rw_semaphore     i_alloc_sem;         /* 索引节点信号量 */
        struct inode_operations *i_op;               /* 索引节点操作表 */
        struct file_operations  *i_fop;              /* 默认的索引节点操作 */
        struct super_block      *i_sb;               /* 相关的超级块 */
        struct file_lock        *i_flock;            /* 文件锁链表 */
        struct address_space    *i_mapping;          /* 相关的地址映射 */
        struct address_space    i_data;              /* 设备地址映射 */
        struct dquot            *i_dquot[MAXQUOTAS]; /* 节点的磁盘限额 */
        struct list_head        i_devices;           /* 块设备链表 */
        struct pipe_inode_info  *i_pipe;             /* 管道信息 */
        struct block_device     *i_bdev;             /* 块设备驱动 */
        unsigned long           i_dnotify_mask;      /* 目录通知掩码 */
        struct dnotify_struct   *i_dnotify;          /* 目录通知 */
        unsigned long           i_state;             /* 状态标志 */
        unsigned long           dirtied_when;        /* 首次修改时间 */
        unsigned int            i_flags;             /* 文件系统标志 */
        unsigned char           i_sock;              /* 可能是个套接字吧 */
        atomic_t                i_writecount;        /* 写者记数 */
        void                    *i_security;         /* 安全模块 */
        __u32                   i_generation;        /* 索引节点版本号 */
        union {
                void            *generic_ip;         /* 文件特殊信息 */
        } u;
};

2.2.1 主要成员

(1)基本元数据

  1. unsigned long i_ino : inode 编号
  2. uid_t i_uid : 使用者id
  3. gid_t i_gid; :使用者id组
  4. struct timespec i_atime : 最后访问时间
  5. struct timespec i_mtime :最后修改(modify)时间
  6. struct timespec i_ctime : 最后改变(change)时间
  7. unsigned int i_nlink : 硬链接数
  8. unsigned long i_blocks :文件的块数

(2)指针类型,用于作为某种连接的头节点或是 连接到某一链表上的指针

类型成员名称描述
struct list_headi_hash哈希表
struct list_headi_list索引节点链表
struct list_headi_dentry目录项链表
struct list_headi_devices块设备链表

(3)操作函数型

类型成员名称描述
struct inode_operations*i_op索引节点操作表
struct file_operations*i_fop对应文件操作表

(4)存储相关

类型成员名称描述
struct address_space*i_mapping相关的地址映射
struct address_spacei_data设备地址映射
loff_ti_size以字节为单位的文件大小
unsigned longi_blocks文件的块数

(5)同步、引用计数相关

类型成员名称描述
struct rw_semaphorei_alloc_sem索引节点信号量
ints_count引用计数
ints_syncing文件系统的同步标记位
spinlock_ti_lock自旋锁

2.3 dentry

每个文件除了一个struct inode结构体外,还要一个目录项struct dentry结构。dentry代表的逻辑意义上的文件,描述的是文件逻辑上的属性,目录项对象在磁盘上并没有对应的映像(inode代表的是物理意义上的文件,记录的是物理上的属性,对于一个具体的文件系统,其inode在磁盘上有对应的映像)

另外,一个索引节点可能对应多个目录项对象(如建立了软链的文件,多个目录项对应通过一个inode )。所以在inode结构中有一个队列i_dentry,凡是代表着同一个文件的所有目录项都通过其dentry结构中的d_alias域挂入相应inode结构中的i_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;
   };

2.3.1 主要成员

(1)基本元数据

  1. unsigned int d_flags : 目录项标志
  2. struct inode * d_inode : 与文件名关联的索引节点
  3. struct dentry * d_parent : 父目录的目录项
  4. struct super_block * d_sb : 目录项树的根 (即文件的超级块)

(2)指针类型,用于作为某种连接的头节点或是 连接到某一链表上的指针

类型成员名称描述
struct list_headd_hash目录项形成的哈希表
struct list_headd_lru未使用的 LRU 链表
struct list_headd_child父目录的子目录项所形成的链表
struct list_headd_subdirs该目录项的子目录所形成的链表

在内核中有一个哈希表dentry_hashtable ,是一个list_head的指针数组。一旦在内存中建立起一个目录节点的dentry 结构,该dentry结构就通过其d_hash域链入哈希表中的某个队列中。
内核中还有一个队列dentry_unused,凡是已经没有用户(count域为0)使用的dentry结构就通过其d_lru域挂入这个队列。
Dentry结构中除了d_alias 、d_hash、d_lru三个队列外,还有d_vfsmnt、d_child及d_subdir三个队列。其中d_vfsmnt仅在该dentry为一个安装点时才使用。另外,当该目录节点有父目录时,则其dentry结构就通过d_child挂入其父节点的d_subdirs队列中,同时又通过指针d_parent指向其父目录的dentry结构,而它自己各个子目录的dentry结构则挂在其d_subdirs域指向的队列中。
从上面的叙述可以看出,一个文件系统中所有目录项结构或组织为一个哈希表,或组织为一颗树,或按照某种需要组织为一个链表,这将为文件访问和文件路径搜索奠定下良好的基础。

(3)操作函数型

类型成员名称描述
struct dentry_operations*d_op目录项的函数集
struct file_operations*i_fop对应文件操作表

2.4 file

进程通过文件描述符来访问文件。系统中的每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码 中,struct file的指针通常被命名为file或filp。

进程会保存自己所有打开的文件,当fork子进程时,默认情况下,子进程会继承父进程中的文件描述符列表。

struct file {
       union {
           struct llist_node    fu_llist;//文件对象链表
           struct rcu_head     fu_rcuhead; //释放之后的RCU链表
       } f_u;
       struct path        f_path;
       struct inode        *f_inode;    /* cached value */
       const struct file_operations    *f_op;
   
       /*
        * Protects f_ep_links, f_flags.
        * Must not be taken from IRQ context.
        */
       spinlock_t        f_lock;
       atomic_long_t        f_count;   //文件对象的使用计数
       unsigned int         f_flags;  //当打开文件时所使用的标志
       fmode_t            f_mode;     //文件的访问模式
       struct mutex        f_pos_lock;
       loff_t            f_pos;       //文件当前的位移量
       struct fown_struct    f_owner;  //拥有者通过信号量进行异步I/O传输
       const struct cred    *f_cred;
       struct file_ra_state    f_ra;
   
       u64            f_version;
   #ifdef CONFIG_SECURITY
       void            *f_security;  //安全模块
   #endif
       /* needed for tty driver, and maybe others */
       void            *private_data;  //tty 设备驱动的钩子
   
   #ifdef CONFIG_EPOLL
       /* Used by fs/eventpoll.c to link all the hooks to this file */
       struct list_head    f_ep_links;  //事件池锁
       struct list_head    f_tfile_llink;
   #endif /* #ifdef CONFIG_EPOLL */
       struct address_space    *f_mapping;  //页缓存映射
   } __attribute__((aligned(4)));    /* lest something weird decides that 2 is OK */

2.4.1 主要成员

(1)基本元数据

  1. struct path f_path :包含dentry和mnt两个成员,用于确定文件路径
  2. atomic_t f_count :文件的引用计数(有多少进程打开该文件)
  3. unsigned int f_flags: 对应于open时指定的flag
  4. mode_t f_mode : 读写模式:open的mod_t mode参数
  5. off_t f_pos : 该文件在当前进程中的文件偏移量

(2)指针类型,用于作为某种连接的头节点或是 连接到某一链表上的指针

类型成员名称描述
struct list_headfu_list文件对象链表指针
struct rcu_headfu_rcuheadRCU(Read-Copy Update)是Linux 2.6内核中新的锁机制

(3)操作函数型

类型成员名称描述
struct file_operations**f_op与该文件相关联的操作函数
struct file_operations*i_fop对应文件操作表

(4)存储相关

类型成员名称描述
struct address_space*f_mapping页缓存映射

(5)同步、引用计数相关

类型成员名称描述
struct spinlock_tf_lock自旋锁

2.5 总结

  1. 进程task_struct中,保存了进程打开的文件列表与进程的文件系统空间(为了支持容器概念,支持资源的隔离);

  2. 对于文件,分为:打开未修改的文件(inode_in_use)、不活跃(没有打开的文件,inode_unused )、打开修改了的文件。对于前两种,相关的文件对象都链到系统全局链表中。打开修改了的文件,链到文件的super_block中的dirty 链表中,以后要刷新同步时,遍历超级块的相关链表即可。

  3. 一个文件对应于一个inode,inode中记录了文件的大小、访问属性、修改时间、映射的地址(或是对于磁盘中的inode,记录了blocks信息)。但是inode中不包含文件名、路径信息(只要文件打开了后,内核都是通过文件描述符,找到对应的file 结构,inode结构,进行操作。文件名是给用户看的)

  4. 对于一个inode结构表示的文件操作通过 i_fop 指定。不同类型的文件,该 成员的值不同。inode根据文件类型,连接到所属的super block中。

  5. super block定义了某个文件系统的总体特性,如最大的文件大小、块大小、文件系统安装目录的目录项等;

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值