This patch adds readpages support in support of readahead when using loose
cache mode. It substantially increases performance for certain workloads.
Signed-off-by: Eric Van Hensbergen [EMAIL PROTECTED]
---
fs/9p/v9fs.c|2 +-
fs/9p/vfs_addr.c| 98 ++
include/net/9p/client.h |3 +-
net/9p/client.c | 82 +--
4 files changed, 143 insertions(+), 42 deletions(-)
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 89ee0ba..ca97404 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -131,7 +131,7 @@ static void v9fs_parse_options(struct v9fs_session_info
*v9ses)
char *s, *e;
/* setup defaults */
- v9ses-maxdata = 8192;
+ v9ses-maxdata = (64*1024);
v9ses-afid = ~0;
v9ses-debug = 0;
v9ses-cache = 0;
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 6248f0e..86c6e0d 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -31,8 +31,11 @@
#include linux/string.h
#include linux/inet.h
#include linux/pagemap.h
+#include linux/pagevec.h
#include linux/idr.h
#include linux/sched.h
+#include linux/uio.h
+#include linux/task_io_accounting_ops.h
#include net/9p/9p.h
#include net/9p/client.h
@@ -50,31 +53,108 @@
static int v9fs_vfs_readpage(struct file *filp, struct page *page)
{
- int retval;
loff_t offset;
char *buffer;
struct p9_fid *fid;
+ int retval = 0;
+ int total = 0;
+ int count = PAGE_SIZE;
P9_DPRINTK(P9_DEBUG_VFS, \n);
fid = filp-private_data;
buffer = kmap(page);
offset = page_offset(page);
- retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE);
- if (retval 0)
- goto done;
+ while (count) {
+ struct kvec kv = {buffer+offset, PAGE_SIZE-count};
+ retval = p9_client_readv(fid, kv, offset, 1);
+ if (retval = 0)
+ break;
- memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval);
- flush_dcache_page(page);
- SetPageUptodate(page);
- retval = 0;
+ buffer += retval;
+ offset += retval;
+ count -= retval;
+ total += retval;
+ }
+
+ if (retval = 0) {
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ retval = 0;
+ }
-done:
kunmap(page);
unlock_page(page);
return retval;
}
+/* large chunks copied and adapted from fs/cifs/file.c */
+static int v9fs_vfs_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *page_list, unsigned num_pages)
+{
+ struct page *tmp_page;
+ loff_t offset;
+ struct pagevec lru_pvec;
+ struct p9_fid *fid;
+ u32 read_size;
+ int retval = 0;
+ unsigned int count = 0;
+ struct list_head *p, *n;
+
+ struct kvec *kv = kmalloc(sizeof(struct kvec)*num_pages, GFP_KERNEL);
+
+ P9_DPRINTK(P9_DEBUG_VFS, %d pages\n, num_pages);
+
+ if (!kv)
+ return -ENOMEM;
+
+ if (list_empty(page_list))
+ goto free_vec;
+
+ pagevec_init(lru_pvec, 0);
+
+ fid = file-private_data;
+ tmp_page = list_entry(page_list-prev, struct page, lru);
+ offset = (loff_t)tmp_page-index PAGE_CACHE_SHIFT;
+
+ list_for_each_entry_reverse(tmp_page, page_list, lru) {
+ BUG_ON(count num_pages);
+ if (add_to_page_cache(tmp_page, mapping,
+ tmp_page-index, GFP_KERNEL)) {
+ page_cache_release(tmp_page);
+ continue;
+ }
+
+ kv[count].iov_base = kmap(tmp_page);
+ kv[count].iov_len = PAGE_CACHE_SIZE;
+ count++;
+ }
+
+ read_size = count * PAGE_CACHE_SIZE;
+ if (!read_size)
+ goto cleanup;
+
+ retval = p9_client_readv(fid, kv, offset, count);
+
+cleanup:
+ list_for_each_safe(p, n, page_list) {
+ tmp_page = list_entry(p, struct page, lru);
+ list_del(tmp_page-lru);
+ if (!pagevec_add(lru_pvec, tmp_page))
+ __pagevec_lru_add(lru_pvec);
+ kunmap(tmp_page);
+ flush_dcache_page(tmp_page);
+ SetPageUptodate(tmp_page);
+ unlock_page(tmp_page);
+ }
+ pagevec_lru_add(lru_pvec);
+
+free_vec:
+ kfree(kv);
+ return retval;
+}
+
const struct address_space_operations v9fs_addr_operations = {
.readpage = v9fs_vfs_readpage,
+ .readpages = v9fs_vfs_readpages,
};
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 9b9221a..6f17d0a 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -67,8 +67,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32
perm, int mode,