afs: Make afs_readpages() fetch data in bulk

Make afs_readpages() use afs_vnode_fetch_data()'s new ability to take a
list of pages and do a bulk fetch.

Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2017-01-05 10:38:35 +00:00
Родитель 196ee9cd2d
Коммит 91b467e0a3
2 изменённых файлов: 130 добавлений и 2 удалений

Просмотреть файл

@ -16,6 +16,7 @@
#include <linux/pagemap.h>
#include <linux/writeback.h>
#include <linux/gfp.h>
#include <linux/task_io_accounting_ops.h>
#include "internal.h"
static int afs_readpage(struct file *file, struct page *page);
@ -261,6 +262,129 @@ static int afs_readpage(struct file *file, struct page *page)
return ret;
}
/*
* Make pages available as they're filled.
*/
static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req)
{
struct afs_vnode *vnode = call->reply;
struct page *page = req->pages[req->index];
req->pages[req->index] = NULL;
SetPageUptodate(page);
/* send the page to the cache */
#ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page) &&
fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) {
fscache_uncache_page(vnode->cache, page);
BUG_ON(PageFsCache(page));
}
#endif
unlock_page(page);
put_page(page);
}
/*
* Read a contiguous set of pages.
*/
static int afs_readpages_one(struct file *file, struct address_space *mapping,
struct list_head *pages)
{
struct afs_vnode *vnode = AFS_FS_I(mapping->host);
struct afs_read *req;
struct list_head *p;
struct page *first, *page;
struct key *key = file->private_data;
pgoff_t index;
int ret, n, i;
/* Count the number of contiguous pages at the front of the list. Note
* that the list goes prev-wards rather than next-wards.
*/
first = list_entry(pages->prev, struct page, lru);
index = first->index + 1;
n = 1;
for (p = first->lru.prev; p != pages; p = p->prev) {
page = list_entry(p, struct page, lru);
if (page->index != index)
break;
index++;
n++;
}
req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *) * n,
GFP_NOFS);
if (!req)
return -ENOMEM;
atomic_set(&req->usage, 1);
req->page_done = afs_readpages_page_done;
req->pos = first->index;
req->pos <<= PAGE_SHIFT;
/* Transfer the pages to the request. We add them in until one fails
* to add to the LRU and then we stop (as that'll make a hole in the
* contiguous run.
*
* Note that it's possible for the file size to change whilst we're
* doing this, but we rely on the server returning less than we asked
* for if the file shrank. We also rely on this to deal with a partial
* page at the end of the file.
*/
do {
page = list_entry(pages->prev, struct page, lru);
list_del(&page->lru);
index = page->index;
if (add_to_page_cache_lru(page, mapping, index,
readahead_gfp_mask(mapping))) {
#ifdef CONFIG_AFS_FSCACHE
fscache_uncache_page(vnode->cache, page);
#endif
put_page(page);
break;
}
req->pages[req->nr_pages++] = page;
req->len += PAGE_SIZE;
} while (req->nr_pages < n);
if (req->nr_pages == 0) {
kfree(req);
return 0;
}
ret = afs_vnode_fetch_data(vnode, key, req);
if (ret < 0)
goto error;
task_io_account_read(PAGE_SIZE * req->nr_pages);
afs_put_read(req);
return 0;
error:
if (ret == -ENOENT) {
_debug("got NOENT from server"
" - marking file deleted and stale");
set_bit(AFS_VNODE_DELETED, &vnode->flags);
ret = -ESTALE;
}
for (i = 0; i < req->nr_pages; i++) {
page = req->pages[i];
if (page) {
#ifdef CONFIG_AFS_FSCACHE
fscache_uncache_page(vnode->cache, page);
#endif
SetPageError(page);
unlock_page(page);
}
}
afs_put_read(req);
return ret;
}
/*
* read a set of pages
*/
@ -314,8 +438,11 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
return ret;
}
/* load the missing pages from the network */
ret = read_cache_pages(mapping, pages, afs_page_filler, key);
while (!list_empty(pages)) {
ret = afs_readpages_one(file, mapping, pages);
if (ret < 0)
break;
}
_leave(" = %d [netting]", ret);
return ret;

Просмотреть файл

@ -106,6 +106,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)
volume->cell = params->cell;
volume->vid = vlocation->vldb.vid[params->type];
volume->bdi.ra_pages = VM_MAX_READAHEAD*1024/PAGE_SIZE;
ret = bdi_setup_and_register(&volume->bdi, "afs");
if (ret)
goto error_bdi;