Skip to content

Commit 6020c20

Browse files
committed
Merge tag 'folio-5.17' of git://git.infradead.org/users/willy/pagecache
Pull folio conversion updates from Matthew Wilcox: "Convert much of the page cache to use folios This stops just short of actually enabling large folios. It converts everything that I noticed needs to be converted, but there may still be places I've overlooked which still have page size assumptions. The big change here is using large entries in the page cache XArray instead of many small entries. That only affects shmem for now, but it's a pretty big change for shmem since it changes where memory needs to be allocated (at split time instead of insertion)" * tag 'folio-5.17' of git://git.infradead.org/users/willy/pagecache: (49 commits) mm: Use multi-index entries in the page cache XArray: Add xas_advance() truncate,shmem: Handle truncates that split large folios truncate: Convert invalidate_inode_pages2_range to folios fs: Convert vfs_dedupe_file_range_compare to folios mm: Remove pagevec_remove_exceptionals() mm: Convert find_lock_entries() to use a folio_batch filemap: Return only folios from find_get_entries() filemap: Convert filemap_get_read_batch() to use a folio_batch filemap: Convert filemap_read() to use a folio truncate: Add invalidate_complete_folio2() truncate: Convert invalidate_inode_pages2_range() to use a folio truncate: Skip known-truncated indices truncate,shmem: Add truncate_inode_folio() shmem: Convert part of shmem_undo_range() to use a folio mm: Add unmap_mapping_folio() truncate: Add truncate_cleanup_folio() filemap: Add filemap_release_folio() filemap: Use a folio in filemap_page_mkwrite filemap: Use a folio in filemap_map_pages ...
2 parents 81ff0be + 6b24ca4 commit 6020c20

25 files changed

+1114
-1013
lines changed

fs/f2fs/f2fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <linux/fscrypt.h>
2929
#include <linux/fsverity.h>
3030

31+
struct pagevec;
32+
3133
#ifdef CONFIG_F2FS_CHECK_FS
3234
#define f2fs_bug_on(sbi, condition) BUG_ON(condition)
3335
#else

fs/fs-writeback.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ static bool inode_do_switch_wbs(struct inode *inode,
372372
{
373373
struct address_space *mapping = inode->i_mapping;
374374
XA_STATE(xas, &mapping->i_pages, 0);
375-
struct page *page;
375+
struct folio *folio;
376376
bool switched = false;
377377

378378
spin_lock(&inode->i_lock);
@@ -389,21 +389,23 @@ static bool inode_do_switch_wbs(struct inode *inode,
389389

390390
/*
391391
* Count and transfer stats. Note that PAGECACHE_TAG_DIRTY points
392-
* to possibly dirty pages while PAGECACHE_TAG_WRITEBACK points to
393-
* pages actually under writeback.
392+
* to possibly dirty folios while PAGECACHE_TAG_WRITEBACK points to
393+
* folios actually under writeback.
394394
*/
395-
xas_for_each_marked(&xas, page, ULONG_MAX, PAGECACHE_TAG_DIRTY) {
396-
if (PageDirty(page)) {
397-
dec_wb_stat(old_wb, WB_RECLAIMABLE);
398-
inc_wb_stat(new_wb, WB_RECLAIMABLE);
395+
xas_for_each_marked(&xas, folio, ULONG_MAX, PAGECACHE_TAG_DIRTY) {
396+
if (folio_test_dirty(folio)) {
397+
long nr = folio_nr_pages(folio);
398+
wb_stat_mod(old_wb, WB_RECLAIMABLE, -nr);
399+
wb_stat_mod(new_wb, WB_RECLAIMABLE, nr);
399400
}
400401
}
401402

402403
xas_set(&xas, 0);
403-
xas_for_each_marked(&xas, page, ULONG_MAX, PAGECACHE_TAG_WRITEBACK) {
404-
WARN_ON_ONCE(!PageWriteback(page));
405-
dec_wb_stat(old_wb, WB_WRITEBACK);
406-
inc_wb_stat(new_wb, WB_WRITEBACK);
404+
xas_for_each_marked(&xas, folio, ULONG_MAX, PAGECACHE_TAG_WRITEBACK) {
405+
long nr = folio_nr_pages(folio);
406+
WARN_ON_ONCE(!folio_test_writeback(folio));
407+
wb_stat_mod(old_wb, WB_WRITEBACK, -nr);
408+
wb_stat_mod(new_wb, WB_WRITEBACK, nr);
407409
}
408410

409411
if (mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) {

fs/remap_range.c

Lines changed: 55 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -146,119 +146,113 @@ static int generic_remap_check_len(struct inode *inode_in,
146146
}
147147

148148
/* Read a page's worth of file data into the page cache. */
149-
static struct page *vfs_dedupe_get_page(struct inode *inode, loff_t offset)
149+
static struct folio *vfs_dedupe_get_folio(struct inode *inode, loff_t pos)
150150
{
151-
struct page *page;
151+
struct folio *folio;
152152

153-
page = read_mapping_page(inode->i_mapping, offset >> PAGE_SHIFT, NULL);
154-
if (IS_ERR(page))
155-
return page;
156-
if (!PageUptodate(page)) {
157-
put_page(page);
153+
folio = read_mapping_folio(inode->i_mapping, pos >> PAGE_SHIFT, NULL);
154+
if (IS_ERR(folio))
155+
return folio;
156+
if (!folio_test_uptodate(folio)) {
157+
folio_put(folio);
158158
return ERR_PTR(-EIO);
159159
}
160-
return page;
160+
return folio;
161161
}
162162

163163
/*
164-
* Lock two pages, ensuring that we lock in offset order if the pages are from
165-
* the same file.
164+
* Lock two folios, ensuring that we lock in offset order if the folios
165+
* are from the same file.
166166
*/
167-
static void vfs_lock_two_pages(struct page *page1, struct page *page2)
167+
static void vfs_lock_two_folios(struct folio *folio1, struct folio *folio2)
168168
{
169169
/* Always lock in order of increasing index. */
170-
if (page1->index > page2->index)
171-
swap(page1, page2);
170+
if (folio1->index > folio2->index)
171+
swap(folio1, folio2);
172172

173-
lock_page(page1);
174-
if (page1 != page2)
175-
lock_page(page2);
173+
folio_lock(folio1);
174+
if (folio1 != folio2)
175+
folio_lock(folio2);
176176
}
177177

178-
/* Unlock two pages, being careful not to unlock the same page twice. */
179-
static void vfs_unlock_two_pages(struct page *page1, struct page *page2)
178+
/* Unlock two folios, being careful not to unlock the same folio twice. */
179+
static void vfs_unlock_two_folios(struct folio *folio1, struct folio *folio2)
180180
{
181-
unlock_page(page1);
182-
if (page1 != page2)
183-
unlock_page(page2);
181+
folio_unlock(folio1);
182+
if (folio1 != folio2)
183+
folio_unlock(folio2);
184184
}
185185

186186
/*
187187
* Compare extents of two files to see if they are the same.
188188
* Caller must have locked both inodes to prevent write races.
189189
*/
190190
static int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
191-
struct inode *dest, loff_t destoff,
191+
struct inode *dest, loff_t dstoff,
192192
loff_t len, bool *is_same)
193193
{
194-
loff_t src_poff;
195-
loff_t dest_poff;
196-
void *src_addr;
197-
void *dest_addr;
198-
struct page *src_page;
199-
struct page *dest_page;
200-
loff_t cmp_len;
201-
bool same;
202-
int error;
203-
204-
error = -EINVAL;
205-
same = true;
194+
bool same = true;
195+
int error = -EINVAL;
196+
206197
while (len) {
207-
src_poff = srcoff & (PAGE_SIZE - 1);
208-
dest_poff = destoff & (PAGE_SIZE - 1);
209-
cmp_len = min(PAGE_SIZE - src_poff,
210-
PAGE_SIZE - dest_poff);
198+
struct folio *src_folio, *dst_folio;
199+
void *src_addr, *dst_addr;
200+
loff_t cmp_len = min(PAGE_SIZE - offset_in_page(srcoff),
201+
PAGE_SIZE - offset_in_page(dstoff));
202+
211203
cmp_len = min(cmp_len, len);
212204
if (cmp_len <= 0)
213205
goto out_error;
214206

215-
src_page = vfs_dedupe_get_page(src, srcoff);
216-
if (IS_ERR(src_page)) {
217-
error = PTR_ERR(src_page);
207+
src_folio = vfs_dedupe_get_folio(src, srcoff);
208+
if (IS_ERR(src_folio)) {
209+
error = PTR_ERR(src_folio);
218210
goto out_error;
219211
}
220-
dest_page = vfs_dedupe_get_page(dest, destoff);
221-
if (IS_ERR(dest_page)) {
222-
error = PTR_ERR(dest_page);
223-
put_page(src_page);
212+
dst_folio = vfs_dedupe_get_folio(dest, dstoff);
213+
if (IS_ERR(dst_folio)) {
214+
error = PTR_ERR(dst_folio);
215+
folio_put(src_folio);
224216
goto out_error;
225217
}
226218

227-
vfs_lock_two_pages(src_page, dest_page);
219+
vfs_lock_two_folios(src_folio, dst_folio);
228220

229221
/*
230-
* Now that we've locked both pages, make sure they're still
222+
* Now that we've locked both folios, make sure they're still
231223
* mapped to the file data we're interested in. If not,
232224
* someone is invalidating pages on us and we lose.
233225
*/
234-
if (!PageUptodate(src_page) || !PageUptodate(dest_page) ||
235-
src_page->mapping != src->i_mapping ||
236-
dest_page->mapping != dest->i_mapping) {
226+
if (!folio_test_uptodate(src_folio) || !folio_test_uptodate(dst_folio) ||
227+
src_folio->mapping != src->i_mapping ||
228+
dst_folio->mapping != dest->i_mapping) {
237229
same = false;
238230
goto unlock;
239231
}
240232

241-
src_addr = kmap_atomic(src_page);
242-
dest_addr = kmap_atomic(dest_page);
233+
src_addr = kmap_local_folio(src_folio,
234+
offset_in_folio(src_folio, srcoff));
235+
dst_addr = kmap_local_folio(dst_folio,
236+
offset_in_folio(dst_folio, dstoff));
243237

244-
flush_dcache_page(src_page);
245-
flush_dcache_page(dest_page);
238+
flush_dcache_folio(src_folio);
239+
flush_dcache_folio(dst_folio);
246240

247-
if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len))
241+
if (memcmp(src_addr, dst_addr, cmp_len))
248242
same = false;
249243

250-
kunmap_atomic(dest_addr);
251-
kunmap_atomic(src_addr);
244+
kunmap_local(dst_addr);
245+
kunmap_local(src_addr);
252246
unlock:
253-
vfs_unlock_two_pages(src_page, dest_page);
254-
put_page(dest_page);
255-
put_page(src_page);
247+
vfs_unlock_two_folios(src_folio, dst_folio);
248+
folio_put(dst_folio);
249+
folio_put(src_folio);
256250

257251
if (!same)
258252
break;
259253

260254
srcoff += cmp_len;
261-
destoff += cmp_len;
255+
dstoff += cmp_len;
262256
len -= cmp_len;
263257
}
264258

include/linux/huge_mm.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ static inline int thp_nr_pages(struct page *page)
274274
return 1;
275275
}
276276

277+
/**
278+
* folio_test_pmd_mappable - Can we map this folio with a PMD?
279+
* @folio: The folio to test
280+
*/
281+
static inline bool folio_test_pmd_mappable(struct folio *folio)
282+
{
283+
return folio_order(folio) >= HPAGE_PMD_ORDER;
284+
}
285+
277286
struct page *follow_devmap_pmd(struct vm_area_struct *vma, unsigned long addr,
278287
pmd_t *pmd, int flags, struct dev_pagemap **pgmap);
279288
struct page *follow_devmap_pud(struct vm_area_struct *vma, unsigned long addr,
@@ -339,6 +348,11 @@ static inline int thp_nr_pages(struct page *page)
339348
return 1;
340349
}
341350

351+
static inline bool folio_test_pmd_mappable(struct folio *folio)
352+
{
353+
return false;
354+
}
355+
342356
static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma)
343357
{
344358
return false;

include/linux/mm.h

Lines changed: 21 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,27 @@ int vma_is_stack_for_current(struct vm_area_struct *vma);
714714
struct mmu_gather;
715715
struct inode;
716716

717+
static inline unsigned int compound_order(struct page *page)
718+
{
719+
if (!PageHead(page))
720+
return 0;
721+
return page[1].compound_order;
722+
}
723+
724+
/**
725+
* folio_order - The allocation order of a folio.
726+
* @folio: The folio.
727+
*
728+
* A folio is composed of 2^order pages. See get_order() for the definition
729+
* of order.
730+
*
731+
* Return: The order of the folio.
732+
*/
733+
static inline unsigned int folio_order(struct folio *folio)
734+
{
735+
return compound_order(&folio->page);
736+
}
737+
717738
#include <linux/huge_mm.h>
718739

719740
/*
@@ -913,27 +934,6 @@ static inline void destroy_compound_page(struct page *page)
913934
compound_page_dtors[page[1].compound_dtor](page);
914935
}
915936

916-
static inline unsigned int compound_order(struct page *page)
917-
{
918-
if (!PageHead(page))
919-
return 0;
920-
return page[1].compound_order;
921-
}
922-
923-
/**
924-
* folio_order - The allocation order of a folio.
925-
* @folio: The folio.
926-
*
927-
* A folio is composed of 2^order pages. See get_order() for the definition
928-
* of order.
929-
*
930-
* Return: The order of the folio.
931-
*/
932-
static inline unsigned int folio_order(struct folio *folio)
933-
{
934-
return compound_order(&folio->page);
935-
}
936-
937937
static inline bool hpage_pincount_available(struct page *page)
938938
{
939939
/*
@@ -1837,28 +1837,6 @@ static inline bool can_do_mlock(void) { return false; }
18371837
extern int user_shm_lock(size_t, struct ucounts *);
18381838
extern void user_shm_unlock(size_t, struct ucounts *);
18391839

1840-
/*
1841-
* Parameter block passed down to zap_pte_range in exceptional cases.
1842-
*/
1843-
struct zap_details {
1844-
struct address_space *zap_mapping; /* Check page->mapping if set */
1845-
struct page *single_page; /* Locked page to be unmapped */
1846-
};
1847-
1848-
/*
1849-
* We set details->zap_mappings when we want to unmap shared but keep private
1850-
* pages. Return true if skip zapping this page, false otherwise.
1851-
*/
1852-
static inline bool
1853-
zap_skip_check_mapping(struct zap_details *details, struct page *page)
1854-
{
1855-
if (!details || !page)
1856-
return false;
1857-
1858-
return details->zap_mapping &&
1859-
(details->zap_mapping != page_rmapping(page));
1860-
}
1861-
18621840
struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
18631841
pte_t pte);
18641842
struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr,
@@ -1893,7 +1871,6 @@ extern void truncate_pagecache(struct inode *inode, loff_t new);
18931871
extern void truncate_setsize(struct inode *inode, loff_t newsize);
18941872
void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to);
18951873
void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
1896-
int truncate_inode_page(struct address_space *mapping, struct page *page);
18971874
int generic_error_remove_page(struct address_space *mapping, struct page *page);
18981875
int invalidate_inode_page(struct page *page);
18991876

@@ -1904,7 +1881,6 @@ extern vm_fault_t handle_mm_fault(struct vm_area_struct *vma,
19041881
extern int fixup_user_fault(struct mm_struct *mm,
19051882
unsigned long address, unsigned int fault_flags,
19061883
bool *unlocked);
1907-
void unmap_mapping_page(struct page *page);
19081884
void unmap_mapping_pages(struct address_space *mapping,
19091885
pgoff_t start, pgoff_t nr, bool even_cows);
19101886
void unmap_mapping_range(struct address_space *mapping,
@@ -1925,7 +1901,6 @@ static inline int fixup_user_fault(struct mm_struct *mm, unsigned long address,
19251901
BUG();
19261902
return -EFAULT;
19271903
}
1928-
static inline void unmap_mapping_page(struct page *page) { }
19291904
static inline void unmap_mapping_pages(struct address_space *mapping,
19301905
pgoff_t start, pgoff_t nr, bool even_cows) { }
19311906
static inline void unmap_mapping_range(struct address_space *mapping,
@@ -1982,7 +1957,6 @@ int get_kernel_pages(const struct kvec *iov, int nr_pages, int write,
19821957
struct page **pages);
19831958
struct page *get_dump_page(unsigned long addr);
19841959

1985-
extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
19861960
extern void do_invalidatepage(struct page *page, unsigned int offset,
19871961
unsigned int length);
19881962

include/linux/page-flags.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@
6868
* might lose their PG_swapbacked flag when they simply can be dropped (e.g. as
6969
* a result of MADV_FREE).
7070
*
71-
* PG_uptodate tells whether the page's contents is valid. When a read
72-
* completes, the page becomes uptodate, unless a disk I/O error happened.
73-
*
7471
* PG_referenced, PG_reclaim are used for page reclaim for anonymous and
7572
* file-backed pagecache (see mm/vmscan.c).
7673
*
@@ -615,6 +612,16 @@ TESTPAGEFLAG_FALSE(Ksm, ksm)
615612

616613
u64 stable_page_flags(struct page *page);
617614

615+
/**
616+
* folio_test_uptodate - Is this folio up to date?
617+
* @folio: The folio.
618+
*
619+
* The uptodate flag is set on a folio when every byte in the folio is
620+
* at least as new as the corresponding bytes on storage. Anonymous
621+
* and CoW folios are always uptodate. If the folio is not uptodate,
622+
* some of the bytes in it may be; see the is_partially_uptodate()
623+
* address_space operation.
624+
*/
618625
static inline bool folio_test_uptodate(struct folio *folio)
619626
{
620627
bool ret = test_bit(PG_uptodate, folio_flags(folio, 0));

0 commit comments

Comments
 (0)