read combining patch
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 3 Nov 2003 19:32:14 +0000 (19:32 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 3 Nov 2003 19:32:14 +0000 (19:32 +0000)
ChangeLog
include/linux/fuse.h
kernel/file.c
kernel/fuse_i.h

index 7968b9151b0689d351772768109a75a1af037279..ee76377cf5b03c224c6fb665f1cf5773d398c71e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-11-03  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+       * Applied read combining patch by Michael Grigoriev (tested by
+       Valient Gough and Vincent Wagelaar)
+
 2003-10-22  Miklos Szeredi <mszeredi@inf.bme.hu>
 
        * Mtab handling fix in fusermount by "Valient Gough" (SF patch
index 507d8729c009a6028134c16908ea31a5c131a2a9..4be9a283a161b396f1d0bba52b320da844949c15 100644 (file)
 /** Opening this will yield a new control file */
 #define FUSE_DEV "/proc/fs/fuse/dev"
 
+/** Read combining parameters */
+#define FUSE_BLOCK_SHIFT 16
+#define FUSE_BLOCK_SIZE 65536
+#define FUSE_BLOCK_MASK 0xffff0000
+
 /** Data passed to mount */
 struct fuse_mount_data {
        /** Must be set to FUSE_KERNEL_VERSION */
index 68bf66081e1081e19d0a80d9fb37ea4d81b2a315..fe83c19de815f44e595c99a668e7679de767bafb 100644 (file)
@@ -112,6 +112,134 @@ static int fuse_readpage(struct file *file, struct page *page)
        return out.h.error;
 }
 
+static int fuse_is_block_uptodate(struct address_space *mapping,
+               struct inode *inode, size_t bl_index)
+{
+       size_t index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
+       size_t end_index = ((bl_index + 1) << FUSE_BLOCK_PAGE_SHIFT) - 1;
+       size_t file_end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+       if (end_index > file_end_index)
+               end_index = file_end_index;
+
+       for (; index <= end_index; index++) {
+               struct page *page = find_get_page(mapping, index);
+
+               if (!page)
+                       return 0;
+
+               if (!Page_Uptodate(page)) {
+                       page_cache_release(page);
+                       return 0;
+               }
+
+               page_cache_release(page);
+       }
+
+       return 1;
+}
+
+
+static int fuse_cache_block(struct address_space *mapping,
+               struct inode *inode, char *bl_buf,
+               size_t bl_index)
+{
+       size_t start_index = bl_index << FUSE_BLOCK_PAGE_SHIFT;
+       size_t end_index = ((bl_index + 1) << FUSE_BLOCK_PAGE_SHIFT) - 1;
+       size_t file_end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+       int i, error = 0;
+
+       if (end_index > file_end_index)
+               end_index = file_end_index;
+
+       for (i = 0; start_index + i <= end_index; i++) {
+               size_t index = start_index + i;
+               struct page *page;
+               char *buffer;
+
+               page = find_or_create_page(mapping, index, GFP_NOFS);
+
+               if (!Page_Uptodate(page)) {
+                       buffer = kmap(page);
+                       memcpy(buffer, bl_buf + i * PAGE_CACHE_SIZE,
+                                       PAGE_CACHE_SIZE);
+                       SetPageUptodate(page);
+                       kunmap(page);
+               }
+
+               UnlockPage(page);
+               page_cache_release(page);
+       }
+
+       return error;
+} 
+
+static int fuse_file_read_block(struct inode *inode, char *bl_buf,
+               size_t bl_index)
+{
+       struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_in in = FUSE_IN_INIT;
+       struct fuse_out out = FUSE_OUT_INIT;
+       struct fuse_read_in inarg;
+
+       memset(&inarg, 0, sizeof(inarg));
+       inarg.offset = bl_index << FUSE_BLOCK_SHIFT;
+       inarg.size = FUSE_BLOCK_SIZE;
+
+       in.h.opcode = FUSE_READ;
+       in.h.ino = inode->i_ino;
+       in.numargs = 1;
+       in.args[0].size = sizeof(inarg);
+       in.args[0].value = &inarg;
+       out.argvar = 1;
+       out.numargs = 1;
+       out.args[0].size = FUSE_BLOCK_SIZE;
+       out.args[0].value = bl_buf;
+
+       request_send(fc, &in, &out);
+
+       if (!out.h.error) {
+               size_t outsize = out.args[0].size;
+               if (outsize < FUSE_BLOCK_SIZE)
+                       memset(bl_buf + outsize, 0, FUSE_BLOCK_SIZE - outsize);
+       }
+
+       return out.h.error;
+}   
+
+static ssize_t fuse_file_read(struct file *filp, char *buf,
+               size_t count, loff_t * ppos)
+{
+       struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
+       struct inode *inode = mapping->host;
+
+       size_t bl_index = *ppos >> FUSE_BLOCK_SHIFT;
+       size_t bl_end_index = (*ppos + count) >> FUSE_BLOCK_SHIFT;
+       size_t bl_file_end_index = inode->i_size >> FUSE_BLOCK_SHIFT;
+
+       if (bl_end_index > bl_file_end_index)
+               bl_end_index = bl_file_end_index;
+
+       while (bl_index <= bl_end_index) {
+               char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
+
+               int res = fuse_is_block_uptodate(mapping, inode, bl_index);
+
+               if (!res)
+                       res = fuse_file_read_block(inode, bl_buf, bl_index);
+
+               if (!res)
+                       fuse_cache_block(mapping, inode, bl_buf, bl_index);
+
+               kfree(bl_buf);
+
+               bl_index++;
+       }
+
+       return generic_file_read(filp, buf, count, ppos);
+}  
+
 static int write_buffer(struct inode *inode, struct page *page,
                        unsigned offset, size_t count)
 {
@@ -192,7 +320,7 @@ static int fuse_commit_write(struct file *file, struct page *page,
 static struct file_operations fuse_file_operations = {
        open:           fuse_open,
        release:        fuse_release,
-       read:           generic_file_read,
+       read:           fuse_file_read,
        write:          generic_file_write,
        mmap:           generic_file_mmap,
 };
index 577681d5a74a6f8eaad3ce9dabb4d30c25416828..5a4a8b7d2ef9896757220508cb36943b10d62538 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
+#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
+
 
 /**
  * A Fuse connection.