diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-08-23 17:04:05 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2020-05-06 17:14:15 -0400 |
commit | 0aecf705738551bc43e6ee2a948fb91b855309b0 (patch) | |
tree | 6e5d06260965d2ac50a26c54f56b8da96c8f0b2f | |
parent | 5eb2111fca77777e9e211adfa59d48515520b295 (diff) |
add_to_page_cache_lru_vec()
-rw-r--r-- | include/linux/pagemap.h | 5 | ||||
-rw-r--r-- | mm/filemap.c | 67 |
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); |