Re: [RFC][PATCH] 9p: add readahead support for loose mode

2007-09-16 Thread Peter Zijlstra
On Sat, 15 Sep 2007 03:41:26 -0700 Andrew Morton
[EMAIL PROTECTED] wrote:

 eww, kmap.  Large amounts of them, apparently.
 
 Be aware that kmap is a) slow and b) deadlockable.  The latter happens when
 multiple tasks want to take more than one kmap simultaneously: they all
 wait for someone else to release one.  Your code here seems especially
 vulnerable to this.
 
 Nick had a kmap-speedup patchset a while back which addressed a) but I
 don't know if it addressed the deadlock.  But that patch seemed to die.

That would've been me.

What I did to address b) is to pre-allocate each kmap user a second
kmap slot. Of course this isn't water-tight either.

These patches are part of -rt, I could respin against mainline if there
is interest.
-
To unsubscribe from this list: send the line unsubscribe linux-fsdevel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC][PATCH] 9p: add readahead support for loose mode

2007-09-15 Thread Andrew Morton
On Fri, 14 Sep 2007 11:02:40 -0500 Eric Van Hensbergen [EMAIL PROTECTED] 
wrote:

 + 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);
 + }

eww, kmap.  Large amounts of them, apparently.

Be aware that kmap is a) slow and b) deadlockable.  The latter happens when
multiple tasks want to take more than one kmap simultaneously: they all
wait for someone else to release one.  Your code here seems especially
vulnerable to this.

Nick had a kmap-speedup patchset a while back which addressed a) but I
don't know if it addressed the deadlock.  But that patch seemed to die.

Strongly recommend that the code be reworked to use kmap_atomic()


-
To unsubscribe from this list: send the line unsubscribe linux-fsdevel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[RFC][PATCH] 9p: add readahead support for loose mode

2007-09-14 Thread Eric Van Hensbergen
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,