内存管理-5-物理内存数据结构-4-struct address_space

基于msm-5.4

一、简介

在 Linux 内存管理里,struct address_space 可以理解为“一个可缓存、可映射对象在内核中的内存视图描述符”。

最常见的对象是文件 inode,对应 inode.i_mapping。它把这几个关键维度绑在一起:
(1) 页缓存管理(哪些页在 page cache 里).
(2) 用户态 mmap 映射关系(哪些 VMA 映射了它).
(3) 回写与错误传播(脏页写回、回写错误).
(4) 文件系统回调接口(a_ops)

所以它是文件系统层和内存管理层的核心桥梁结构。是文件页缓存与 mmap 映射的总控制块,既管页,也管映射,还负责把回写错误和文件系统操作连接起来。”


二、成员介绍

struct address_space { //fs.h
    struct inode    *host;
    struct xarray    i_pages;
    gfp_t        gfp_mask;
    atomic_t    i_mmap_writable;
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
    atomic_t        nr_thps;
#endif
    struct rb_root_cached    i_mmap;
    struct rw_semaphore    i_mmap_rwsem;
    unsigned long        nrpages;
    unsigned long        nrexceptional;
    pgoff_t            writeback_index;
    const struct address_space_operations *a_ops;
    unsigned long        flags;
    errseq_t        wb_err;
    spinlock_t        private_lock;
    struct list_head    private_list;
    void            *private_data;
} __attribute__((aligned(sizeof(long)))) __randomize_layout;

成员介绍:

host:
该 mapping 的拥有者,通常是 inode,也可能是 block_device。作用是让 VM 从 mapping 回到“上层对象”,例如拿到 inode 属性、超级块信息等。

i_pages:
页缓存容器。里面存的是普通 page cache 页,或 exceptional entry(例如 shadow 条目、DAX 特殊条目)。作用是按页索引快速查找缓存页,是 read/write/mmap 缓存命中的核心数据结构。

gfp_mask:
这个 mapping 分配页缓存页时允许使用的内存分配标志。用于约束分配行为,例如是否允许进入文件系统回收路径,避免递归死锁等。

i_mmap_writable:
可写共享映射计数(VM_SHARED 且可写相关语义)。用于判断该文件是否存在可写共享映射,支持“禁止新增可写映射”等控制逻辑(例如写保护相关场景).

nr_thps:
该 mapping 中 THP 页缓存计数(仅特定配置下存在)。用于统计与策略判断,主要给只读文件 THP 场景使用。

i_mmap:
映射该文件的 VMA 区间树(红黑树缓存根)。作用是当页失效、截断、回收、写保护变化时,内核可快速找到受影响的用户映射并进行页表级处理。

i_mmap_rwsem:
保护 i_mmap 和 i_mmap_writable 的读写信号量。用于并发控制,确保 mmap 建立/拆除与遍历映射关系时一致性。

nrpages:
当前 mapping 中“普通 page cache 页条目数”。用于快速统计缓存规模,供回收和写回路径参考。

nrexceptional:
当前 mapping 中 exceptional entry 数量。典型包含:shadow entries(回收后留下的工作集提示)、DAX 相关条目。用于帮助内核区分“真实页缓存页”和“特殊占位条目”。

writeback_index:
写回扫描起始位置(页索引)。用于回写时从这个位置继续推进,避免每次都从头扫描,提高大文件回写公平性和效率。

a_ops:
address_space_operations 回调函数表。用于告诉 VM “这个 mapping 的页该如何读、写、失效、迁移、直接 IO”等。典型函数包括 readpage、writepage、writepages、write_begin、write_end、invalidatepage、releasepage、migratepage、swap_activate 等。

flags:
mapping 状态位集合。常见语义:
(1) 异步回写错误标记(如 EIO、ENOSPC 的历史兼容位).
(2) 是否不可回收(unevictable).
(3) 是否正在退出(exiting).
(4) 是否使用写回标签等策略位.

wb_err:
基于 errseq 的回写错误序列状态。用于记录最近一次写回错误。让 fsync 等接口按“采样点之后是否出错”语义向用户态报告错误,这是现代内核报告写回错误的关键机制。

private_lock:
留给 mapping 拥有者使用的私有自旋锁。用于保护 private_list 和 private_data,具体语义由具体文件系统或子系统定义。

private_list:
留给拥有者挂接私有链表节点的链表头。用于扩展,常用于文件系统自己的脏元数据、缓冲头或其他关联对象的管理。

private_data:
留给拥有者的私有指针。也是扩展点,指向文件系统或设备自定义上下文。

 

三、struct address_space_operations

1. 结构体描述

struct address_space_operations { //fs.h
    int (*writepage)(struct page *page, struct writeback_control *wbc);
    int (*readpage)(struct file *, struct page *);
    int (*writepages)(struct address_space *, struct writeback_control *);
    int (*set_page_dirty)(struct page *page);
    int (*readpages)(struct file *filp, struct address_space *mapping,
                struct list_head *pages, unsigned nr_pages);
    int (*write_begin)(struct file *, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned flags,
                struct page **pagep, void **fsdata);
    int (*write_end)(struct file *, struct address_space *mapping,
                loff_t pos, unsigned len, unsigned copied,
                struct page *page, void *fsdata);
    sector_t (*bmap)(struct address_space *, sector_t);
    void (*invalidatepage) (struct page *, unsigned int, unsigned int);
    int (*releasepage) (struct page *, gfp_t);
    void (*freepage)(struct page *);
    ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter);
    int (*migratepage) (struct address_space *,
                struct page *, struct page *, enum migrate_mode);
    bool (*isolate_page)(struct page *, isolate_mode_t);
    void (*putback_page)(struct page *);
    int (*launder_page) (struct page *);
    int (*is_partially_uptodate) (struct page *, unsigned long, unsigned long);
    void (*is_dirty_writeback) (struct page *, bool *, bool *);
    int (*error_remove_page)(struct address_space *, struct page *);
    int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
                sector_t *span);
    void (*swap_deactivate)(struct file *file);
};

address_space_operations 是文件系统提供给 VM 的“页缓存操作接口表”。VM 不关心你是 ext4、xfs 还是其他文件系统,它只通过这组回调完成:
(1) 把页读进 page cache.
(2) 把脏页写回存储.
(3) 处理截断、回收、迁移.
(4) 支持 swapfile 激活与停用.
可以把它看成:VM 到具体文件系统的数据面适配层。

这里按“读路径、写路径、回收迁移、swap 支持”分组,逐个解释它们的职责和典型调用场景。


2. 写回相关回调

(1) writepage(page, wbc)
含义:回写单个脏页。
场景:回收脏页、后台回写线程扫描到脏页。
要点:常见返回0;有时可返回 AOP_WRITEPAGE_ACTIVATE,提示 VM 把页重新激活而不是继续回收。

(2) writepages(mapping, wbc)
含义:批量回写该 mapping 的脏页。
场景:sync、fsync、后台脏页回写、内存回收触发集中写回。
要点:通常比逐页 writepage 更高效,可按文件系统策略聚合IO。

(3) set_page_dirty(page)
含义:把页标脏(并维护文件系统所需的脏状态)。
场景:页内容被修改后。
要点:返回值表示这次是否真的把页从“非脏”变成“脏”。


3. 读取与预读回调

(1) readpage(file, page)
含义:把一个页从后备存储读入。
场景:缺页或缓存未命中。
要点:需要正确设置页的 uptodate、错误状态,并解锁页。

(2) readpages(file, mapping, pages, nr_pages)
含义:批量预读。
场景:readahead。
要点:和 readpage 不同,它是“预取优化接口”,目标是提高顺序读吞吐。


4. buffered write回调

(1) write_begin(file, mapping, pos, len, flags, pagep, fsdata)
含义:开始一次 buffered write,准备目标页。
场景:用户写文件走 page cache 路径时。
要点:负责拿到并锁定页、处理块映射/空间预留等前置动作。

(2) write_end(file, mapping, pos, len, copied, page, fsdata)
含义:结束一次 buffered write。
场景:拷贝数据到页之后。
要点:更新脏状态、i_size、元数据等;返回实际写入字节数或错误。

这两个是 buffered write 路径最核心的一对回调。


5. 块映射与页生命周期回调

(1) bmap(mapping, block)
含义:把文件逻辑块映射到设备物理块(历史接口)。
场景:主要给旧接口如 FIBMAP。
要点:现代路径使用减少,但仍可能被实现。

(2) invalidatepage(page, offset, length)
含义:页局部或全部失效时,释放对应私有状态。
场景:truncate、hole punch、失效页缓存。
要点:常见用于释放 buffer_head 等附属结构。

(3) releasepage(page, gfp)
含义:回收器想释放该页时,询问文件系统能否释放其私有数据。
场景:内存回收。
要点:返回 1 表示已释放可继续回收,返回 0 表示当前不能释放。

(4) freepage(page)
含义:页即将被释放时的最终清理钩子。
场景:页从缓存移除并真正释放。
要点:清理文件系统在页上的残留私有资源。


6. 直接IO与迁移回调

(1) direct_IO(iocb, iter)
含义:绕过 page cache 的直接 IO。
场景:O_DIRECT。
要点:由文件系统自行处理对齐、块映射和数据传输。

(2) migratepage(mapping, newpage, oldpage, mode)
含义:页面迁移时搬运页内容及其私有状态。
场景:NUMA 迁移、内存压缩/整理、内存热迁移。
要点:异步迁移模式下不能随意阻塞。

(3) isolate_page(page, isolate_mode) / putback_page(page)
含义:配合文件系统管理的特殊页隔离与放回。
场景:特定回收或迁移策略。
要点:不是所有文件系统都实现。

(4) launder_page(page)
含义:在回收前“清洗”页(典型是确保脏状态处理完)。
场景:回收路径需要更强保证时。
要点:可触发写回或等待。


7. 页状态判断与错误处理回调

(1) is_partially_uptodate(page, from, count)
含义:页是否“部分有效”。
场景:子页粒度有效性判断(某些文件系统或网络文件系统场景)。
要点:优化部分读取和一致性判断。

(2) is_dirty_writeback(page, dirty, writeback)
含义:查询页的脏/回写状态(含文件系统私有状态)。
场景:VM 在通用标志之外需要 FS 辅助判断时。
要点:帮助 VM 决策回收与等待行为。

(3) error_remove_page(mapping, page)
含义:在错误场景下从缓存移除页。
场景:IO错误恢复、数据一致性异常处理。
要点:让文件系统介入决定如何安全移除或清理该页。


9. swapfile支持回调

(1) swap_activate(sis, file, span)
含义:把普通文件激活为 swapfile。
场景:swapon 指向文件时。
要点:建立文件逻辑页到可交换后备块的映射关系,并返回可用跨度信息。

(2) swap_deactivate(file)
含义:停用 swapfile。
场景:swapoff 时。
要点:清理激活期间建立的文件系统侧状态。


如果你读某个文件系统实现,按这个顺序最容易抓主干:先看 write_begin/write_end, 确认 buffered write 语义; 再看 readpage/readpages 确认读入和预读行为; 再看 writepage/writepages 确认回写策略; 最后看 invalidatepage/releasepage/migratepage 确认回收与迁移兼容性。

 

posted on 2026-04-02 17:27  Hello-World3  阅读(2)  评论(0)    收藏  举报

导航