mm: add new 'read_cache_page_gfp()' helper function
It's a simplified 'read_cache_page()' which takes a page allocation flag, so that different paths can control how aggressive the memory allocations are that populate a address space. In particular, the intel GPU object mapping code wants to be able to do a certain amount of own internal memory management by automatically shrinking the address space when memory starts getting tight. This allows it to dynamically use different memory allocation policies on a per-allocation basis, rather than depend on the (static) address space gfp policy. The actual new function is a one-liner, but re-organizing the helper functions to the point where you can do this with a single line of code is what most of the patch is all about. Tested-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
caf0801e0c
Коммит
0531b2aac5
|
@ -253,6 +253,8 @@ extern struct page * read_cache_page_async(struct address_space *mapping,
|
|||
extern struct page * read_cache_page(struct address_space *mapping,
|
||||
pgoff_t index, filler_t *filler,
|
||||
void *data);
|
||||
extern struct page * read_cache_page_gfp(struct address_space *mapping,
|
||||
pgoff_t index, gfp_t gfp_mask);
|
||||
extern int read_cache_pages(struct address_space *mapping,
|
||||
struct list_head *pages, filler_t *filler, void *data);
|
||||
|
||||
|
|
100
mm/filemap.c
100
mm/filemap.c
|
@ -1634,14 +1634,15 @@ EXPORT_SYMBOL(generic_file_readonly_mmap);
|
|||
static struct page *__read_cache_page(struct address_space *mapping,
|
||||
pgoff_t index,
|
||||
int (*filler)(void *,struct page*),
|
||||
void *data)
|
||||
void *data,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct page *page;
|
||||
int err;
|
||||
repeat:
|
||||
page = find_get_page(mapping, index);
|
||||
if (!page) {
|
||||
page = page_cache_alloc_cold(mapping);
|
||||
page = __page_cache_alloc(gfp | __GFP_COLD);
|
||||
if (!page)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL);
|
||||
|
@ -1661,31 +1662,18 @@ repeat:
|
|||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_cache_page_async - read into page cache, fill it if needed
|
||||
* @mapping: the page's address_space
|
||||
* @index: the page index
|
||||
* @filler: function to perform the read
|
||||
* @data: destination for read data
|
||||
*
|
||||
* Same as read_cache_page, but don't wait for page to become unlocked
|
||||
* after submitting it to the filler.
|
||||
*
|
||||
* Read into the page cache. If a page already exists, and PageUptodate() is
|
||||
* not set, try to fill the page but don't wait for it to become unlocked.
|
||||
*
|
||||
* If the page does not get brought uptodate, return -EIO.
|
||||
*/
|
||||
struct page *read_cache_page_async(struct address_space *mapping,
|
||||
static struct page *do_read_cache_page(struct address_space *mapping,
|
||||
pgoff_t index,
|
||||
int (*filler)(void *,struct page*),
|
||||
void *data)
|
||||
void *data,
|
||||
gfp_t gfp)
|
||||
|
||||
{
|
||||
struct page *page;
|
||||
int err;
|
||||
|
||||
retry:
|
||||
page = __read_cache_page(mapping, index, filler, data);
|
||||
page = __read_cache_page(mapping, index, filler, data, gfp);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
if (PageUptodate(page))
|
||||
|
@ -1710,8 +1698,67 @@ out:
|
|||
mark_page_accessed(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_cache_page_async - read into page cache, fill it if needed
|
||||
* @mapping: the page's address_space
|
||||
* @index: the page index
|
||||
* @filler: function to perform the read
|
||||
* @data: destination for read data
|
||||
*
|
||||
* Same as read_cache_page, but don't wait for page to become unlocked
|
||||
* after submitting it to the filler.
|
||||
*
|
||||
* Read into the page cache. If a page already exists, and PageUptodate() is
|
||||
* not set, try to fill the page but don't wait for it to become unlocked.
|
||||
*
|
||||
* If the page does not get brought uptodate, return -EIO.
|
||||
*/
|
||||
struct page *read_cache_page_async(struct address_space *mapping,
|
||||
pgoff_t index,
|
||||
int (*filler)(void *,struct page*),
|
||||
void *data)
|
||||
{
|
||||
return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping));
|
||||
}
|
||||
EXPORT_SYMBOL(read_cache_page_async);
|
||||
|
||||
static struct page *wait_on_page_read(struct page *page)
|
||||
{
|
||||
if (!IS_ERR(page)) {
|
||||
wait_on_page_locked(page);
|
||||
if (!PageUptodate(page)) {
|
||||
page_cache_release(page);
|
||||
page = ERR_PTR(-EIO);
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_cache_page_gfp - read into page cache, using specified page allocation flags.
|
||||
* @mapping: the page's address_space
|
||||
* @index: the page index
|
||||
* @gfp: the page allocator flags to use if allocating
|
||||
*
|
||||
* This is the same as "read_mapping_page(mapping, index, NULL)", but with
|
||||
* any new page allocations done using the specified allocation flags. Note
|
||||
* that the Radix tree operations will still use GFP_KERNEL, so you can't
|
||||
* expect to do this atomically or anything like that - but you can pass in
|
||||
* other page requirements.
|
||||
*
|
||||
* If the page does not get brought uptodate, return -EIO.
|
||||
*/
|
||||
struct page *read_cache_page_gfp(struct address_space *mapping,
|
||||
pgoff_t index,
|
||||
gfp_t gfp)
|
||||
{
|
||||
filler_t *filler = (filler_t *)mapping->a_ops->readpage;
|
||||
|
||||
return wait_on_page_read(do_read_cache_page(mapping, index, filler, NULL, gfp));
|
||||
}
|
||||
EXPORT_SYMBOL(read_cache_page_gfp);
|
||||
|
||||
/**
|
||||
* read_cache_page - read into page cache, fill it if needed
|
||||
* @mapping: the page's address_space
|
||||
|
@ -1729,18 +1776,7 @@ struct page *read_cache_page(struct address_space *mapping,
|
|||
int (*filler)(void *,struct page*),
|
||||
void *data)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = read_cache_page_async(mapping, index, filler, data);
|
||||
if (IS_ERR(page))
|
||||
goto out;
|
||||
wait_on_page_locked(page);
|
||||
if (!PageUptodate(page)) {
|
||||
page_cache_release(page);
|
||||
page = ERR_PTR(-EIO);
|
||||
}
|
||||
out:
|
||||
return page;
|
||||
return wait_on_page_read(read_cache_page_async(mapping, index, filler, data));
|
||||
}
|
||||
EXPORT_SYMBOL(read_cache_page);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче