Linux内核文件系统-虚拟文件系统-地址空间

建议点击这里查看个人主页上的最新原文

点击这里在哔哩哔哩bilibili在线观看配套的教学视频

点击这里在哔哩哔哩bilibili在线观看配套的加餐视频(就是一些补充)

点击跳转到内核课程所有目录

一般的Linux书籍都是先讲解进程和内存相关的知识,但我想先讲解文件系统。第一,因为我就是做文件系统的,更擅长这一块,其他模块的内容我还要再去好好看看书,毕竟不能误人子弟嘛;第二,是因为文件系统模块更接近于用户态,是相对比较好理解的内容(当然想深入还是要下大功夫的),由文件系统入手比较适合初学者。

虚拟文件系统英文全称Virtual file system,缩写为VFS,又称为虚拟文件切换系统(virtual filesystem switch)。所有的文件系统都要先经过虚拟文件系统层,虚拟文件系统相当于制定了一套规则,如果你想写一个新的文件系统,只需要遵守这套规则就可以了。

VFS虽然是用C语言写的,但使用了面向对象的设计思路。

磁盘块可能不连续和动态变化的,文件访问需要将文件看作一个连续的字节流,这个矛盾的解决核心在于地址空间的引入。

// 可缓存、可映射对象的内容。
struct address_space {
        struct inode            *host;            // 拥有者,可以是 inode 或 block_device。
        struct xarray           i_pages;          // 缓存的页面。
        struct rw_semaphore     invalidate_lock;  // 在无效操作期间,保护页缓存内容与文件偏移->磁盘块映射之间的一致性。它还用于阻止通过内存映射修改页缓存内容。
        gfp_t                   gfp_mask;         // 用于分配页面的内存分配标志。
        atomic_t                i_mmap_writable;  // VM_SHARED 映射的数量。
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
        /* thp 的数量,仅用于非 shmem 文件 */
        atomic_t                nr_thps;        // 页缓存中的 THP(非共享内存)数量。
#endif
        struct rb_root_cached   i_mmap;         // 私有和共享映射的树。
        unsigned long           nrpages;        // 页条目的数量,由 i_pages 锁保护。
        pgoff_t                 writeback_index;// 写回从这里开始。
        const struct address_space_operations *a_ops; // 方法。
        unsigned long           flags;          // 错误位和标志(AS_*)。
        struct rw_semaphore     i_mmap_rwsem;   // 保护 @i_mmap 和 @i_mmap_writable
        errseq_t                wb_err;         // 最近发生的错误。
        spinlock_t              private_lock;   // 供 address_space 的拥有者使用。
        struct list_head        private_list;   // 供 address_space 的拥有者使用。
        void                    *private_data;  // 供 address_space 的拥有者使用。
} __attribute__((aligned(sizeof(long)))) __randomize_layout;

地址空间操作:

struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc); // 将文件在内存page中的更新到磁盘上
        int (*read_folio)(struct file *, struct folio *); // 从磁盘上读取文件的数据到内存page中

        /* 从此映射中回写一些脏页。 */
        int (*writepages)(struct address_space *, struct writeback_control *); // 将多个page更新到磁盘上

        /* 标记一个 folio 为脏页。如果此操作使其变脏,则返回 true */
        bool (*dirty_folio)(struct address_space *, struct folio *);

        void (*readahead)(struct readahead_control *);

        int (*write_begin)(struct file *, struct address_space *mapping, // 要求具体文件系统准备将数据写到文件
                                loff_t pos, unsigned len,
                                struct page **pagep, void **fsdata);
        int (*write_end)(struct file *, struct address_space *mapping,   // 完成数据复制之后调用,具体文件系统 unlock page,释放引用计数,更新 i_size
                                loff_t pos, unsigned len, unsigned copied,
                                struct page *page, void *fsdata);

        /* 不幸的是,FIBMAP 需要这个权宜之计。不要使用它 */
        sector_t (*bmap)(struct address_space *, sector_t); // 将文件中的逻辑块扇区编号映射为对应设备上的物理块扇区编号
        void (*invalidate_folio) (struct folio *, size_t offset, size_t len); // 使某个page部分或全部失效
        bool (*release_folio)(struct folio *, gfp_t); // 日志文件系统使用,释放page
        void (*free_folio)(struct folio *folio);
        ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); // 绕过page cache
        /*
         * 将folio的内容移动到指定的目标,如果migrate_mode是MIGRATE_ASYNC,就不阻塞(异步)
         */
        int (*migrate_folio)(struct address_space *, struct folio *dst,
                        struct folio *src, enum migrate_mode);
        int (*launder_folio)(struct folio *); // 释放一个folio之前调用,回写dirty的folio
        bool (*is_partially_uptodate) (struct folio *, size_t from, // 判断是否最新
                        size_t count);
        void (*is_dirty_writeback) (struct folio *, bool *dirty, bool *wb);
        int (*error_remove_page)(struct address_space *, struct page *); // 被内存故障处理代码使用

        /* swapfile support */
        int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
                                sector_t *span);
        void (*swap_deactivate)(struct file *file);
        int (*swap_rw)(struct kiocb *iocb, struct iov_iter *iter);
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值