【linux内核】结构体address_space_operations接口分析

结构体address_space_operations接口分析

 

struct address_space_operations {
	int (*writepage)(struct page *page, struct writeback_control *wbc);
	int (*readpage)(struct file *, struct page *);

	/* Write back some dirty pages from this mapping. */
	int (*writepages)(struct address_space *, struct writeback_control *);

	/* Set a page dirty.  Return true if this dirtied it */
	int (*set_page_dirty)(struct page *page);

	/*
	 * Reads in the requested pages. Unlike ->readpage(), this is
	 * PURELY used for read-ahead!.
	 */
	int (*readpages)(struct file *filp, struct address_space *mapping,
			struct list_head *pages, unsigned nr_pages);
	void (*readahead)(struct readahead_control *);

	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);

	/* Unfortunately this kludge is needed for FIBMAP. Don't use it */
	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);
	/*
	 * migrate the contents of a page to the specified target. If
	 * migrate_mode is MIGRATE_ASYNC, it must not block.
	 */
	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 *);

	/* swapfile support */
	int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
				sector_t *span);
	void (*swap_deactivate)(struct file *file);
};

cephfs内核客户蹲会接接口:

const struct address_space_operations ceph_aops = {
	.readpage = ceph_readpage,
	.readpages = ceph_readpages,
	.writepage = ceph_writepage,
	.writepages = ceph_writepages_start,
	.write_begin = ceph_write_begin,
	.write_end = ceph_write_end,
	.set_page_dirty = ceph_set_page_dirty,
	.invalidatepage = ceph_invalidatepage,
	.releasepage = ceph_releasepage,
	.direct_IO = ceph_direct_io,
};

  • writepage:将Page写回磁盘。
  • readpage: 从磁盘读取Page。
  • writepages: 写多个Page至磁盘。
  • set_page_dirty:设置某个Page为脏页。
  • readpages: 读取多个Page, 一般用来预读。
  • write_begin: 准备一个写操作。
  • write_end: 完成一个写操作。
  • invalidatepage:使该Page无效。
  • releasepage:释放Page。
  • direct_IO:对address_space中的所有Page进行DIO。

 

write_begin、write_end

以最常见的:

write(fd, buf, len)

为例(非 O_DIRECT):

sys_write
 └─ vfs_write
    └─ new_sync_write
       └─ file->f_op->write_iter
          └─ generic_file_write_iter
             └─ generic_perform_write
                ├─ write_begin   ← ★ 这里触发
                ├─ 拷贝用户数据到 page cache
                └─ write_end     ← ★ 这里触发

👉 真正触发点在 generic_perform_write()

 

set_page_dirty 触发时机:只要内核认为“这个 page 的内容已经被修改、需要回写”,就会触发 set_page_dirty(),而且 90% 的情况发生在:write_end() 之后。

典型路径:

write(fd)
 └─ generic_file_write_iter
    └─ generic_perform_write
       ├─ write_begin
       ├─ copy_from_iter   ← 数据真正被修改
       └─ write_end
          └─ set_page_dirty(page)   ← ★

为什么必须在 write_end?

  • write_begin:还没改数据
  • copy_from_iter:改了 page 内容
  • write_end:确认改成功 → 标脏

📌 这是 page cache 写的“唯一合法点”。

posted @ 2025-12-16 10:09  苏格拉底的落泪  阅读(7)  评论(0)    收藏  举报