aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--kernel/dev.c52
-rw-r--r--kernel/dir.c17
-rw-r--r--kernel/file.c401
-rw-r--r--kernel/fuse_i.h61
-rw-r--r--kernel/inode.c10
-rw-r--r--kernel/util.c4
7 files changed, 234 insertions, 315 deletions
diff --git a/ChangeLog b/ChangeLog
index c9a090d..441669b 100644
--- 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
diff --git a/kernel/dev.c b/kernel/dev.c
index 0eebd31..aca602f 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -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,
diff --git a/kernel/dir.c b/kernel/dir.c
index 19834b4..412ffc8 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -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);
}
diff --git a/kernel/file.c b/kernel/file.c
index 0676135..2d15c5b 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -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;
}
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 9dbe3f3..37d8cad 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -6,7 +6,6 @@
See the file COPYING.
*/
-
#include <linux/fuse.h>
#ifndef FUSE_MAINLINE
#include <linux/version.h>
@@ -54,13 +53,6 @@
#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
diff --git a/kernel/inode.c b/kernel/inode.c
index 8cae834..0a70d02 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -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));
diff --git a/kernel/util.c b/kernel/util.c
index fa5b082..003f8b2 100644
--- a/kernel/util.c
+++ b/kernel/util.c
@@ -40,9 +40,9 @@ int __init fuse_init(void)
return 0;
- err_fs_cleanup:
+ err_fs_cleanup:
fuse_fs_cleanup();
- err:
+ err:
return res;
}