Commit 60aac486 authored by Vishal Moola (Oracle)'s avatar Vishal Moola (Oracle) Committed by Andrew Morton

ramfs: convert ramfs_nommu_get_unmapped_area() to use filemap_get_folios_contig()

Convert to use folios throughout.  This is in preparation for the removal
for find_get_pages_contig().  Now also supports large folios.

The initial version of this function set the page_address to be returned
after finishing all the checks.  Since folio_batches have a maximum of 15
folios, the function had to be modified to support getting and checking up
to lpages, 15 pages at a time while still returning the initial page
address.  Now the function sets ret as soon as the first batch arrives,
and updates it only if a check fails.

The physical adjacency check utilizes the page frame numbers.  The page
frame number of each folio must be nr_pages away from the first folio.

Link: https://lkml.kernel.org/r/20220824004023.77310-7-vishal.moola@gmail.comSigned-off-by: default avatarVishal Moola (Oracle) <vishal.moola@gmail.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Chris Mason <clm@fb.com>
Cc: David Sterba <dsterba@suse.com>
Cc: David Sterba <dsterb@suse.com>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 24a1efb4
...@@ -203,9 +203,9 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, ...@@ -203,9 +203,9 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
unsigned long addr, unsigned long len, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags) unsigned long pgoff, unsigned long flags)
{ {
unsigned long maxpages, lpages, nr, loop, ret; unsigned long maxpages, lpages, nr_folios, loop, ret, nr_pages, pfn;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct page **pages = NULL, **ptr, *page; struct folio_batch fbatch;
loff_t isize; loff_t isize;
/* the mapping mustn't extend beyond the EOF */ /* the mapping mustn't extend beyond the EOF */
...@@ -221,31 +221,39 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, ...@@ -221,31 +221,39 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
goto out; goto out;
/* gang-find the pages */ /* gang-find the pages */
pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL); folio_batch_init(&fbatch);
if (!pages) nr_pages = 0;
goto out_free; repeat:
nr_folios = filemap_get_folios_contig(inode->i_mapping, &pgoff,
nr = find_get_pages_contig(inode->i_mapping, pgoff, lpages, pages); ULONG_MAX, &fbatch);
if (nr != lpages) if (!nr_folios) {
goto out_free_pages; /* leave if some pages were missing */ ret = -ENOSYS;
return ret;
}
if (ret == -ENOSYS) {
ret = (unsigned long) folio_address(fbatch.folios[0]);
pfn = folio_pfn(fbatch.folios[0]);
}
/* check the pages for physical adjacency */ /* check the pages for physical adjacency */
ptr = pages; for (loop = 0; loop < nr_folios; loop++) {
page = *ptr++; if (pfn + nr_pages != folio_pfn(fbatch.folios[loop])) {
page++; ret = -ENOSYS;
for (loop = lpages; loop > 1; loop--) goto out_free; /* leave if not physical adjacent */
if (*ptr++ != page++) }
goto out_free_pages; nr_pages += folio_nr_pages(fbatch.folios[loop]);
if (nr_pages >= lpages)
goto out_free; /* successfully found desired pages*/
}
if (nr_pages < lpages) {
folio_batch_release(&fbatch);
goto repeat; /* loop if pages are missing */
}
/* okay - all conditions fulfilled */ /* okay - all conditions fulfilled */
ret = (unsigned long) page_address(pages[0]);
out_free_pages:
ptr = pages;
for (loop = nr; loop > 0; loop--)
put_page(*ptr++);
out_free: out_free:
kfree(pages); folio_batch_release(&fbatch);
out: out:
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment