頁高速緩存是Linux內(nèi)核實現(xiàn)磁盤緩存,主要用來減少對磁盤的I/O操作,這么做的原因是:
- 訪問磁盤的速度遠(yuǎn)遠(yuǎn)低于訪問內(nèi)存的速度
- 臨時局部原理:數(shù)據(jù)一旦被訪問究反,就很有可能在短期內(nèi)再次被訪問到置逻。
一、緩存手段
頁高速緩存是由內(nèi)存中的物理頁面組成的涩蜘,其內(nèi)容對應(yīng)磁盤上的物理塊。頁高速緩存大小能力可以動態(tài)調(diào)整熏纯,被緩存的存儲設(shè)備稱為后備存儲同诫。
1.1 寫緩存
緩存一般有三種策略:
- 不緩存:不緩存任何寫操作
- 寫透緩存(write-through cache):寫操作將自動更新內(nèi)存緩存,同時也更新磁盤文件樟澜,緩存數(shù)據(jù)和后備存儲保持同步误窖。
- 回寫策略:Linux采用的策略,寫操作直接寫到緩存中秩贰,后備存儲不會立即更新霹俺,而是將頁高速緩存中被寫入的頁面標(biāo)記成臟,并加入到臟頁鏈表中萍膛。然后由一個回寫進(jìn)程周期將臟頁鏈表中的頁回寫到磁盤中吭服,從而使磁盤和內(nèi)存中的數(shù)據(jù)一致。最后清理臟頁標(biāo)志蝗罗。
1.2 緩存回收
Linux緩存回收是通過選擇干凈頁進(jìn)行簡單替換艇棕。如果緩存中沒有足夠的干凈頁,內(nèi)核將強(qiáng)制進(jìn)行回寫操作串塑,以騰出更多的干凈可用頁沼琉。最難的事情在于決定什么頁應(yīng)該回收,相關(guān)策略有:
- 最近最少使用(LRU):跟蹤每個頁面的訪問蹤跡(或按照訪問時間為序的頁鏈表)桩匪,以便能回收最老時間戳的頁面(或回收排序鏈表頭所指的頁面)打瘪。
- 雙鏈策略(LRU/2):維護(hù)兩個LRU鏈表,即活躍鏈表和非活躍鏈表。前者不會被換出闺骚,后者的頁面可以被換出彩扔。活躍鏈表的頁面必須在其訪問時就處于非活躍鏈表上僻爽,如果活躍鏈表對于非活躍鏈表虫碉,那么前者的頭頁面被重新放回非活躍鏈表中。
二胸梆、Linux頁高速緩存
頁高速緩存緩存的是內(nèi)存頁面敦捧。緩存中的頁來自對正規(guī)文件、塊設(shè)備文件和內(nèi)存映射文件的讀寫碰镜。
頁高速緩存中的頁可能包含多個不連續(xù)的物理磁盤塊兢卵,Linux使用address_space結(jié)構(gòu)體管理緩存項和頁I/O操作。
每個緩存文件只和一個address_space結(jié)構(gòu)體相關(guān)聯(lián):
/**
* struct address_space - Contents of a cacheable, mappable object.
* @host: Owner, either the inode or the block_device.
* @i_pages: Cached pages.
* @gfp_mask: Memory allocation flags to use for allocating pages.
* @i_mmap_writable: Number of VM_SHARED mappings.
* @nr_thps: Number of THPs in the pagecache (non-shmem only).
* @i_mmap: Tree of private and shared mappings.
* @i_mmap_rwsem: Protects @i_mmap and @i_mmap_writable.
* @nrpages: Number of page entries, protected by the i_pages lock.
* @nrexceptional: Shadow or DAX entries, protected by the i_pages lock.
* @writeback_index: Writeback starts here.
* @a_ops: Methods.
* @flags: Error bits and flags (AS_*).
* @wb_err: The most recent error which has occurred.
* @private_lock: For use by the owner of the address_space.
* @private_list: For use by the owner of the address_space.
* @private_data: For use by the owner of the address_space.
*/
struct address_space {
struct inode *host;
struct xarray i_pages;
gfp_t gfp_mask;
atomic_t i_mmap_writable;
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
/* number of thp, only for non-shmem files */
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;
物理頁中包含了address_space結(jié)構(gòu)體指針:
struct page {
unsigned long flags;//頁的狀態(tài)
atomic_t _count;//引用計數(shù)
atomic_t _mapcount;
unsigned long private;
struct address_space *mapping;
pgoff_t index;
struct list_head;
void *virtual;//頁的虛擬地址
};
三绪颖、緩沖區(qū)高速緩存
獨立的磁盤塊通過塊I/O緩沖也要被存入頁高速緩存秽荤,稱為緩沖區(qū)高速緩存。
四菠发、flusher線程
在以下情況下王滤,內(nèi)核會喚醒一個或多個flusher線程對臟頁進(jìn)行回寫:
- 當(dāng)空閑內(nèi)存低于一個閾值時,內(nèi)核必須將臟頁回寫到磁盤滓鸠,使臟頁變?yōu)楦蓛繇摚缓蟊憧梢曰厥崭蓛繇撘葬尫艃?nèi)存第喳。
- 當(dāng)臟頁在內(nèi)存中駐留時間超過閾值時糜俗,內(nèi)核必須將超時臟頁寫會磁盤,以確保臟頁不會無限期駐留在內(nèi)存中曲饱。
- 當(dāng)用戶進(jìn)程調(diào)用sync()和fsync()系統(tǒng)調(diào)用時悠抹,內(nèi)核會按要求執(zhí)行回寫動作。