多個執行緒同時從同一個檔案做很小的讀取時,資料可能早就在頁面快取裡,瓶頸卻不一定是磁碟。Linux 現有的 filemap_read() 會先替 folio 增加參照計數,複製資料後再減掉;每次讀取都得寫入同一條 struct page cache line。不同 CPU 反覆爭用這個位置,安全機制本身就成了成本。

Linus Torvalds 在 patch 說明裡指出,2024 年已有人從實際客戶工作負載提出這個問題。他在自己的 i7-8565U 筆電上,讓八個執行緒對同一頁檔案做 16-byte pread();在 Linus 的八執行緒測試裡,這條 cache line 佔了 99.92% 的 load HITM。

Linux kernel Git 摘要頁顯示 master 與 noref-filemap-read-with-llm 兩個分支,後者的提交訊息為 mm: read from the page cache without folio references。

來源:Phoronix 截圖自 git.kernel.org

八個 patch 把成本從讀取端移到釋放端

這組 noref-filemap-read-with-llm 分支共有八個 patch。核心做法是:folio 從頁面快取移除後,不立刻讓它的記憶體被重新利用,而是等一個 RCU grace period 結束再交回 allocator。讀取端因此可以在 rcu_read_lock() 範圍內直接複製頁面資料,不必先取得 folio reference。讀取端不再加減 refcount;代價轉成延後釋放記憶體。

這不是只改 filemap_read()。為了讓「RCU 期間記憶體不會被換成別的用途」成立,系列還得處理頁面被 splice 交給新擁有者、inode 正在被移除、待釋放頁面如何分批排隊,以及單一 CPU 累積太多 deferred free 時要怎麼加速 grace period。換句話說,這不是替熱路徑刪掉兩次原子操作就結束,而是把安全保證搬到另一條生命週期上。