[RFC v2 03/14] filemap: use mapping_min_order while allocating folios

From: Pankaj Raghav (Samsung)
Date: Tue Feb 13 2024 - 04:40:48 EST


From: Pankaj Raghav <p.raghav@xxxxxxxxxxx>

filemap_create_folio() and do_read_cache_folio() were always allocating
folio of order 0. __filemap_get_folio was trying to allocate higher
order folios when fgp_flags had higher order hint set but it will default
to order 0 folio if higher order memory allocation fails.

As we bring the notion of mapping_min_order, make sure these functions
allocate at least folio of mapping_min_order as we need to guarantee it
in the page cache.

Add some additional VM_BUG_ON() in page_cache_delete[batch] and
__filemap_add_folio to catch errors where we delete or add folios that
has order less than min_order.

Signed-off-by: Pankaj Raghav <p.raghav@xxxxxxxxxxx>
Signed-off-by: Luis Chamberlain <mcgrof@xxxxxxxxxx>
---
mm/filemap.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index 323a8e169581..7a6e15c47150 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -127,6 +127,7 @@
static void page_cache_delete(struct address_space *mapping,
struct folio *folio, void *shadow)
{
+ unsigned int min_order = mapping_min_folio_order(mapping);
XA_STATE(xas, &mapping->i_pages, folio->index);
long nr = 1;

@@ -135,6 +136,7 @@ static void page_cache_delete(struct address_space *mapping,
xas_set_order(&xas, folio->index, folio_order(folio));
nr = folio_nr_pages(folio);

+ VM_BUG_ON_FOLIO(folio_order(folio) < min_order, folio);
VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);

xas_store(&xas, shadow);
@@ -277,6 +279,7 @@ void filemap_remove_folio(struct folio *folio)
static void page_cache_delete_batch(struct address_space *mapping,
struct folio_batch *fbatch)
{
+ unsigned int min_order = mapping_min_folio_order(mapping);
XA_STATE(xas, &mapping->i_pages, fbatch->folios[0]->index);
long total_pages = 0;
int i = 0;
@@ -305,6 +308,7 @@ static void page_cache_delete_batch(struct address_space *mapping,

WARN_ON_ONCE(!folio_test_locked(folio));

+ VM_BUG_ON_FOLIO(folio_order(folio) < min_order, folio);
folio->mapping = NULL;
/* Leave folio->index set: truncation lookup relies on it */

@@ -846,6 +850,7 @@ noinline int __filemap_add_folio(struct address_space *mapping,
int huge = folio_test_hugetlb(folio);
bool charged = false;
long nr = 1;
+ unsigned int min_order = mapping_min_folio_order(mapping);

VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
VM_BUG_ON_FOLIO(folio_test_swapbacked(folio), folio);
@@ -896,6 +901,7 @@ noinline int __filemap_add_folio(struct address_space *mapping,
}
}

+ VM_BUG_ON_FOLIO(folio_order(folio) < min_order, folio);
xas_store(&xas, folio);
if (xas_error(&xas))
goto unlock;
@@ -1847,6 +1853,10 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
fgf_t fgp_flags, gfp_t gfp)
{
struct folio *folio;
+ unsigned int min_order = mapping_min_folio_order(mapping);
+ unsigned int min_nrpages = mapping_min_folio_nrpages(mapping);
+
+ index = round_down(index, min_nrpages);

repeat:
folio = filemap_get_entry(mapping, index);
@@ -1886,7 +1896,7 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
folio_wait_stable(folio);
no_page:
if (!folio && (fgp_flags & FGP_CREAT)) {
- unsigned order = FGF_GET_ORDER(fgp_flags);
+ unsigned int order = max(min_order, FGF_GET_ORDER(fgp_flags));
int err;

if ((fgp_flags & FGP_WRITE) && mapping_can_writeback(mapping))
@@ -1914,8 +1924,13 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
err = -ENOMEM;
if (order == 1)
order = 0;
+ if (order < min_order)
+ order = min_order;
if (order > 0)
alloc_gfp |= __GFP_NORETRY | __GFP_NOWARN;
+
+ VM_BUG_ON(index & ((1UL << order) - 1));
+
folio = filemap_alloc_folio(alloc_gfp, order);
if (!folio)
continue;
@@ -1929,7 +1944,7 @@ struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index,
break;
folio_put(folio);
folio = NULL;
- } while (order-- > 0);
+ } while (order-- > min_order);

if (err == -EEXIST)
goto repeat;
@@ -2424,7 +2439,8 @@ static int filemap_create_folio(struct file *file,
struct folio *folio;
int error;

- folio = filemap_alloc_folio(mapping_gfp_mask(mapping), 0);
+ folio = filemap_alloc_folio(mapping_gfp_mask(mapping),
+ mapping_min_folio_order(mapping));
if (!folio)
return -ENOMEM;

@@ -3682,7 +3698,8 @@ static struct folio *do_read_cache_folio(struct address_space *mapping,
repeat:
folio = filemap_get_folio(mapping, index);
if (IS_ERR(folio)) {
- folio = filemap_alloc_folio(gfp, 0);
+ folio = filemap_alloc_folio(gfp,
+ mapping_min_folio_order(mapping));
if (!folio)
return ERR_PTR(-ENOMEM);
err = filemap_add_folio(mapping, folio, index, gfp);
--
2.43.0