cleanup
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 30 Nov 2004 18:25:20 +0000 (18:25 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 30 Nov 2004 18:25:20 +0000 (18:25 +0000)
ChangeLog
kernel/dev.c
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
kernel/util.c

index c9a090d55c847cb479ca30b69c559e53d6118c4f..441669bf1fd9d6b79802d96186286139e939d2c3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-11-30  Miklos Szeredi <miklos@szeredi.hu>
+
+       * kernel: clean up reading functions
+
 2004-11-29  Miklos Szeredi <miklos@szeredi.hu>
 
        * kernel: make readpage() uninterruptible
index 0eebd3155f5959bdcad66467ab9a48575b7dff6c..aca602f5d6d1da21f565914037b7792d6db981de 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/proc_fs.h>
 #endif
 #include <linux/miscdevice.h>
+#include <linux/pagemap.h>
 #include <linux/file.h>
 
 static kmem_cache_t *fuse_req_cachep;
@@ -169,10 +170,9 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req)
 }
 
 void request_send_async(struct fuse_conn *fc, struct fuse_req *req, 
-                          fuse_reqend_t end, void *data)
+                       fuse_reqend_t end)
 {
        req->end = end;
-       req->data = data;
        req->isreply = 1;
        
        spin_lock(&fuse_lock);
@@ -289,7 +289,7 @@ static ssize_t fuse_dev_read(struct file *file, char __user *buf,
        return ret;
 }
 
-static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique)
+static struct fuse_req *request_find(struct fuse_conn *fc, unsigned unique)
 {
        struct list_head *entry;
        struct fuse_req *req = NULL;
@@ -312,6 +312,37 @@ static void process_getdir(struct fuse_req *req)
        arg->file = fget(arg->fd);
 }
 
+static int copy_out_pages(struct fuse_req *req, const char __user *buf,
+                         size_t nbytes)
+{
+       unsigned count;
+       unsigned page_offset;
+       unsigned zeroing = req->out.page_zeroing;
+       unsigned i;
+       
+       req->out.args[0].size = nbytes;
+       page_offset = req->page_offset;
+       count = min(nbytes, (unsigned) PAGE_CACHE_SIZE - page_offset);
+       for (i = 0; i < req->num_pages && (zeroing || nbytes); i++) {
+               struct page *page = req->pages[i];
+               char *tmpbuf = kmap(page);
+               int err = 0;
+               if (count < PAGE_CACHE_SIZE && zeroing)
+                       memset(tmpbuf, 0, PAGE_CACHE_SIZE);
+               if (count)
+                       err = copy_from_user(tmpbuf + page_offset, buf, count);
+               flush_dcache_page(page);
+               kunmap(page);
+               if (err)
+                       return -EFAULT;
+               nbytes -= count;
+               buf += count;
+               count = min(nbytes, (unsigned) PAGE_CACHE_SIZE);
+               page_offset = 0;
+       }
+       return 0;
+}
+
 static inline int copy_out_one(struct fuse_out_arg *arg,
                               const char __user **srcp,
                               size_t *srclenp, int allowvar)
@@ -346,9 +377,10 @@ static inline int copy_out_args(struct fuse_req *req, const char __user *buf,
        nbytes -= sizeof(struct fuse_out_header);
                
        if (!out->h.error) {
-               if (req->copy_out)
-                       return req->copy_out(req, buf, nbytes);
-               else {
+               if (out->argpages) {
+                       if (nbytes <= out->args[0].size)
+                               return copy_out_pages(req, buf, nbytes);
+               } else {
                        for (i = 0; i < out->numargs; i++) {
                                struct fuse_out_arg *arg = &out->args[i];
                                int allowvar;
@@ -489,17 +521,17 @@ static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
        /* Unlocks fuse_lock: */
        request_end(fc, req);
 
 out:
+ out:
        if (!err)
                return nbytes;
        else
                return err;
 }
 
-static unsigned int fuse_dev_poll(struct file *file, poll_table *wait)
+static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
 {
        struct fuse_conn *fc = fuse_get_conn(file);
-       unsigned int mask = POLLOUT | POLLWRNORM;
+       unsigned mask = POLLOUT | POLLWRNORM;
 
        if (!fc)
                return -ENODEV;
@@ -605,7 +637,7 @@ static void fuse_version_clean(void)
 static struct proc_dir_entry *proc_fs_fuse;
 
 static int read_version(char *page, char **start, off_t off, int count,
-                          int *eof, void *data)
+                       int *eof, void *data)
 {
        char *s = page;
        s += sprintf(s, "%i.%i\n", FUSE_KERNEL_VERSION,
index 19834b43c34dc87905497aa97594c4efd3f7e16e..412ffc88ddd91d12c746ace6d536efc38af763a9 100644 (file)
@@ -389,7 +389,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
        struct fuse_inode *fi = INO_FI(dir);
        struct fuse_req *req;
        struct fuse_entry_out outarg;
-       unsigned int len = strlen(link) + 1;
+       unsigned len = strlen(link) + 1;
        int err;
        
        if (len > FUSE_SYMLINK_MAX)
@@ -619,7 +619,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
 #ifdef KERNEL_2_6_10_PLUS
                                err = generic_permission(inode, mask, NULL);
 #else
-                               err = vfs_permission(inode, mask);
+                               err = vfs_permission(inode, mask);
 #endif
                }
 
@@ -659,7 +659,7 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
                        break;
 
                over = filldir(dstbuf, dirent->name, dirent->namelen,
-                             file->f_pos, dirent->ino, dirent->type);
+                              file->f_pos, dirent->ino, dirent->type);
                if (over)
                        break;
 
@@ -820,11 +820,10 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static unsigned int iattr_to_fattr(struct iattr *iattr,
-                                  struct fuse_attr *fattr)
+static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
 {
-       unsigned int ivalid = iattr->ia_valid;
-       unsigned int fvalid = 0;
+       unsigned ivalid = iattr->ia_valid;
+       unsigned fvalid = 0;
        
        memset(fattr, 0, sizeof(*fattr));
        
@@ -962,7 +961,7 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
 }
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
-                                  struct nameidata *nd)
+                                 struct nameidata *nd)
 {
        struct inode *inode;
        int err = fuse_lookup_iget(dir, entry, &inode);
@@ -993,7 +992,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 }
 
 static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
-                     int rdev)
+                         int rdev)
 {
        return fuse_mknod(dir, entry, mode, rdev);
 }
index 0676135b0a479070bccc2e92de74a2b0e76862ec..2d15c5bb8344b7bcc32872a88e0839aae56a4605 100644 (file)
@@ -5,6 +5,7 @@
     This program can be distributed under the terms of the GNU GPL.
     See the file COPYING.
 */
+
 #include "fuse_i.h"
 
 #include <linux/pagemap.h>
@@ -221,104 +222,58 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        return err;
 }
 
-static ssize_t fuse_send_read(struct file *file, struct inode *inode,
-                             char *buf, loff_t pos, size_t count)
+static void fuse_read_init(struct fuse_req *req, struct file *file,
+                          struct inode *inode, loff_t pos, size_t count)
 {
-       struct fuse_conn *fc = INO_FC(inode);
        struct fuse_inode *fi = INO_FI(inode);
        struct fuse_file *ff = file->private_data;
-       struct fuse_req *req;
-       struct fuse_read_in inarg;
-       ssize_t res;
-       
-       req = fuse_get_request_nonint(fc);
-       memset(&inarg, 0, sizeof(inarg));
-       inarg.fh = ff->fh;
-       inarg.offset = pos;
-       inarg.size = count;
+       struct fuse_read_in *inarg = &req->misc.read_in;
+
+       inarg->fh = ff->fh;
+       inarg->offset = pos;
+       inarg->size = count;
        req->in.h.opcode = FUSE_READ;
        req->in.h.nodeid = fi->nodeid;
        req->in.numargs = 1;
-       req->in.args[0].size = sizeof(inarg);
-       req->in.args[0].value = &inarg;
+       req->in.args[0].size = sizeof(struct fuse_read_in);
+       req->in.args[0].value = inarg;
        req->out.argvar = 1;
        req->out.numargs = 1;
        req->out.args[0].size = count;
-       req->out.args[0].value = buf;
-       request_send(fc, req);
-       res = req->out.h.error;
-       if (!res)
-               res = req->out.args[0].size;
-       fuse_put_request(fc, req);
-       return res;
 }
 
 static int fuse_readpage(struct file *file, struct page *page)
 {
        struct inode *inode = page->mapping->host;
-       char *buffer;
-       ssize_t res;
-       loff_t pos;
-
-       pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
-       buffer = kmap(page);
-       res = fuse_send_read(file, inode, buffer, pos, PAGE_CACHE_SIZE);
-       if (res >= 0) {
-               if (res < PAGE_CACHE_SIZE) 
-                       memset(buffer + res, 0, PAGE_CACHE_SIZE - res);
-               flush_dcache_page(page);
+       struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_req *req = fuse_get_request_nonint(fc);
+       loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
+       int err;
+       
+       fuse_read_init(req, file, inode, pos, PAGE_CACHE_SIZE);
+       req->out.argpages = 1;
+       req->out.page_zeroing = 1;
+       req->num_pages = 1;
+       req->pages[0] = page;
+       request_send(fc, req);
+       err = req->out.h.error;
+       fuse_put_request(fc, req);
+       if (!err)
                SetPageUptodate(page);
-               res = 0;
-       }
-       kunmap(page);
        unlock_page(page);
-       return res;
+       return err;
 }
 
 #ifdef KERNEL_2_6
-static int read_pages_copyout(struct fuse_req *req, const char __user *buf,
-                             size_t nbytes)
+static void read_pages_end(struct fuse_conn *fc, struct fuse_req *req)
 {
        unsigned i;
-       unsigned long base_index = req->pages[0]->index;
        for (i = 0; i < req->num_pages; i++) {
                struct page *page = req->pages[i];
-               unsigned long offset;
-               unsigned count;
-               char *tmpbuf;
-               int err;
-
-               offset = (page->index - base_index) * PAGE_CACHE_SIZE;
-               if (offset >= nbytes)
-                       count = 0;
-               else if (offset + PAGE_CACHE_SIZE <= nbytes)
-                       count = PAGE_CACHE_SIZE;
-               else
-                       count = nbytes - offset;
-
-               tmpbuf = kmap(page);
-               err = 0;
-               if (count)
-                       err = copy_from_user(tmpbuf, buf + offset, count);
-               if (count < PAGE_CACHE_SIZE)
-                       memset(tmpbuf + count, 0, PAGE_CACHE_SIZE - count);
-               kunmap(page);
-               if (err)
-                       return -EFAULT;
-
-               flush_dcache_page(page);
-               SetPageUptodate(page);
+               if (!req->out.h.error)
+                       SetPageUptodate(page);
+               unlock_page(page);
        }
-       return 0;
-}
-
-static void read_pages_end(struct fuse_conn *fc, struct fuse_req *req)
-{
-       unsigned i;
-
-       for (i = 0; i < req->num_pages; i++)
-               unlock_page(req->pages[i]);
-       
        fuse_put_request(fc, req);
 }
 
@@ -326,28 +281,12 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file,
                                struct inode *inode)
 {
        struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_inode *fi = INO_FI(inode);
-       struct fuse_file *ff = file->private_data;
-       struct fuse_read_in *inarg;
-       loff_t pos;
-       unsigned numpages;
-       
-       pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
-       /* Allow for holes between the pages */
-       numpages = req->pages[req->num_pages - 1]->index + 1 
-               - req->pages[0]->index;
-       
-       inarg = &req->misc.read_in;
-       inarg->fh = ff->fh;
-       inarg->offset = pos;
-       inarg->size = numpages * PAGE_CACHE_SIZE;
-       req->in.h.opcode = FUSE_READ;
-       req->in.h.nodeid = fi->nodeid;
-       req->in.numargs = 1;
-       req->in.args[0].size = sizeof(struct fuse_read_in);
-       req->in.args[0].value = inarg;
-       req->copy_out = read_pages_copyout;
-       request_send_async(fc, req, read_pages_end, NULL);
+       loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
+       size_t count = req->num_pages << PAGE_CACHE_SHIFT;
+       fuse_read_init(req, file, inode, pos, count);
+       req->out.argpages = 1;
+       req->out.page_zeroing = 1;
+       request_send_async(fc, req, read_pages_end);
 }
 
 struct fuse_readpages_data {
@@ -396,133 +335,105 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
        return 0;
 }
 #else /* KERNEL_2_6 */
-static int fuse_is_block_uptodate(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 = i_size_read(inode) >> PAGE_CACHE_SHIFT;
+#define FUSE_BLOCK_SHIFT 16
+#define FUSE_BLOCK_SIZE (1UL << FUSE_BLOCK_SHIFT)
+#define FUSE_BLOCK_MASK (~(FUSE_BLOCK_SIZE-1))
+#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
+#error FUSE_BLOCK_SHIFT too large
+#endif
 
-       if (end_index > file_end_index)
-               end_index = file_end_index;
+static int fuse_is_block_uptodate(struct inode *inode, unsigned start,
+                                 unsigned end)
+{
+       int index;
 
-       for (; index <= end_index; index++) {
+       for (index = start; index < end; index++) {
                struct page *page = find_get_page(inode->i_mapping, index);
-
                if (!page)
                        return 0;
-
                if (!PageUptodate(page)) {
                        page_cache_release(page);
                        return 0;
                }
-
                page_cache_release(page);
        }
-
        return 1;
 }
 
-
-static int fuse_cache_block(struct inode *inode, char *bl_buf,
-                           size_t bl_index)
+static void fuse_file_read_block(struct fuse_req *req, struct file *file,
+                                struct inode *inode, unsigned start,
+                                unsigned end)
 {
-       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 = i_size_read(inode) >> PAGE_CACHE_SHIFT;
-
+       struct fuse_conn *fc = INO_FC(inode);
+       loff_t pos;
+       size_t count;
+       int index;
+       int err = 1;
        int i;
 
-       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 = grab_cache_page(inode->i_mapping, index);
+       for (index = start; index < end; index++) {
+               struct page *page = grab_cache_page(inode->i_mapping, index);
                if (!page)
-                       return -1;
-
-               if (!PageUptodate(page)) {
-                       buffer = kmap(page);
-                       memcpy(buffer, bl_buf + i * PAGE_CACHE_SIZE,
-                                       PAGE_CACHE_SIZE);
-                       flush_dcache_page(page);
+                       goto out;
+               req->pages[req->num_pages++] = page;
+       }
+       pos = (loff_t) start << PAGE_CACHE_SHIFT;
+       count = req->num_pages << PAGE_CACHE_SHIFT;
+       fuse_read_init(req, file, inode, pos, count);
+       req->out.argpages = 1;
+       req->out.page_zeroing = 1;
+       request_send(fc, req);
+       err = req->out.h.error;
+ out:
+       for (i = 0; i < req->num_pages; i++) {
+               struct page *page = req->pages[i];
+               if (!err)
                        SetPageUptodate(page);
-                       kunmap(page);
-               }
-
                unlock_page(page);
                page_cache_release(page);
        }
-
-       return 0;
-} 
-
-static int fuse_file_read_block(struct file *file, struct inode *inode,
-                               char *bl_buf, size_t bl_index)
-{
-       ssize_t res;
-       loff_t offset;
-       
-       offset = (loff_t) bl_index << FUSE_BLOCK_SHIFT;
-       res = fuse_send_read(file, inode, bl_buf, offset, FUSE_BLOCK_SIZE);
-       if (res >= 0) {
-               if (res < FUSE_BLOCK_SIZE)
-                       memset(bl_buf + res, 0, FUSE_BLOCK_SIZE - res);
-               res = 0;
-       }
-       return res;
 }   
 
-static void fuse_file_bigread(struct file *file, struct inode *inode,
-                             loff_t pos, size_t count)
+static int fuse_file_bigread(struct file *file, struct inode *inode,
+                            loff_t pos, size_t count)
 {
-       size_t bl_index = pos >> FUSE_BLOCK_SHIFT;
-       size_t bl_end_index = (pos + count) >> FUSE_BLOCK_SHIFT;
-       size_t bl_file_end_index = i_size_read(inode) >> FUSE_BLOCK_SHIFT;
+       struct fuse_conn *fc = INO_FC(inode);
+       unsigned starti;
+       unsigned endi;
+       unsigned nexti;
+       struct fuse_req *req;
+       loff_t size = i_size_read(inode);
+       loff_t end = (pos + count + FUSE_BLOCK_SIZE - 1) & FUSE_BLOCK_MASK;
+       end = min(end, size);
+       if (end <= pos)
+               return 0;
+
+       starti = (pos & FUSE_BLOCK_MASK) >> PAGE_CACHE_SHIFT;
+       endi = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        
-       if (bl_end_index > bl_file_end_index)
-               bl_end_index = bl_file_end_index;
+       req = fuse_get_request(fc);
+       if (!req)
+               return -ERESTARTSYS;
        
-       while (bl_index <= bl_end_index) {
-               int res;
-               char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_KERNEL);
-               if (!bl_buf)
-                       break;
-               res = fuse_is_block_uptodate(inode, bl_index);
-               if (!res)
-                       res = fuse_file_read_block(file, inode, bl_buf,
-                                                  bl_index);
-               if (!res)
-                       fuse_cache_block(inode, bl_buf, bl_index);
-               kfree(bl_buf);
-               bl_index++;
+       for (; starti < endi; starti = nexti) {
+               nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
+               nexti = min(nexti, endi);
+               if (!fuse_is_block_uptodate(inode, starti, nexti)) {
+                       fuse_file_read_block(req, file, inode, starti, nexti);
+                       fuse_reset_request(req);
+               }
        }
+       fuse_put_request(fc, req);
+       return 0;
 }
 #endif /* KERNEL_2_6 */
 
-static int fuse_read_copyout(struct fuse_req *req, const char __user *buf,
-                            size_t nbytes)
+static void fuse_release_user_pages(struct fuse_req *req)
 {
-       struct fuse_read_in *inarg =  &req->misc.read_in;
-       unsigned count;
-       unsigned page_offset;
        unsigned i;
-       if (nbytes > inarg->size) {
-               printk("fuse: long read\n");
-               return -EPROTO;
-       }
-       req->out.args[0].size = nbytes;
-       page_offset = req->page_offset;
-       count = min(nbytes, (unsigned) PAGE_SIZE - page_offset);
-       for (i = 0; i < req->num_pages && nbytes; i++) {
-               struct page *page = req->pages[i];
-               char *buffer = kmap(page);
-               int err = copy_from_user(buffer + page_offset, buf, count);
-               flush_dcache_page(page);
-               kunmap(page);
+
+       for (i = 0; i < req->num_pages; i++) {
+               struct page *page = req->pages[i]; 
 #ifdef KERNEL_2_6
                set_page_dirty_lock(page);
 #else
@@ -530,80 +441,59 @@ static int fuse_read_copyout(struct fuse_req *req, const char __user *buf,
                set_page_dirty(page);
                unlock_page(page);
 #endif
-               if (err)
-                       return -EFAULT;
-               nbytes -= count;
-               buf += count;
-               count = min(nbytes, (unsigned) PAGE_SIZE);
-               page_offset = 0;
+               page_cache_release(page);
        }
-       return 0;
 }
 
-static int fuse_send_read_multi(struct file *file, struct fuse_req *req,
-                                   size_t size, off_t pos)
+static int fuse_get_user_pages(struct fuse_req *req, char __user *buf,
+                              unsigned nbytes)
 {
-       struct inode *inode = file->f_dentry->d_inode;
-       struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_inode *fi = INO_FI(inode);
-       struct fuse_file *ff = file->private_data;
-       struct fuse_read_in *inarg;
-       
-       inarg = &req->misc.read_in;
-       inarg->fh = ff->fh;
-       inarg->offset = pos;
-       inarg->size = size;
-       req->in.h.opcode = FUSE_READ;
-       req->in.h.nodeid = fi->nodeid;
-       req->in.numargs = 1;
-       req->in.args[0].size = sizeof(struct fuse_read_in);
-       req->in.args[0].value = inarg;
-       req->copy_out = fuse_read_copyout;
-       request_send(fc, req);
-       return req->out.h.error;
+       unsigned long user_addr = (unsigned long) buf;
+       unsigned offset = user_addr & ~PAGE_CACHE_MASK;
+       int npages;
+
+       nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_CACHE_SHIFT);
+       npages = (nbytes + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+       npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
+       npages = get_user_pages(current, current->mm, user_addr, npages, 1, 0,
+                               req->pages, NULL);
+       if (npages < 0)
+               return npages;
+
+       req->num_pages = npages;
+       req->page_offset = offset;
+       return 0;
 }
 
-static ssize_t fuse_read(struct file *file, char __user *buf, size_t count,
-                        loff_t *ppos)
+static ssize_t fuse_direct_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
        loff_t pos = *ppos;
-       struct fuse_req *req;
-       ssize_t res;
-
-       req = fuse_get_request(fc);
+       ssize_t res = 0;
+       struct fuse_req *req = fuse_get_request(fc);
        if (!req)
                return -ERESTARTSYS;
 
-       res = 0;
        while (count) {
                unsigned nbytes = min(count, fc->max_read);
                unsigned nread;
-               unsigned long user_addr = (unsigned long) buf;
-               unsigned offset = user_addr & ~PAGE_MASK;
-               int npages;
-               int err;
-               int i;
-               
-               nbytes = min(nbytes, (unsigned) (FUSE_MAX_PAGES_PER_REQ * PAGE_SIZE));
-               npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
-               npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
-               npages = get_user_pages(current, current->mm, user_addr,
-                                       npages, 1, 0, req->pages, NULL);
-               if (npages < 0) {
-                       res = npages;
+               unsigned ntmp;
+               int err = fuse_get_user_pages(req, buf, nbytes);
+               if (err) {
+                       res = err;
                        break;
                }
-               req->num_pages = npages;
-               req->page_offset = offset;
-               nbytes = min(nbytes, (unsigned) (npages * PAGE_SIZE - offset));
-               err = fuse_send_read_multi(file, req, nbytes, pos);
-               for (i = 0; i < npages; i++)
-                       page_cache_release(req->pages[i]);
-               if (err) {
+               ntmp = (req->num_pages << PAGE_CACHE_SHIFT) - req->page_offset;
+               nbytes = min(nbytes, ntmp);
+               fuse_read_init(req, file, inode, pos, nbytes);
+               req->out.argpages = 1;
+               request_send(fc, req);
+               fuse_release_user_pages(req);
+               if (req->out.h.error) {
                        if (!res)
-                               res = err;
+                               res = req->out.h.error;
                        break;
                }
                nread = req->out.args[0].size;
@@ -629,20 +519,20 @@ static ssize_t fuse_file_read(struct file *file, char __user *buf,
        struct fuse_conn *fc = INO_FC(inode);
        ssize_t res;
 
-       if (fc->flags & FUSE_DIRECT_IO) {
-               res = fuse_read(file, buf, count, ppos);
-       }
+       if (fc->flags & FUSE_DIRECT_IO)
+               res = fuse_direct_read(file, buf, count, ppos);
        else {
 #ifndef KERNEL_2_6
                if (fc->flags & FUSE_LARGE_READ) {
                        down(&inode->i_sem);
-                       fuse_file_bigread(file, inode, *ppos, count);
+                       res = fuse_file_bigread(file, inode, *ppos, count);
                        up(&inode->i_sem);
+                       if (res)
+                               return res;
                }
 #endif
                res = generic_file_read(file, buf, count, ppos);
        }
-
        return res;
 }  
 
@@ -734,7 +624,7 @@ static int get_write_count(struct inode *inode, struct page *page)
 #ifdef KERNEL_2_6
 static void write_page_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-       struct page *page = req->data;
+       struct page *page = req->pages[0];
        struct inode *inode = page->mapping->host;
        struct fuse_inode *fi = INO_FI(inode);
        struct fuse_write_out *outarg = req->out.args[0].value;
@@ -788,7 +678,8 @@ static void fuse_send_writepage(struct fuse_req *req, struct inode *inode,
        req->out.numargs = 1;
        req->out.args[0].size = sizeof(struct fuse_write_out);
        req->out.args[0].value = &req->misc.write.out;
-       request_send_async(fc, req, write_page_end, page);
+       req->pages[0] = page;
+       request_send_async(fc, req, write_page_end);
 }
 
 static int fuse_writepage(struct page *page, struct writeback_control *wbc)
@@ -956,8 +847,8 @@ static int fuse_commit_write(struct file *file, struct page *page,
        return err;
 }
 
-static ssize_t fuse_write(struct file *file, const char __user *buf,
-                         size_t count, loff_t *ppos)
+static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
@@ -1021,7 +912,7 @@ static ssize_t fuse_file_write(struct file *file, const char __user *buf,
        if (fc->flags & FUSE_DIRECT_IO) {
                ssize_t res;
                down(&inode->i_sem);
-               res = fuse_write(file, buf, count, ppos);
+               res = fuse_direct_write(file, buf, count, ppos);
                up(&inode->i_sem);
                return res;
        }
index 9dbe3f3690cbad7e587469ec7950d2aa18b2e77a..37d8cad342370079a6185114ffcbe2912246f675 100644 (file)
@@ -6,7 +6,6 @@
     See the file COPYING.
 */
 
-
 #include <linux/fuse.h>
 #ifndef FUSE_MAINLINE
 #include <linux/version.h>
 #ifndef __user
 #define __user
 #endif
-#ifndef KERNEL_2_6
-/** Read combining parameters */
-#define FUSE_BLOCK_SHIFT 16
-#define FUSE_BLOCK_SIZE 65536
-#define FUSE_BLOCK_MASK 0xffff0000
-#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
-#endif
 /* Max number of pages that can be used in a single read request */
 #define FUSE_MAX_PAGES_PER_REQ 32
 
@@ -69,8 +61,8 @@
 
 
 /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
-module will check permissions based on the file mode.  Otherwise no
-permission checking is done in the kernel */
+    module will check permissions based on the file mode.  Otherwise no
+    permission checking is done in the kernel */
 #define FUSE_DEFAULT_PERMISSIONS (1 << 0)
 
 /** If the FUSE_ALLOW_OTHER flag is given, then not only the user
@@ -115,28 +107,30 @@ struct fuse_file {
 
 /** One input argument of a request */
 struct fuse_in_arg {
-       unsigned int size;
+       unsigned size;
        const void *value;
 };
 
 /** The request input */
 struct fuse_in {
        struct fuse_in_header h;
-       unsigned int numargs;
+       unsigned numargs;
        struct fuse_in_arg args[3];
 };
 
 /** One output argument of a request */
 struct fuse_out_arg {
-       unsigned int size;
+       unsigned size;
        void *value;
 };
 
 /** The request output */
 struct fuse_out {
        struct fuse_out_header h;
-       unsigned int argvar;
-       unsigned int numargs;
+       unsigned argvar:1;
+       unsigned argpages:1;
+       unsigned page_zeroing:1;
+       unsigned numargs;
        struct fuse_out_arg args[3];
 };
 
@@ -154,13 +148,13 @@ struct fuse_req {
        struct list_head list;
 
        /** True if the request has reply */
-       unsigned int isreply:1;
+       unsigned isreply:1;
 
        /* The request is preallocated */
-       unsigned int preallocated:1;
+       unsigned preallocated:1;
 
        /* The request is finished */
-       unsigned int finished;
+       unsigned finished;
 
        /** The request input */
        struct fuse_in in;
@@ -174,12 +168,6 @@ struct fuse_req {
        /** Request completion callback */
        fuse_reqend_t end;
 
-       /** Request copy out function */
-       fuse_copyout_t copy_out;
-
-       /** User data */
-       void *data;
-
        /** Data for asynchronous requests */
        union {
                struct {
@@ -191,8 +179,13 @@ struct fuse_req {
                struct fuse_forget_in forget_in;
        } misc;
 
+       /** page vector */
        struct page *pages[FUSE_MAX_PAGES_PER_REQ];
+
+       /** number of pages in vector */
        unsigned num_pages;
+
+       /** offset of data on first page */
        unsigned page_offset;
 };
 
@@ -214,13 +207,13 @@ struct fuse_conn {
        uid_t uid;
 
        /** The fuse mount flags for this mount */
-       unsigned int flags;
+       unsigned flags;
 
        /** Maximum read size */
-       unsigned int max_read;
+       unsigned max_read;
 
        /** Maximum write size */
-       unsigned int max_write;
+       unsigned max_write;
 
        /** Readers of the connection are waiting on this */
        wait_queue_head_t waitq;
@@ -244,22 +237,22 @@ struct fuse_conn {
        int reqctr;
        
        /** Is fsync not implemented by fs? */
-       unsigned int no_fsync : 1;
+       unsigned no_fsync : 1;
 
        /** Is flush not implemented by fs? */
-       unsigned int no_flush : 1;
+       unsigned no_flush : 1;
 
        /** Is setxattr not implemented by fs? */
-       unsigned int no_setxattr : 1;
+       unsigned no_setxattr : 1;
 
        /** Is getxattr not implemented by fs? */
-       unsigned int no_getxattr : 1;
+       unsigned no_getxattr : 1;
 
        /** Is listxattr not implemented by fs? */
-       unsigned int no_listxattr : 1;
+       unsigned no_listxattr : 1;
 
        /** Is removexattr not implemented by fs? */
-       unsigned int no_removexattr : 1;
+       unsigned no_removexattr : 1;
 
 #ifdef KERNEL_2_6
        /** Backing dev info */
@@ -395,7 +388,7 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req);
  * Send asynchronous request
  */
 void request_send_async(struct fuse_conn *fc, struct fuse_req *req, 
-                       fuse_reqend_t end, void *data);
+                       fuse_reqend_t end);
 
 /**
  * Get the attributes of a file
index 8cae834961c689397697001c0642963defe79408..0a70d028f43eddba74478ab53733576b40e49f1b 100644 (file)
@@ -46,10 +46,10 @@ MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_o
 #endif
 struct fuse_mount_data {
        int fd;
-       unsigned int rootmode;
-       unsigned int uid;
-       unsigned int flags;
-       unsigned int max_read;
+       unsigned rootmode;
+       unsigned uid;
+       unsigned flags;
+       unsigned max_read;
 };
 
 static struct inode *fuse_alloc_inode(struct super_block *sb)
@@ -392,7 +392,7 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
        return fc;
 }
 
-static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
+static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
 {
        struct fuse_attr attr;
        memset(&attr, 0, sizeof(attr));
index fa5b0828fb26d8f45a3ddc40bdd9467aecb37791..003f8b2146eaa5d8d098a3b020f0ba73f7c6e33e 100644 (file)
@@ -40,9 +40,9 @@ int __init fuse_init(void)
        
        return 0;
 
 err_fs_cleanup:
+ err_fs_cleanup:
        fuse_fs_cleanup();
 err:
+ err:
        return res;
 }