summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-08-23 17:04:05 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2020-05-06 17:14:15 -0400
commit0aecf705738551bc43e6ee2a948fb91b855309b0 (patch)
tree6e5d06260965d2ac50a26c54f56b8da96c8f0b2f
parent5eb2111fca77777e9e211adfa59d48515520b295 (diff)
add_to_page_cache_lru_vec()
-rw-r--r--include/linux/pagemap.h5
-rw-r--r--mm/filemap.c67
2 files changed, 57 insertions, 15 deletions
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index b61fab5a1317..90f74071d678 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -617,6 +617,11 @@ int add_to_page_cache(struct page *page, struct address_space *mapping,
pgoff_t index, gfp_t gfp_mask);
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
pgoff_t index, gfp_t gfp_mask);
+int add_to_page_cache_lru_vec(struct address_space *mapping,
+ struct page **pages,
+ unsigned nr_pages,
+ pgoff_t offset, gfp_t gfp_mask);
+
extern void delete_from_page_cache(struct page *page);
extern void __delete_from_page_cache(struct page *page, void *shadow);
int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask);
diff --git a/mm/filemap.c b/mm/filemap.c
index b82fd3be69ca..37e16bd7b0fd 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1063,16 +1063,26 @@ int add_to_page_cache(struct page *page, struct address_space *mapping,
}
EXPORT_SYMBOL(add_to_page_cache);
-int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
- pgoff_t offset, gfp_t gfp_mask)
+int add_to_page_cache_lru_vec(struct address_space *mapping,
+ struct page **pages,
+ unsigned nr_pages,
+ pgoff_t offset, gfp_t gfp_mask)
{
- void *shadow = NULL;
- int ret;
+ void *shadow_stack[8], **shadow = shadow_stack;
+ int i, ret = 0, err = 0, nr_added;
- ret = add_to_page_cache_vec(&page, 1, mapping, offset,
- gfp_mask, &shadow);
- if (unlikely(ret))
- return ret;
+ if (nr_pages > ARRAY_SIZE(shadow_stack)) {
+ shadow = kmalloc_array(nr_pages, sizeof(void *), gfp_mask);
+ if (!shadow)
+ goto slowpath;
+ }
+
+ for (i = 0; i < nr_pages; i++)
+ VM_BUG_ON_PAGE(PageActive(pages[i]), pages[i]);
+
+ ret = add_to_page_cache_vec(pages, nr_pages, mapping,
+ offset, gfp_mask, shadow);
+ nr_added = ret > 0 ? ret : 0;
/*
* The page might have been evicted from cache only recently, in which
@@ -1081,13 +1091,40 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
* the working set, only to cache data that will get overwritten with
* something else, is a waste of memory.
*/
- if (!(gfp_mask & __GFP_WRITE) &&
- shadow && workingset_refault(shadow)) {
- SetPageActive(page);
- workingset_activation(page);
- } else
- ClearPageActive(page);
- lru_cache_add(page);
+ for (i = 0; i < nr_added; i++) {
+ struct page *page = pages[i];
+ void *s = shadow[i];
+
+ if (!(gfp_mask & __GFP_WRITE) &&
+ s && workingset_refault(s)) {
+ SetPageActive(page);
+ workingset_activation(page);
+ }
+ lru_cache_add(page);
+ }
+
+ if (shadow != shadow_stack)
+ kfree(shadow);
+
+ return ret;
+slowpath:
+ for (i = 0; i < nr_pages; i++) {
+ err = add_to_page_cache_lru(pages[i], mapping,
+ offset + i, gfp_mask);
+ if (err)
+ break;
+ }
+
+ return i ?: err;
+}
+EXPORT_SYMBOL_GPL(add_to_page_cache_lru_vec);
+
+int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
+ pgoff_t offset, gfp_t gfp_mask)
+{
+ int ret = add_to_page_cache_lru_vec(mapping, &page, 1, offset, gfp_mask);
+ if (ret < 0)
+ return ret;
return 0;
}
EXPORT_SYMBOL_GPL(add_to_page_cache_lru);