Skip to content

Commit 5c211ba

Browse files
Matthew Wilcox (Oracle)torvalds
Matthew Wilcox (Oracle)
authored andcommitted
mm: add and use find_lock_entries
We have three functions (shmem_undo_range(), truncate_inode_pages_range() and invalidate_mapping_pages()) which want exactly this function, so add it to filemap.c. Before this patch, shmem_undo_range() would split any compound page which overlaps either end of the range being punched in both the first and second loops through the address space. After this patch, that functionality is left for the second loop, which is arguably more appropriate since the first loop is supposed to run through all the pages quickly, and splitting a page can sleep. [[email protected]: add assertion] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Reviewed-by: Jan Kara <[email protected]> Reviewed-by: William Kucharski <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Cc: Dave Chinner <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Yang Shi <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 54fa39a commit 5c211ba

File tree

4 files changed

+78
-97
lines changed

4 files changed

+78
-97
lines changed

mm/filemap.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,65 @@ unsigned find_get_entries(struct address_space *mapping,
19201920
return ret;
19211921
}
19221922

1923+
/**
1924+
* find_lock_entries - Find a batch of pagecache entries.
1925+
* @mapping: The address_space to search.
1926+
* @start: The starting page cache index.
1927+
* @end: The final page index (inclusive).
1928+
* @pvec: Where the resulting entries are placed.
1929+
* @indices: The cache indices of the entries in @pvec.
1930+
*
1931+
* find_lock_entries() will return a batch of entries from @mapping.
1932+
* Swap, shadow and DAX entries are included. Pages are returned
1933+
* locked and with an incremented refcount. Pages which are locked by
1934+
* somebody else or under writeback are skipped. Only the head page of
1935+
* a THP is returned. Pages which are partially outside the range are
1936+
* not returned.
1937+
*
1938+
* The entries have ascending indexes. The indices may not be consecutive
1939+
* due to not-present entries, THP pages, pages which could not be locked
1940+
* or pages under writeback.
1941+
*
1942+
* Return: The number of entries which were found.
1943+
*/
1944+
unsigned find_lock_entries(struct address_space *mapping, pgoff_t start,
1945+
pgoff_t end, struct pagevec *pvec, pgoff_t *indices)
1946+
{
1947+
XA_STATE(xas, &mapping->i_pages, start);
1948+
struct page *page;
1949+
1950+
rcu_read_lock();
1951+
while ((page = find_get_entry(&xas, end, XA_PRESENT))) {
1952+
if (!xa_is_value(page)) {
1953+
if (page->index < start)
1954+
goto put;
1955+
VM_BUG_ON_PAGE(page->index != xas.xa_index, page);
1956+
if (page->index + thp_nr_pages(page) - 1 > end)
1957+
goto put;
1958+
if (!trylock_page(page))
1959+
goto put;
1960+
if (page->mapping != mapping || PageWriteback(page))
1961+
goto unlock;
1962+
VM_BUG_ON_PAGE(!thp_contains(page, xas.xa_index),
1963+
page);
1964+
}
1965+
indices[pvec->nr] = xas.xa_index;
1966+
if (!pagevec_add(pvec, page))
1967+
break;
1968+
goto next;
1969+
unlock:
1970+
unlock_page(page);
1971+
put:
1972+
put_page(page);
1973+
next:
1974+
if (!xa_is_value(page) && PageTransHuge(page))
1975+
xas_set(&xas, page->index + thp_nr_pages(page));
1976+
}
1977+
rcu_read_unlock();
1978+
1979+
return pagevec_count(pvec);
1980+
}
1981+
19231982
/**
19241983
* find_get_pages_range - gang pagecache lookup
19251984
* @mapping: The address_space to search

mm/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ static inline void force_page_cache_readahead(struct address_space *mapping,
6060
force_page_cache_ra(&ractl, &file->f_ra, nr_to_read);
6161
}
6262

63+
unsigned find_lock_entries(struct address_space *mapping, pgoff_t start,
64+
pgoff_t end, struct pagevec *pvec, pgoff_t *indices);
65+
6366
/**
6467
* page_evictable - test whether a page is evictable
6568
* @page: the page to test

mm/shmem.c

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -907,12 +907,8 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
907907

908908
pagevec_init(&pvec);
909909
index = start;
910-
while (index < end) {
911-
pvec.nr = find_get_entries(mapping, index,
912-
min(end - index, (pgoff_t)PAGEVEC_SIZE),
913-
pvec.pages, indices);
914-
if (!pvec.nr)
915-
break;
910+
while (index < end && find_lock_entries(mapping, index, end - 1,
911+
&pvec, indices)) {
916912
for (i = 0; i < pagevec_count(&pvec); i++) {
917913
struct page *page = pvec.pages[i];
918914

@@ -927,18 +923,10 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
927923
index, page);
928924
continue;
929925
}
926+
index += thp_nr_pages(page) - 1;
930927

931-
VM_BUG_ON_PAGE(page_to_pgoff(page) != index, page);
932-
933-
if (!trylock_page(page))
934-
continue;
935-
936-
if ((!unfalloc || !PageUptodate(page)) &&
937-
page_mapping(page) == mapping) {
938-
VM_BUG_ON_PAGE(PageWriteback(page), page);
939-
if (shmem_punch_compound(page, start, end))
940-
truncate_inode_page(mapping, page);
941-
}
928+
if (!unfalloc || !PageUptodate(page))
929+
truncate_inode_page(mapping, page);
942930
unlock_page(page);
943931
}
944932
pagevec_remove_exceptionals(&pvec);

mm/truncate.c

Lines changed: 11 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -326,51 +326,19 @@ void truncate_inode_pages_range(struct address_space *mapping,
326326

327327
pagevec_init(&pvec);
328328
index = start;
329-
while (index < end && pagevec_lookup_entries(&pvec, mapping, index,
330-
min(end - index, (pgoff_t)PAGEVEC_SIZE),
331-
indices)) {
332-
/*
333-
* Pagevec array has exceptional entries and we may also fail
334-
* to lock some pages. So we store pages that can be deleted
335-
* in a new pagevec.
336-
*/
337-
struct pagevec locked_pvec;
338-
339-
pagevec_init(&locked_pvec);
340-
for (i = 0; i < pagevec_count(&pvec); i++) {
341-
struct page *page = pvec.pages[i];
342-
343-
/* We rely upon deletion not changing page->index */
344-
index = indices[i];
345-
if (index >= end)
346-
break;
347-
348-
if (xa_is_value(page))
349-
continue;
350-
351-
if (!trylock_page(page))
352-
continue;
353-
WARN_ON(page_to_index(page) != index);
354-
if (PageWriteback(page)) {
355-
unlock_page(page);
356-
continue;
357-
}
358-
if (page->mapping != mapping) {
359-
unlock_page(page);
360-
continue;
361-
}
362-
pagevec_add(&locked_pvec, page);
363-
}
364-
for (i = 0; i < pagevec_count(&locked_pvec); i++)
365-
truncate_cleanup_page(mapping, locked_pvec.pages[i]);
366-
delete_from_page_cache_batch(mapping, &locked_pvec);
367-
for (i = 0; i < pagevec_count(&locked_pvec); i++)
368-
unlock_page(locked_pvec.pages[i]);
329+
while (index < end && find_lock_entries(mapping, index, end - 1,
330+
&pvec, indices)) {
331+
index = indices[pagevec_count(&pvec) - 1] + 1;
369332
truncate_exceptional_pvec_entries(mapping, &pvec, indices, end);
333+
for (i = 0; i < pagevec_count(&pvec); i++)
334+
truncate_cleanup_page(mapping, pvec.pages[i]);
335+
delete_from_page_cache_batch(mapping, &pvec);
336+
for (i = 0; i < pagevec_count(&pvec); i++)
337+
unlock_page(pvec.pages[i]);
370338
pagevec_release(&pvec);
371339
cond_resched();
372-
index++;
373340
}
341+
374342
if (partial_start) {
375343
struct page *page = find_lock_page(mapping, start - 1);
376344
if (page) {
@@ -539,9 +507,7 @@ static unsigned long __invalidate_mapping_pages(struct address_space *mapping,
539507
int i;
540508

541509
pagevec_init(&pvec);
542-
while (index <= end && pagevec_lookup_entries(&pvec, mapping, index,
543-
min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
544-
indices)) {
510+
while (find_lock_entries(mapping, index, end, &pvec, indices)) {
545511
for (i = 0; i < pagevec_count(&pvec); i++) {
546512
struct page *page = pvec.pages[i];
547513

@@ -555,39 +521,7 @@ static unsigned long __invalidate_mapping_pages(struct address_space *mapping,
555521
page);
556522
continue;
557523
}
558-
559-
if (!trylock_page(page))
560-
continue;
561-
562-
WARN_ON(page_to_index(page) != index);
563-
564-
/* Middle of THP: skip */
565-
if (PageTransTail(page)) {
566-
unlock_page(page);
567-
continue;
568-
} else if (PageTransHuge(page)) {
569-
index += HPAGE_PMD_NR - 1;
570-
i += HPAGE_PMD_NR - 1;
571-
/*
572-
* 'end' is in the middle of THP. Don't
573-
* invalidate the page as the part outside of
574-
* 'end' could be still useful.
575-
*/
576-
if (index > end) {
577-
unlock_page(page);
578-
continue;
579-
}
580-
581-
/* Take a pin outside pagevec */
582-
get_page(page);
583-
584-
/*
585-
* Drop extra pins before trying to invalidate
586-
* the huge page.
587-
*/
588-
pagevec_remove_exceptionals(&pvec);
589-
pagevec_release(&pvec);
590-
}
524+
index += thp_nr_pages(page) - 1;
591525

592526
ret = invalidate_inode_page(page);
593527
unlock_page(page);
@@ -601,9 +535,6 @@ static unsigned long __invalidate_mapping_pages(struct address_space *mapping,
601535
if (nr_pagevec)
602536
(*nr_pagevec)++;
603537
}
604-
605-
if (PageTransHuge(page))
606-
put_page(page);
607538
count += ret;
608539
}
609540
pagevec_remove_exceptionals(&pvec);

0 commit comments

Comments
 (0)