2022-10-11 22:05:20

by Vishal Moola

[permalink] [raw]
Subject: [PATCH 0/4] Rework find_get_entries() and find_lock_entries()

Originally the callers of find_get_entries() and find_lock_entries()
were keeping track of the start index themselves as
they traverse the search range range.

This resulted in hacky code such as in shmem_undo_range():

index = folio->index + folio_nr_pages(folio) - 1;

where the - 1 is only present to stay in the right spot after
incrementing index later. This sort of calculation was also being done
on every folio despite not even using index later within that function.

The first two patches change find_get_entries() and find_lock_entries()
to calculate the new index instead of leaving it to the callers so we can
avoid all these complications.

Furthermore, the indices array is almost exclusively used for the
calculations of index mentioned above. Now that those calculations are
no longer occuring, the indices array serves no purpose aside from
tracking the xarray index of a folio which is also no longer needed.
Each folio already keeps track of its index and can be accessed using
folio->index instead.

The last 2 patches remove the indices arrays from the calling functions:
truncate_inode_pages_range(), invalidate_inode_pages2_range(),
invalidate_mapping_pagevec(), and shmem_undo_range().

Vishal Moola (Oracle) (4):
filemap: find_lock_entries() now updates start offset
filemap: find_get_entries() now updates start offset
truncate: Remove indices argument from
truncate_folio_batch_exceptionals()
filemap: Remove indices argument from find_lock_entries() and
find_get_entries()

mm/filemap.c | 40 ++++++++++++++++++++++++++++-----------
mm/internal.h | 8 ++++----
mm/shmem.c | 23 +++++++----------------
mm/truncate.c | 52 +++++++++++++++++++--------------------------------
4 files changed, 59 insertions(+), 64 deletions(-)

--
2.36.1


2022-10-11 22:19:10

by Vishal Moola

[permalink] [raw]
Subject: [PATCH 4/4] filemap: Remove indices argument from find_lock_entries() and find_get_entries()

The indices array is unnecessary. Folios keep track of their xarray indices
in the folio->index field which can simply be accessed as needed.

This change removes the indices argument from find_lock_entries() and
find_get_entries(). All of the callers are able to remove their indices
arrays as well.

Signed-off-by: Vishal Moola (Oracle) <[email protected]>
---
mm/filemap.c | 8 ++------
mm/internal.h | 4 ++--
mm/shmem.c | 6 ++----
mm/truncate.c | 12 ++++--------
4 files changed, 10 insertions(+), 20 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index 1b8022c18dc7..1f6be113a214 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2034,7 +2034,6 @@ static inline struct folio *find_get_entry(struct xa_state *xas, pgoff_t max,
* @start: The starting page cache index
* @end: The final page index (inclusive).
* @fbatch: Where the resulting entries are placed.
- * @indices: The cache indices corresponding to the entries in @entries
*
* find_get_entries() will search for and return a batch of entries in
* the mapping. The entries are placed in @fbatch. find_get_entries()
@@ -2050,7 +2049,7 @@ static inline struct folio *find_get_entry(struct xa_state *xas, pgoff_t max,
* Also updates @start to be positioned after the last found entry
*/
unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
- pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices)
+ pgoff_t end, struct folio_batch *fbatch)
{
XA_STATE(xas, &mapping->i_pages, *start);
unsigned long nr;
@@ -2058,7 +2057,6 @@ unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,

rcu_read_lock();
while ((folio = find_get_entry(&xas, end, XA_PRESENT)) != NULL) {
- indices[fbatch->nr] = xas.xa_index;
if (!folio_batch_add(fbatch, folio))
break;
}
@@ -2082,7 +2080,6 @@ unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
* @start: The starting page cache index.
* @end: The final page index (inclusive).
* @fbatch: Where the resulting entries are placed.
- * @indices: The cache indices of the entries in @fbatch.
*
* find_lock_entries() will return a batch of entries from @mapping.
* Swap, shadow and DAX entries are included. Folios are returned
@@ -2098,7 +2095,7 @@ unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
* Also updates @start to be positioned after the last found entry
*/
unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
- pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices)
+ pgoff_t end, struct folio_batch *fbatch)
{
XA_STATE(xas, &mapping->i_pages, *start);
unsigned long nr;
@@ -2119,7 +2116,6 @@ unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
VM_BUG_ON_FOLIO(!folio_contains(folio, xas.xa_index),
folio);
}
- indices[fbatch->nr] = xas.xa_index;
if (!folio_batch_add(fbatch, folio))
break;
continue;
diff --git a/mm/internal.h b/mm/internal.h
index 68afdbe7106e..db8d5dfa6d68 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -107,9 +107,9 @@ static inline void force_page_cache_readahead(struct address_space *mapping,
}

unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
- pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
+ pgoff_t end, struct folio_batch *fbatch);
unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
- pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
+ pgoff_t end, struct folio_batch *fbatch);
void filemap_free_folio(struct address_space *mapping, struct folio *folio);
int truncate_inode_folio(struct address_space *mapping, struct folio *folio);
bool truncate_inode_partial_folio(struct folio *folio, loff_t start,
diff --git a/mm/shmem.c b/mm/shmem.c
index 8240e066edfc..ad6b5adf04ac 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -907,7 +907,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
pgoff_t start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT;
pgoff_t end = (lend + 1) >> PAGE_SHIFT;
struct folio_batch fbatch;
- pgoff_t indices[PAGEVEC_SIZE];
struct folio *folio;
bool same_folio;
long nr_swaps_freed = 0;
@@ -923,7 +922,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
folio_batch_init(&fbatch);
index = start;
while (index < end && find_lock_entries(mapping, &index, end - 1,
- &fbatch, indices)) {
+ &fbatch)) {
for (i = 0; i < folio_batch_count(&fbatch); i++) {
folio = fbatch.folios[i];

@@ -973,8 +972,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
while (index < end) {
cond_resched();

- if (!find_get_entries(mapping, &index, end - 1, &fbatch,
- indices)) {
+ if (!find_get_entries(mapping, &index, end - 1, &fbatch)) {
/* If all gone or hole-punch or unfalloc, we're done */
if (index == start || end != -1)
break;
diff --git a/mm/truncate.c b/mm/truncate.c
index 4e63d885498a..9db247a88483 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -332,7 +332,6 @@ void truncate_inode_pages_range(struct address_space *mapping,
pgoff_t start; /* inclusive */
pgoff_t end; /* exclusive */
struct folio_batch fbatch;
- pgoff_t indices[PAGEVEC_SIZE];
pgoff_t index;
int i;
struct folio *folio;
@@ -361,7 +360,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
folio_batch_init(&fbatch);
index = start;
while (index < end && find_lock_entries(mapping, &index, end - 1,
- &fbatch, indices)) {
+ &fbatch)) {
truncate_folio_batch_exceptionals(mapping, &fbatch);
for (i = 0; i < folio_batch_count(&fbatch); i++)
truncate_cleanup_folio(fbatch.folios[i]);
@@ -399,8 +398,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
index = start;
while (index < end) {
cond_resched();
- if (!find_get_entries(mapping, &index, end - 1, &fbatch,
- indices)) {
+ if (!find_get_entries(mapping, &index, end - 1, &fbatch)) {
/* If all gone from start onwards, we're done */
if (index == start)
break;
@@ -497,7 +495,6 @@ EXPORT_SYMBOL(truncate_inode_pages_final);
unsigned long invalidate_mapping_pagevec(struct address_space *mapping,
pgoff_t start, pgoff_t end, unsigned long *nr_pagevec)
{
- pgoff_t indices[PAGEVEC_SIZE];
struct folio_batch fbatch;
pgoff_t index = start;
unsigned long ret;
@@ -505,7 +502,7 @@ unsigned long invalidate_mapping_pagevec(struct address_space *mapping,
int i;

folio_batch_init(&fbatch);
- while (find_lock_entries(mapping, &index, end, &fbatch, indices)) {
+ while (find_lock_entries(mapping, &index, end, &fbatch)) {
for (i = 0; i < folio_batch_count(&fbatch); i++) {
struct folio *folio = fbatch.folios[i];

@@ -620,7 +617,6 @@ static int folio_launder(struct address_space *mapping, struct folio *folio)
int invalidate_inode_pages2_range(struct address_space *mapping,
pgoff_t start, pgoff_t end)
{
- pgoff_t indices[PAGEVEC_SIZE];
struct folio_batch fbatch;
pgoff_t index;
int i;
@@ -633,7 +629,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,

folio_batch_init(&fbatch);
index = start;
- while (find_get_entries(mapping, &index, end, &fbatch, indices)) {
+ while (find_get_entries(mapping, &index, end, &fbatch)) {
for (i = 0; i < folio_batch_count(&fbatch); i++) {
struct folio *folio = fbatch.folios[i];

--
2.36.1

2022-10-11 22:19:41

by Vishal Moola

[permalink] [raw]
Subject: [PATCH 3/4] truncate: Remove indices argument from truncate_folio_batch_exceptionals()

The indices array is unnecessary. Folios keep track of their xarray indices
in the folio->index field which can simply be accessed as needed.

This change is in preparation for the removal of the indices arguments of
find_get_entries() and find_lock_entries().

Signed-off-by: Vishal Moola (Oracle) <[email protected]>
---
mm/truncate.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/mm/truncate.c b/mm/truncate.c
index 846ddbdb27a4..4e63d885498a 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -58,7 +58,7 @@ static void clear_shadow_entry(struct address_space *mapping, pgoff_t index,
* exceptional entries similar to what folio_batch_remove_exceptionals() does.
*/
static void truncate_folio_batch_exceptionals(struct address_space *mapping,
- struct folio_batch *fbatch, pgoff_t *indices)
+ struct folio_batch *fbatch)
{
int i, j;
bool dax;
@@ -82,7 +82,6 @@ static void truncate_folio_batch_exceptionals(struct address_space *mapping,

for (i = j; i < folio_batch_count(fbatch); i++) {
struct folio *folio = fbatch->folios[i];
- pgoff_t index = indices[i];

if (!xa_is_value(folio)) {
fbatch->folios[j++] = folio;
@@ -90,11 +89,11 @@ static void truncate_folio_batch_exceptionals(struct address_space *mapping,
}

if (unlikely(dax)) {
- dax_delete_mapping_entry(mapping, index);
+ dax_delete_mapping_entry(mapping, folio->index);
continue;
}

- __clear_shadow_entry(mapping, index, folio);
+ __clear_shadow_entry(mapping, folio->index, folio);
}

if (!dax) {
@@ -363,7 +362,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
index = start;
while (index < end && find_lock_entries(mapping, &index, end - 1,
&fbatch, indices)) {
- truncate_folio_batch_exceptionals(mapping, &fbatch, indices);
+ truncate_folio_batch_exceptionals(mapping, &fbatch);
for (i = 0; i < folio_batch_count(&fbatch); i++)
truncate_cleanup_folio(fbatch.folios[i]);
delete_from_page_cache_batch(mapping, &fbatch);
@@ -424,7 +423,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
truncate_inode_folio(mapping, folio);
folio_unlock(folio);
}
- truncate_folio_batch_exceptionals(mapping, &fbatch, indices);
+ truncate_folio_batch_exceptionals(mapping, &fbatch);
folio_batch_release(&fbatch);
}
}
--
2.36.1

2022-10-11 22:20:18

by Vishal Moola

[permalink] [raw]
Subject: [PATCH 2/4] filemap: find_get_entries() now updates start offset

Initially, find_get_entries() was being passed in the start offset as a
value. That left the calculation of the offset to the callers. This led
to complexity in the callers trying to keep track of the index.

Now find_get_entires() takes in a pointer to the start offset and
updates the value to be directly after the last entry found. If no entry is
found, the offset is not changed. This gets rid of multiple hacky
calculations that kept track of the start offset.

Signed-off-by: Vishal Moola (Oracle) <[email protected]>
---
mm/filemap.c | 15 +++++++++++++--
mm/internal.h | 2 +-
mm/shmem.c | 11 ++++-------
mm/truncate.c | 23 +++++++++--------------
4 files changed, 27 insertions(+), 24 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index e95500b07ee9..1b8022c18dc7 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2047,11 +2047,13 @@ static inline struct folio *find_get_entry(struct xa_state *xas, pgoff_t max,
* shmem/tmpfs, are included in the returned array.
*
* Return: The number of entries which were found.
+ * Also updates @start to be positioned after the last found entry
*/
-unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
+unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices)
{
- XA_STATE(xas, &mapping->i_pages, start);
+ XA_STATE(xas, &mapping->i_pages, *start);
+ unsigned long nr;
struct folio *folio;

rcu_read_lock();
@@ -2061,7 +2063,16 @@ unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
break;
}
rcu_read_unlock();
+ nr = folio_batch_count(fbatch);
+
+ if (nr) {
+ folio = fbatch->folios[nr - 1];
+ nr = folio_nr_pages(folio);

+ if (folio_test_hugetlb(folio))
+ nr = 1;
+ *start = folio->index + nr;
+ }
return folio_batch_count(fbatch);
}

diff --git a/mm/internal.h b/mm/internal.h
index c504ac7267e0..68afdbe7106e 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -108,7 +108,7 @@ static inline void force_page_cache_readahead(struct address_space *mapping,

unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
-unsigned find_get_entries(struct address_space *mapping, pgoff_t start,
+unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
void filemap_free_folio(struct address_space *mapping, struct folio *folio);
int truncate_inode_folio(struct address_space *mapping, struct folio *folio);
diff --git a/mm/shmem.c b/mm/shmem.c
index ab4f6dfcf6bb..8240e066edfc 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -973,7 +973,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
while (index < end) {
cond_resched();

- if (!find_get_entries(mapping, index, end - 1, &fbatch,
+ if (!find_get_entries(mapping, &index, end - 1, &fbatch,
indices)) {
/* If all gone or hole-punch or unfalloc, we're done */
if (index == start || end != -1)
@@ -985,13 +985,12 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
for (i = 0; i < folio_batch_count(&fbatch); i++) {
folio = fbatch.folios[i];

- index = indices[i];
if (xa_is_value(folio)) {
if (unfalloc)
continue;
- if (shmem_free_swap(mapping, index, folio)) {
+ if (shmem_free_swap(mapping, folio->index, folio)) {
/* Swap was replaced by page: retry */
- index--;
+ index = folio->index;
break;
}
nr_swaps_freed++;
@@ -1004,19 +1003,17 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
if (folio_mapping(folio) != mapping) {
/* Page was replaced by swap: retry */
folio_unlock(folio);
- index--;
+ index = folio->index;
break;
}
VM_BUG_ON_FOLIO(folio_test_writeback(folio),
folio);
truncate_inode_folio(mapping, folio);
}
- index = folio->index + folio_nr_pages(folio) - 1;
folio_unlock(folio);
}
folio_batch_remove_exceptionals(&fbatch);
folio_batch_release(&fbatch);
- index++;
}

spin_lock_irq(&info->lock);
diff --git a/mm/truncate.c b/mm/truncate.c
index b0bd63b2359f..846ddbdb27a4 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -400,7 +400,7 @@ void truncate_inode_pages_range(struct address_space *mapping,
index = start;
while (index < end) {
cond_resched();
- if (!find_get_entries(mapping, index, end - 1, &fbatch,
+ if (!find_get_entries(mapping, &index, end - 1, &fbatch,
indices)) {
/* If all gone from start onwards, we're done */
if (index == start)
@@ -414,21 +414,18 @@ void truncate_inode_pages_range(struct address_space *mapping,
struct folio *folio = fbatch.folios[i];

/* We rely upon deletion not changing page->index */
- index = indices[i];
-
if (xa_is_value(folio))
continue;

folio_lock(folio);
- VM_BUG_ON_FOLIO(!folio_contains(folio, index), folio);
+ VM_BUG_ON_FOLIO(!folio_contains(folio, folio->index),
+ folio);
folio_wait_writeback(folio);
truncate_inode_folio(mapping, folio);
folio_unlock(folio);
- index = folio_index(folio) + folio_nr_pages(folio) - 1;
}
truncate_folio_batch_exceptionals(mapping, &fbatch, indices);
folio_batch_release(&fbatch);
- index++;
}
}
EXPORT_SYMBOL(truncate_inode_pages_range);
@@ -637,16 +634,14 @@ int invalidate_inode_pages2_range(struct address_space *mapping,

folio_batch_init(&fbatch);
index = start;
- while (find_get_entries(mapping, index, end, &fbatch, indices)) {
+ while (find_get_entries(mapping, &index, end, &fbatch, indices)) {
for (i = 0; i < folio_batch_count(&fbatch); i++) {
struct folio *folio = fbatch.folios[i];

/* We rely upon deletion not changing folio->index */
- index = indices[i];
-
if (xa_is_value(folio)) {
if (!invalidate_exceptional_entry2(mapping,
- index, folio))
+ folio->index, folio))
ret = -EBUSY;
continue;
}
@@ -656,13 +651,14 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
* If folio is mapped, before taking its lock,
* zap the rest of the file in one hit.
*/
- unmap_mapping_pages(mapping, index,
- (1 + end - index), false);
+ unmap_mapping_pages(mapping, folio->index,
+ (1 + end - folio->index), false);
did_range_unmap = 1;
}

folio_lock(folio);
- VM_BUG_ON_FOLIO(!folio_contains(folio, index), folio);
+ VM_BUG_ON_FOLIO(!folio_contains(folio, folio->index),
+ folio);
if (folio->mapping != mapping) {
folio_unlock(folio);
continue;
@@ -685,7 +681,6 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
folio_batch_remove_exceptionals(&fbatch);
folio_batch_release(&fbatch);
cond_resched();
- index++;
}
/*
* For DAX we invalidate page tables after invalidating page cache. We
--
2.36.1