forked from Minki/linux
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.com Signed-off-by: Vishal 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: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
24a1efb4a9
commit
60aac486da
@ -203,9 +203,9 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
|
||||
unsigned long addr, unsigned long len,
|
||||
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 page **pages = NULL, **ptr, *page;
|
||||
struct folio_batch fbatch;
|
||||
loff_t isize;
|
||||
|
||||
/* the mapping mustn't extend beyond the EOF */
|
||||
@ -221,31 +221,39 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
|
||||
goto out;
|
||||
|
||||
/* gang-find the pages */
|
||||
pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL);
|
||||
if (!pages)
|
||||
goto out_free;
|
||||
|
||||
nr = find_get_pages_contig(inode->i_mapping, pgoff, lpages, pages);
|
||||
if (nr != lpages)
|
||||
goto out_free_pages; /* leave if some pages were missing */
|
||||
folio_batch_init(&fbatch);
|
||||
nr_pages = 0;
|
||||
repeat:
|
||||
nr_folios = filemap_get_folios_contig(inode->i_mapping, &pgoff,
|
||||
ULONG_MAX, &fbatch);
|
||||
if (!nr_folios) {
|
||||
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 */
|
||||
ptr = pages;
|
||||
page = *ptr++;
|
||||
page++;
|
||||
for (loop = lpages; loop > 1; loop--)
|
||||
if (*ptr++ != page++)
|
||||
goto out_free_pages;
|
||||
for (loop = 0; loop < nr_folios; loop++) {
|
||||
if (pfn + nr_pages != folio_pfn(fbatch.folios[loop])) {
|
||||
ret = -ENOSYS;
|
||||
goto out_free; /* leave if not physical adjacent */
|
||||
}
|
||||
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 */
|
||||
ret = (unsigned long) page_address(pages[0]);
|
||||
|
||||
out_free_pages:
|
||||
ptr = pages;
|
||||
for (loop = nr; loop > 0; loop--)
|
||||
put_page(*ptr++);
|
||||
out_free:
|
||||
kfree(pages);
|
||||
folio_batch_release(&fbatch);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user