Skip to content

Commit

Permalink
mm: support order-1 folios in the page cache
Browse files Browse the repository at this point in the history
Folios of order 1 have no space to store the deferred list.  This is not a
problem for the page cache as file-backed folios are never placed on the
deferred list.  All we need to do is prevent the core MM from touching the
deferred list for order 1 folios and remove the code which prevented us
from allocating order 1 folios.

Link: https://lore.kernel.org/linux-mm/[email protected]/
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Matthew Wilcox (Oracle) <[email protected]>
Signed-off-by: Zi Yan <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Kirill A. Shutemov <[email protected]>
Cc: Luis Chamberlain <[email protected]>
Cc: Michal Koutny <[email protected]>
Cc: Roman Gushchin <[email protected]>
Cc: Ryan Roberts <[email protected]>
Cc: Yang Shi <[email protected]>
Cc: Yu Zhao <[email protected]>
Cc: Zach O'Keefe <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
Matthew Wilcox (Oracle) authored and akpm00 committed Mar 5, 2024
1 parent 319a624 commit 8897277
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 11 deletions.
2 changes: 0 additions & 2 deletions mm/filemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1912,8 +1912,6 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
gfp_t alloc_gfp = gfp;

err = -ENOMEM;
if (order == 1)
order = 0;
if (order > 0)
alloc_gfp |= __GFP_NORETRY | __GFP_NOWARN;
folio = filemap_alloc_folio(alloc_gfp, order);
Expand Down
19 changes: 15 additions & 4 deletions mm/huge_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,8 +790,10 @@ struct deferred_split *get_deferred_split_queue(struct folio *folio)

void folio_prep_large_rmappable(struct folio *folio)
{
VM_BUG_ON_FOLIO(folio_order(folio) < 2, folio);
INIT_LIST_HEAD(&folio->_deferred_list);
if (!folio || !folio_test_large(folio))
return;
if (folio_order(folio) > 1)
INIT_LIST_HEAD(&folio->_deferred_list);
folio_set_large_rmappable(folio);
}

Expand Down Expand Up @@ -3114,7 +3116,8 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
/* Prevent deferred_split_scan() touching ->_refcount */
spin_lock(&ds_queue->split_queue_lock);
if (folio_ref_freeze(folio, 1 + extra_pins)) {
if (!list_empty(&folio->_deferred_list)) {
if (folio_order(folio) > 1 &&
!list_empty(&folio->_deferred_list)) {
ds_queue->split_queue_len--;
list_del(&folio->_deferred_list);
}
Expand Down Expand Up @@ -3165,6 +3168,9 @@ void folio_undo_large_rmappable(struct folio *folio)
struct deferred_split *ds_queue;
unsigned long flags;

if (folio_order(folio) <= 1)
return;

/*
* At this point, there is no one trying to add the folio to
* deferred_list. If folio is not in deferred_list, it's safe
Expand All @@ -3190,7 +3196,12 @@ void deferred_split_folio(struct folio *folio)
#endif
unsigned long flags;

VM_BUG_ON_FOLIO(folio_order(folio) < 2, folio);
/*
* Order 1 folios have no space for a deferred list, but we also
* won't waste much memory by not adding them to the deferred list.
*/
if (folio_order(folio) <= 1)
return;

/*
* The try_to_unmap() in page reclaim path might reach here too,
Expand Down
3 changes: 1 addition & 2 deletions mm/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,7 @@ static inline struct folio *page_rmappable_folio(struct page *page)
{
struct folio *folio = (struct folio *)page;

if (folio && folio_order(folio) > 1)
folio_prep_large_rmappable(folio);
folio_prep_large_rmappable(folio);
return folio;
}

Expand Down
3 changes: 0 additions & 3 deletions mm/readahead.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,6 @@ void page_cache_ra_order(struct readahead_control *ractl,
/* Don't allocate pages past EOF */
while (index + (1UL << order) - 1 > limit)
order--;
/* THP machinery does not support order-1 */
if (order == 1)
order = 0;
err = ra_alloc_folio(ractl, index, mark, order, gfp);
if (err)
break;
Expand Down

0 comments on commit 8897277

Please sign in to comment.