Linux文件系统(二)—— 文件读写

2021/12/1 7:07:35

本文主要是介绍Linux文件系统(二)—— 文件读写,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

【前言】

        文件系统是结合了众多工程师智慧的结晶,所以在这个过程中,会出现各种各样的小技术手段来解决一些实际性问题,从而产生了很多技术词汇。

【文件系统Overview】

Linux一切皆文件:普通文件、目录文件(也就是文件夹)、设备文件、链接文件、管道文件、套接字文件(数据通信的接口)等等。引入文件系统,帮助我们屏蔽底层实现的细节(不必care扇区,cache,文件管理),我们只需通过VFS提供的fs_op就可以对文件进行对应的操作。

Android 支持的文件系统:        ext4  vfat  f2fs  sdcardfs  fuse(fuse解决了文件系统必须在内核态的难题。将文件系统的实现从内核态搬到了用户态

 Android linux 文件系统核心:   VFS(1.向上提供接口,向下兼容文件系统,实现了inode/page cache等公共部分,让其他文件系统无需重复实现)

【文件系统四大对象】

1. 超级块super_block:

 struct super_block {
    struct list_head    s_list;        /* Keep this first 指向超级块链表的指针*/
    dev_t         s_dev;        /*具体文件系统的块设备描述符*/
    unsigned char s_blocksize_bits;
    unsigned long s_blocksize; /*以字节为单位的数据块的大小*/
    loff_t        s_maxbytes;    /* Max file size */
    struct file_system_type    *s_type; /*文件系统类型,每个文件系统只有一个结构体*/
    const struct super_operations    *s_op; /*指向super_block操作的函数集合*/
	alloc_inode () /*创建并初始化一个inode*/
	write_inode() /*将inode同步到磁盘*/
    sync_fs() /*同步文件系统元数据到磁盘*/      
    list_head s_inodes;  /* all inodes */
    list_head  s_inodess_dirty;  /* dirty inodes */
    void *s_fs_info;    /* Filesystem private info 具体文件系统的私有数据*/
*** }
  • 超级块用来描述整个文件系统的信息
  • 每个具体的文件系统都有自己的超级块
  • VFS超级块是各种文件系统在安装时建立的,并在卸载时被自动删除,其数据结构是super_block
  • 所有超级块对象都以双向循环链表的形式链接在一起

1.1 struct super_operations:超级块操作表

 

2. inode:index node

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;
  • 文件系统处理文件所需要的所有信息都保存在称为索引节点的inode结构体中
  • 同一个文件系统中,每个文件的索引节点号都是唯一的
  • 与索引节点关联的方法由struct inode_operations来描述
  • inode有两个设备号:i_dev(常规文件的设备号),i_rdev(某一设备的设备号)
  • LInux文件系统的另外一大特色:设备即文件 —— 驱动中设备号的来源。

2.1 struct inode_operations:index node操作函数

 

3. dentry:目录项

struct dentry {
    atomic_t d_count;                     //目录项对象使用计数器,可以有未使用态,使用态和负状态 
    unsigned int d_flags;                  //目录项标志 
    struct inode *d_inode;                 //与文件名关联的索引节点 
    struct dentry *d_parent;               //父目录的目录项对象 
    struct list_head d_hash;               //散列表表项的指针 
    struct list_head d_lru;                 //未使用链表的指针 
    struct list_head d_child;               //父目录中目录项对象的链表的指针 
    struct list_head d_subdirs;             //对目录而言,表示子目录目录项对象的链表 
    struct list_head d_alias;               //相关索引节点(别名)的链表 
    int d_mounted;                          //对于安装点而言,表示被安装文件系统根项 
    struct qstr d_name;                     //文件名 
    unsigned long d_time;         /* used by d_revalidate */ 
    struct dentry_operations *d_op;         //目录项方法 
    struct super_block *d_sb;               //文件的超级块对象 
    vunsigned long d_vfs_flags; 
    void *d_fsdata;                         //与文件系统相关的数据 
    unsigned char d_iname [DNAME_INLINE_LEN]; //存放短文件名
};
  • 存在于内存的目录项缓存,为了提高查找性能而设计,动态生成的(哈希表,或组织为一颗树,链表)。
  • 每个文件除了一个struct inode结构体外,还要一个目录项struct dentry结构,通过其d_hash域链入哈希表中
  • 不管是文件夹还是文件(目录),都属于目录项,所有的目录项在一起构成一颗庞大的目录树。
  • dentry对象有三种状态:被使用,未被使用和负状态。

3.1 struct dentry_operations

 (未完待续)

PS:

【I/O 缓冲区】

Cache:解决的是速度不同步的问题。

  • Buffer : 用于内存和硬盘的缓冲,缓冲“写”操作,保存即将要写入到磁盘上的数据。
  • Cache:一般指高速缓存,用于CPU和内存之间的缓冲,解决读的问题,保存从磁盘上读出的数据。

Buffer Cache和 Page Cache

  • buffer cache:块缓冲器,面向块设备(文件系统的块)。
  • page cache:  页缓冲器,面向虚拟内存。已映射到内存的某些物理设备(例如磁盘)上的数据,包含来自最近访问的“文件”的整个页面。在页面I / O操作(例如read()])中,内核检查数据是否驻留在page cache中。如果数据在page cache中,则内核可以快速返回请求的页面,而不必从磁盘读取数据



这篇关于Linux文件系统(二)—— 文件读写的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程