open() / read() 関数の処理は O_DIRECT フラグを設定した場合を除いてページキャッシュというレイヤーに依存しています。
紛らわしいですがページキャッシュ内では inode オブジェクトのことをオーナー(所有者)と呼びます。
基本やってることは、
ですね。
例えば inode と inode 内のインデックス(添字)から検索する機能ですね。
このページキャッシュで最も重要なオブジェクトが struct address_space です。
struct address_space は inode オブジェクトのメンバーです。
// /usr/src/linux-headers-4.18.16-041816-generic/include/linux/fs.h 572 struct inode { 586 struct address_space *i_mapping;
キャッシュ内の複数のページが同じ inode を参照し、と同時に address_space とリンクされることができます。
まあこの辺は inode と address_space 構造体のメンバーが相互にリンクをはっているので明らかだと思います。
そして address_space はページ記述子( page )のメンバーでもあります。
// /usr/src/linux-headers-4.18.16-041816-generic/include/linux/mm_types.h 70 struct page { 88 struct address_space *mapping; 89 pgoff_t index; /* Our offset within mapping. */
mapping はページを所有する inode の struct address_space を指します。
index はオーナー( inode )のディスクイメージ内の位置、またはページ内のオフセットです。
次は address_space を見てみましょう。
// /usr/src/linux-headers-4.18.16-041816-generic/include/linux/fs.h 394 struct address_space { 395 struct inode *host; /* owner: inode, block_device */ 396 struct radix_tree_root i_pages; /* cached pages */ 397 atomic_t i_mmap_writable;/* count VM_SHARED mappings */ 398 struct rb_root_cached i_mmap; /* tree of private and shared mappings */ 399 struct rw_semaphore i_mmap_rwsem; /* protect tree, count, list */ 400 /* Protected by the i_pages lock */ 401 unsigned long nrpages; /* number of total pages */ 402 /* number of shadow or DAX exceptional entries */ 403 unsigned long nrexceptional; 404 pgoff_t writeback_index;/* writeback starts here */ 405 const struct address_space_operations *a_ops; /* methods */ 406 unsigned long flags; /* error bits */ 407 spinlock_t private_lock; /* for use by the address_space */ 408 gfp_t gfp_mask; /* implicit gfp mask for allocations */ 409 struct list_head private_list; /* for use by the address_space */ 410 void *private_data; /* ditto */ 411 errseq_t wb_err; 412 } __attribute__((aligned(sizeof(long)))) __randomize_layout;
この中で特に重要な行は以下です。
396 struct radix_tree_root i_pages; /* cached pages */ 398 struct rb_root_cached i_mmap; /* tree of private and shared mappings */
i_pages は基数木で整理されたページ記述子( struct page )とマップします。
i_pages は「 page_tree 」から変更されたようです。昔のマニュアルや書籍を見ると page_tree となってるものが多いですね。
rb_root_cached は赤黒木 ( red-black tree) ですね。
てなことで i_mmap には vm_area_struct がマップされます。
address_space の強さというのは inode オブジェクトへのポインターと、前述した page と file と inode オブジェクトと(メンバーポインターにより)リンクされている点ですかね。
まあページの読み書きにキャッシュを使うのは OS やコンピューターのアーキテクチャーからすれば至極当然なので、驚きはないでしょうがね。
ちなみに address_space に何らかの操作をするなら address_space_operations オブジェクト内の関数ポインターを見ると良いでしょう。
334 struct address_space_operations { 335 int (*writepage)(struct page *page, struct writeback_control *wbc); 336 int (*readpage)(struct file *, struct page *); 337 338 /* Write back some dirty pages from this mapping. */ 339 int (*writepages)(struct address_space *, struct writeback_control *); 340 341 /* Set a page dirty. Return true if this dirtied it */ 342 int (*set_page_dirty)(struct page *page); 343 344 int (*readpages)(struct file *filp, struct address_space *mapping, 345 struct list_head *pages, unsigned nr_pages); 346 347 int (*write_begin)(struct file *, struct address_space *mapping, 348 loff_t pos, unsigned len, unsigned flags, 349 struct page **pagep, void **fsdata); 350 int (*write_end)(struct file *, struct address_space *mapping, 351 loff_t pos, unsigned len, unsigned copied, 352 struct page *page, void *fsdata); 353 354 /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ 355 sector_t (*bmap)(struct address_space *, sector_t); 356 void (*invalidatepage) (struct page *, unsigned int, unsigned int); 357 int (*releasepage) (struct page *, gfp_t); 358 void (*freepage)(struct page *); 359 ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); 360 /* 361 * migrate the contents of a page to the specified target. If 362 * migrate_mode is MIGRATE_ASYNC, it must not block. 363 */ 364 int (*migratepage) (struct address_space *, 365 struct page *, struct page *, enum migrate_mode); 366 bool (*isolate_page)(struct page *, isolate_mode_t); 367 void (*putback_page)(struct page *); 368 int (*launder_page) (struct page *); 369 int (*is_partially_uptodate) (struct page *, unsigned long, 370 unsigned long); 371 void (*is_dirty_writeback) (struct page *, bool *, bool *); 372 int (*error_remove_page)(struct address_space *, struct page *); 373 374 /* swapfile support */ 375 int (*swap_activate)(struct swap_info_struct *sis, struct file *file, 376 sector_t *span); 377 void (*swap_deactivate)(struct file *file); 378 };
wirtepages とか readpages とか明らかにページと関係する名前の関数ポインターが宣言されてますよね。
Copyright 2018-2019, by Masaki Komatsu