direct IO + fixes
authorMiklos Szeredi <miklos@szeredi.hu>
Fri, 2 Jul 2004 09:22:50 +0000 (09:22 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Fri, 2 Jul 2004 09:22:50 +0000 (09:22 +0000)
ChangeLog
include/linux/fuse.h
kernel/.cvsignore
kernel/Makefile.in
kernel/dir.c
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
lib/fuse.c
util/fusermount.c

index 5448cc90d1f350b7b690d7828582d43163d53395..14ce894b5ac5d0af5614cd21d40f7cf90db9476b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2004-07-02  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+       * Fix kernel hang on mkfifo under 2.4 kernels (spotted and patch
+       by Mattias Wadman)
+
+       * Added option for direct read/write (-r)
+
+       * Fix revalidate time setting for newly created inodes
+
+2004-07-01  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+       * Change passing fuse include dir to 2.6 kernel make system more
+       robust (hopefully fixes problems seen on SuSE 9.1)
+
 2004-06-30  Miklos Szeredi <mszeredi@inf.bme.hu>
 
        * Acquire inode->i_sem before open and release methods to prevent
index 027cb5e246ffafdb477b0a8aeb7b9ca1f8f561d6..7f241e6a6052d427215a988c3a7c086f786bda73 100644 (file)
@@ -153,6 +153,10 @@ struct fuse_write_in {
        unsigned int size;
 };
 
+struct fuse_write_out {
+       unsigned int size;
+};
+
 struct fuse_statfs_out {
        struct fuse_kstatfs st;
 };
index 9722e6c75073f47bd7b422f60001433971bd1a11..a9f80886bc26a637f3a15e63d974a6e87027a1f4 100644 (file)
@@ -5,3 +5,4 @@ Makefile
 *.ko
 *.s
 .tmp_versions
+.*.d
index 6ea6569845dd52b0ea415e4ee4c31744713820b7..bcd792fbd3333fa450390d4bec1a5488e8c2c4f9 100644 (file)
@@ -67,7 +67,8 @@ util.o: $(fuse_headers)
 
 else
 
-EXTRA_CFLAGS := -I$(PWD)/../include -DFUSE_VERSION=\"@VERSION@\"
+export FUSE_INCLUDE ?= $(shell pwd)/../include
+EXTRA_CFLAGS += -I$(FUSE_INCLUDE) -DFUSE_VERSION=\"@VERSION@\"
 
 obj-m := fuse.o
 fuse-objs := dev.o dir.o file.o inode.o util.o
@@ -75,7 +76,3 @@ fuse-objs := dev.o dir.o file.o inode.o util.o
 all-spec:
        $(MAKE) -C @kernelsrc@ SUBDIRS=$(PWD) @KERNELMAKE_PARAMS@ modules
 endif
-
-
-
-
index af41ab5dba8ba435c8e10336b996529e960ee941..aa3129538fe72a5f75f8e59426b87b44fd088db2 100644 (file)
@@ -182,8 +182,10 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
        if (err && err != -ENOENT)
                return err;
 
-       entry->d_time = time_to_jiffies(outarg.entry_valid,
-                                       outarg.entry_valid_nsec);
+       if (inode)
+               entry->d_time = time_to_jiffies(outarg.entry_valid,
+                                               outarg.entry_valid_nsec);
+
        entry->d_op = &fuse_dentry_operations;
        *inodep = inode;
        return 0;
@@ -210,6 +212,9 @@ static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
                return -EINVAL;
        }
 
+       entry->d_time = time_to_jiffies(outarg->entry_valid,
+                                       outarg->entry_valid_nsec);
+
        d_instantiate(entry, inode);
        return 0;
 }
@@ -847,7 +852,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
                      int rdev)
 {
-       return fuse_mknod(dir, entry, mode, rdev);
+       return _fuse_mknod(dir, entry, mode, rdev);
 }
 
 static int fuse_dentry_revalidate(struct dentry *entry, int flags)
index 9a7da73af53fbf13ece9ca7ae22bb6c3795c4719..d7b61ea68f575360042a4f5e52bbd5b337afcbf8 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/pagemap.h>
 #include <linux/slab.h>
+#include <asm/uaccess.h>
 #ifdef KERNEL_2_6
 #include <linux/backing-dev.h>
 #include <linux/writeback.h>
@@ -45,15 +46,16 @@ static int fuse_open(struct inode *inode, struct file *file)
                        return err;
        }
 
+       down(&inode->i_sem);
+       err = -ERESTARTSYS;
        req = fuse_get_request(fc);
        if (!req)
-               return -ERESTARTSYS;
+               goto out;
 
+       err = -ENOMEM;
        req2 = fuse_request_alloc();
-       if (!req2) {
-               fuse_put_request(fc, req);
-               return -ENOMEM;
-       }
+       if (!req2)
+               goto out_put_request;
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.flags = file->f_flags & ~O_EXCL;
@@ -62,9 +64,7 @@ static int fuse_open(struct inode *inode, struct file *file)
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
-       down(&inode->i_sem);
        request_send(fc, req);
-       up(&inode->i_sem);
        err = req->out.h.error;
        if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) {
 #ifdef KERNEL_2_6
@@ -77,7 +77,11 @@ static int fuse_open(struct inode *inode, struct file *file)
                fuse_request_free(req2);
        else
                file->private_data = req2;
+
+ out_put_request:
        fuse_put_request(fc, req);
+ out:
+       up(&inode->i_sem);
        return err;
 }
 
@@ -90,6 +94,7 @@ static int fuse_release(struct inode *inode, struct file *file)
        if (file->f_mode & FMODE_WRITE)
                filemap_fdatawrite(inode->i_mapping);
 
+       down(&inode->i_sem);
        inarg = &req->misc.open_in;
        inarg->flags = file->f_flags & ~O_EXCL;
        req->in.h.opcode = FUSE_RELEASE;
@@ -97,10 +102,9 @@ static int fuse_release(struct inode *inode, struct file *file)
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(struct fuse_open_in);
        req->in.args[0].value = inarg;
-       down(&inode->i_sem);
        request_send(fc, req);
-       up(&inode->i_sem);
        fuse_put_request(fc, req);
+       up(&inode->i_sem);
 
        /* Return value is ignored by VFS */
        return 0;
@@ -168,24 +172,21 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
            care of this? */
 }
 
-static int fuse_readpage(struct file *file, struct page *page)
+static ssize_t fuse_send_read(struct inode *inode, char *buf, loff_t pos,
+                             size_t count)
 {
-       struct inode *inode = page->mapping->host;
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_req *req;
        struct fuse_read_in inarg;
-       char *buffer;
-       int err;
-
-       buffer = kmap(page);
+       ssize_t res;
        
        req = fuse_get_request(fc);
        if (!req)
                return -ERESTARTSYS;
        
        memset(&inarg, 0, sizeof(inarg));
-       inarg.offset = (unsigned long long) page->index << PAGE_CACHE_SHIFT;
-       inarg.size = PAGE_CACHE_SIZE;
+       inarg.offset = pos;
+       inarg.size = count;
        req->in.h.opcode = FUSE_READ;
        req->in.h.ino = inode->i_ino;
        req->in.numargs = 1;
@@ -193,25 +194,40 @@ static int fuse_readpage(struct file *file, struct page *page)
        req->in.args[0].value = &inarg;
        req->out.argvar = 1;
        req->out.numargs = 1;
-       req->out.args[0].size = PAGE_CACHE_SIZE;
-       req->out.args[0].value = buffer;
+       req->out.args[0].size = count;
+       req->out.args[0].value = buf;
        request_send(fc, req);
-       err = req->out.h.error;
-       if (!err) {
-               size_t outsize = req->out.args[0].size;
-               if (outsize < PAGE_CACHE_SIZE) 
-                       memset(buffer + outsize, 0, PAGE_CACHE_SIZE - outsize);
+       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 = (unsigned long long) page->index << PAGE_CACHE_SHIFT;
+       buffer = kmap(page);
+       res = fuse_send_read(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);
                SetPageUptodate(page);
+               res = 0;
        }
-       fuse_put_request(fc, req);
        kunmap(page);
        unlock_page(page);
-       return err;
+       return res;
 }
 
-static int fuse_is_block_uptodate(struct address_space *mapping,
-               struct inode *inode, size_t bl_index)
+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;
@@ -221,7 +237,7 @@ static int fuse_is_block_uptodate(struct address_space *mapping,
                end_index = file_end_index;
 
        for (; index <= end_index; index++) {
-               struct page *page = find_get_page(mapping, index);
+               struct page *page = find_get_page(inode->i_mapping, index);
 
                if (!page)
                        return 0;
@@ -238,9 +254,8 @@ static int fuse_is_block_uptodate(struct address_space *mapping,
 }
 
 
-static int fuse_cache_block(struct address_space *mapping,
-               struct inode *inode, char *bl_buf,
-               size_t bl_index)
+static int fuse_cache_block(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;
@@ -256,7 +271,7 @@ static int fuse_cache_block(struct address_space *mapping,
                struct page *page;
                char *buffer;
 
-               page = grab_cache_page(mapping, index);
+               page = grab_cache_page(inode->i_mapping, index);
                if (!page)
                        return -1;
 
@@ -277,41 +292,22 @@ static int fuse_cache_block(struct address_space *mapping,
 } 
 
 static int fuse_file_read_block(struct inode *inode, char *bl_buf,
-               size_t bl_index)
+                               size_t bl_index)
 {
-       struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_req *req = fuse_get_request(fc);
-       struct fuse_read_in inarg;
-       int err;
-
-       if (!req)
-               return -ERESTARTSYS;
-
-       memset(&inarg, 0, sizeof(inarg));
-       inarg.offset = (unsigned long long) bl_index << FUSE_BLOCK_SHIFT;
-       inarg.size = FUSE_BLOCK_SIZE;
-       req->in.h.opcode = FUSE_READ;
-       req->in.h.ino = inode->i_ino;
-       req->in.numargs = 1;
-       req->in.args[0].size = sizeof(inarg);
-       req->in.args[0].value = &inarg;
-       req->out.argvar = 1;
-       req->out.numargs = 1;
-       req->out.args[0].size = FUSE_BLOCK_SIZE;
-       req->out.args[0].value = bl_buf;
-       request_send(fc, req);
-       err = req->out.h.error;
-       if (!err) {
-               size_t outsize = req->out.args[0].size;
-               if (outsize < FUSE_BLOCK_SIZE)
-                       memset(bl_buf + outsize, 0, FUSE_BLOCK_SIZE - outsize);
+       ssize_t res;
+       loff_t offset;
+       
+       offset = (unsigned long long) bl_index << FUSE_BLOCK_SHIFT;
+       res = fuse_send_read(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;
        }
-       fuse_put_request(fc, req);
-       return err;
+       return res;
 }   
 
-static void fuse_file_bigread(struct address_space *mapping,
-                             struct inode *inode, loff_t pos, size_t count)
+static void fuse_file_bigread(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;
@@ -325,47 +321,95 @@ static void fuse_file_bigread(struct address_space *mapping,
                char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_KERNEL);
                if (!bl_buf)
                        break;
-               res = fuse_is_block_uptodate(mapping, inode, bl_index);
+               res = fuse_is_block_uptodate(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);
+                       fuse_cache_block(inode, bl_buf, bl_index);
                kfree(bl_buf);
                bl_index++;
        }
 }
 
-static ssize_t fuse_file_read(struct file *filp, char *buf,
-               size_t count, loff_t * ppos)
+static ssize_t fuse_read(struct file *file, char *buf, size_t count,
+                        loff_t *ppos)
 {
-       struct address_space *mapping = filp->f_dentry->d_inode->i_mapping;
-       struct inode *inode = mapping->host;
+       struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
+       char *tmpbuf;
+       ssize_t res = 0;
+       loff_t pos = *ppos;
 
-       if (fc->flags & FUSE_LARGE_READ)
-               fuse_file_bigread(mapping, inode, *ppos, count);
+       tmpbuf = kmalloc(count < fc->max_read ? count : fc->max_read,
+                        GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
+
+       while (count) {
+               size_t nbytes = count < fc->max_read ? count : fc->max_read;
+               ssize_t res1;
+               res1 = fuse_send_read(inode, tmpbuf, pos, nbytes);
+               if (res1 < 0) {
+                       if (!res)
+                               res = res1;
+                       break;
+               }
+               res += res1;
+               if (copy_to_user(buf, tmpbuf, res1)) {
+                       res = -EFAULT;
+                       break;
+               }
+               count -= res1;
+               buf += res1;
+               pos += res1;
+               if (res1 < nbytes)
+                       break;
+       }
+       kfree(tmpbuf);
+
+       if (res > 0)
+               *ppos += res;
+
+       return res;
+}
+
+static ssize_t fuse_file_read(struct file *file, char *buf,
+                             size_t count, loff_t * ppos)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = INO_FC(inode);
+       ssize_t res;
 
-       return generic_file_read(filp, buf, count, ppos);
+       down(&inode->i_sem);
+       if (fc->flags & FUSE_DIRECT_IO) {
+               res = fuse_read(file, buf, count, ppos);
+       }
+       else {
+               if (fc->flags & FUSE_LARGE_READ)
+                       fuse_file_bigread(inode, *ppos, count);
+               
+               res = generic_file_read(file, buf, count, ppos);
+       }
+       up(&inode->i_sem);
+
+       return res;
 }  
 
-static int write_buffer(struct inode *inode, struct page *page,
-                       unsigned offset, size_t count)
+static ssize_t fuse_send_write(struct inode *inode, const char *buf,
+                              loff_t pos, size_t count)
 {
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_req *req;
        struct fuse_write_in inarg;
-       char *buffer;
-       int err;
-
-       buffer = kmap(page);
-
+       struct fuse_write_out outarg;
+       ssize_t res;
+       
        req = fuse_get_request(fc);
        if (!req)
                return -ERESTARTSYS;
-
+       
        memset(&inarg, 0, sizeof(inarg));
-       inarg.offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) +
-               offset;
+       inarg.offset = pos;
        inarg.size = count;
        req->in.h.opcode = FUSE_WRITE;
        req->in.h.ino = inode->i_ino;
@@ -373,14 +417,39 @@ static int write_buffer(struct inode *inode, struct page *page,
        req->in.args[0].size = sizeof(inarg);
        req->in.args[0].value = &inarg;
        req->in.args[1].size = count;
-       req->in.args[1].value = buffer + offset;
+       req->in.args[1].value = buf;
+       req->out.numargs = 1;
+       req->out.args[0].size = sizeof(outarg);
+       req->out.args[0].value = &outarg;
        request_send(fc, req);
-       err = req->out.h.error;
+       res = req->out.h.error;
+       if (!res)
+               res = outarg.size;
        fuse_put_request(fc, req);
+       return res;
+}
+
+static int write_buffer(struct inode *inode, struct page *page,
+                       unsigned offset, size_t count)
+{
+       char *buffer;
+       ssize_t res;
+       loff_t pos;
+
+       pos = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset;
+       buffer = kmap(page);
+       res = fuse_send_write(inode, buffer + offset, pos, count);
+       if (res >= 0) {
+               if (res < count) {
+                       printk("fuse: short write\n");
+                       res = -EPROTO;
+               } else
+                       res = 0;
+       }
        kunmap(page);
-       if (err)
+       if (res)
                SetPageError(page);
-       return err;
+       return res;
 }
 
 static int get_write_count(struct inode *inode, struct page *page)
@@ -405,7 +474,12 @@ static int get_write_count(struct inode *inode, struct page *page)
 static void write_buffer_end(struct fuse_conn *fc, struct fuse_req *req)
 {
        struct page *page = (struct page *) req->data;
-       
+       struct fuse_write_out *outarg = req->out.args[0].value;
+       if (!req->out.h.error && outarg->size != req->in.args[1].size) {
+               printk("fuse: short write\n");
+               req->out.h.error = -EPROTO;
+       }
+
        lock_page(page);
        if (req->out.h.error) {
                SetPageError(page);
@@ -425,14 +499,14 @@ static int write_buffer_nonblock(struct inode *inode, struct page *page,
 {
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_req *req;
-       struct fuse_write_in *inarg = NULL;
+       struct fuse_write_in *inarg;
        char *buffer;
 
        req = fuse_get_request_nonblock(fc);
        if (!req)
                return -EWOULDBLOCK;
 
-       inarg = &req->misc.write_in;
+       inarg = &req->misc.write.in;
        buffer = kmap(page);
        inarg->offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset;
        inarg->size = count;
@@ -443,6 +517,9 @@ static int write_buffer_nonblock(struct inode *inode, struct page *page,
        req->in.args[0].value = inarg;
        req->in.args[1].size = count;
        req->in.args[1].value = buffer + offset;
+       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_nonblock(fc, req, write_buffer_end, page);
        return 0;
 }
@@ -509,10 +586,82 @@ static int fuse_commit_write(struct file *file, struct page *page,
        return err;
 }
 
+static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
+                         loff_t *ppos)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = INO_FC(inode);
+       char *tmpbuf;
+       ssize_t res = 0;
+       loff_t pos = *ppos;
+
+       tmpbuf = kmalloc(count < fc->max_write ? count : fc->max_write,
+                        GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
+
+       while (count) {
+               size_t nbytes = count < fc->max_write ? count : fc->max_write;
+               ssize_t res1;
+               if (copy_from_user(tmpbuf, buf, nbytes)) {
+                       res = -EFAULT;
+                       break;
+               }
+               res1 = fuse_send_write(inode, tmpbuf, pos, nbytes);
+               if (res1 < 0) {
+                       res = res1;
+                       break;
+               }
+               res += res1;
+               count -= res1;
+               buf += res1;
+               pos += res1;
+               if (res1 < nbytes)
+                       break;
+       }
+       kfree(tmpbuf);
+
+       if (res > 0) {
+               if (pos > i_size_read(inode))
+                       i_size_write(inode, pos);
+               *ppos = pos;
+       }
+
+       return res;
+}
+
+static ssize_t fuse_file_write(struct file *file, const char *buf,
+                              size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = INO_FC(inode);
+       
+       if (fc->flags & FUSE_DIRECT_IO) {
+               ssize_t res;
+               down(&inode->i_sem);
+               res = fuse_write(file, buf, count, ppos);
+               up(&inode->i_sem);
+               return res;
+       }
+       else 
+               return generic_file_write(file, buf, count, ppos);
+}
+                              
+static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct fuse_conn *fc = INO_FC(inode);
+
+       if (fc->flags & FUSE_DIRECT_IO)
+               return -ENODEV;
+       else
+               return generic_file_mmap(file, vma);
+}
+
 static struct file_operations fuse_file_operations = {
        .read           = fuse_file_read,
-       .write          = generic_file_write,
-       .mmap           = generic_file_mmap,
+       .write          = fuse_file_write,
+       .mmap           = fuse_file_mmap,
        .open           = fuse_open,
        .flush          = fuse_flush,
        .release        = fuse_release,
index f83ac6ab236b311f28a59e36cd31fe2125cf0968..59bc0bcde4a6b9f44e1702be518f37061e3dbbcc 100644 (file)
@@ -62,6 +62,9 @@ permission checking is done in the kernel */
     than for small. */
 #define FUSE_LARGE_READ          (1 << 3)
 
+/** Bypass the page cache for read and write operations  */
+#define FUSE_DIRECT_IO           (1 << 4)
+
 /** One input argument of a request */
 struct fuse_in_arg {
        unsigned int size;
@@ -136,7 +139,11 @@ struct fuse_req {
 
        /** Data for asynchronous requests */
        union {
-               struct fuse_write_in write_in;
+               struct {
+                       struct fuse_write_in in;
+                       struct fuse_write_out out;
+                       
+               } write;
                struct fuse_open_in open_in;
                struct fuse_forget_in forget_in;
        } misc;
@@ -162,6 +169,12 @@ struct fuse_conn {
        /** The fuse mount flags for this mount */
        unsigned int flags;
 
+       /** Maximum read size */
+       unsigned int max_read;
+
+       /** Maximum write size */
+       unsigned int max_write;
+
        /** Readers of the connection are waiting on this */
        wait_queue_head_t waitq;
 
index afee16d2c2dd553e7ce7cf655e79647c5eb6990d..d94b3b2336f79cc0ce81076cd8d997b5a1b61691 100644 (file)
@@ -37,6 +37,7 @@ struct fuse_mount_data {
        unsigned int rootmode;
        unsigned int uid;
        unsigned int flags;
+       unsigned int max_read;
 };
 
 static void fuse_read_inode(struct inode *inode)
@@ -124,7 +125,8 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
 }
 
 enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions, 
-       opt_allow_other, opt_kernel_cache, opt_large_read, opt_err };
+       opt_allow_other, opt_kernel_cache, opt_large_read, opt_direct_io,
+       opt_max_read, opt_err };
 
 static match_table_t tokens = {
        {opt_fd, "fd=%u"},
@@ -134,6 +136,8 @@ static match_table_t tokens = {
        {opt_allow_other, "allow_other"},
        {opt_kernel_cache, "kernel_cache"},
        {opt_large_read, "large_read"},
+       {opt_direct_io, "direct_io"},
+       {opt_max_read, "max_read" },
        {opt_err, NULL}
 };
 
@@ -142,6 +146,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
        char *p;
        memset(d, 0, sizeof(struct fuse_mount_data));
        d->fd = -1;
+       d->max_read = ~0;
 
        while ((p = strsep(&opt, ",")) != NULL) {
                int token;
@@ -185,6 +190,17 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                case opt_large_read:
                        d->flags |= FUSE_LARGE_READ;
                        break;
+                       
+               case opt_direct_io:
+                       d->flags |= FUSE_DIRECT_IO;
+                       break;
+
+               case opt_max_read:
+                       if (match_int(&args[0], &value))
+                               return 0;
+                       d->max_read = value;
+                       break;
+
                default:
                        return 0;
                }
@@ -208,6 +224,10 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",kernel_cache");
        if (fc->flags & FUSE_LARGE_READ)
                seq_puts(m, ",large_read");
+       if (fc->flags & FUSE_DIRECT_IO)
+               seq_puts(m, ",direct_io");
+       if (fc->max_read != ~0)
+               seq_printf(m, ",max_read=%u", fc->max_read);
        return 0;
 }
 
@@ -314,6 +334,8 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
 
        fc->flags = d.flags;
        fc->uid = d.uid;
+       fc->max_read = d.max_read;
+       fc->max_write = FUSE_MAX_IN / 2;
        
        /* fc is needed in fuse_init_file_inode which could be called
           from get_root_inode */
index 4cd89157abda6826b6cd69652290c9309bf6a6a6..0b7da30f7d4cc68392d958a3e1e02e2acde4b46b 100644 (file)
@@ -1061,6 +1061,7 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
 {
     int res;
     char *path;
+    struct fuse_write_out outarg;
 
     res = -ENOENT;
     path = get_path(f, in->ino);
@@ -1076,17 +1077,12 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
         free(path);
     }
     
-    if (res > 0) {
-        if ((size_t) res != arg->size) {
-            fprintf(stderr, "short write: %u (should be %u)\n", res,
-                    arg->size);
-            res = -EINVAL;
-        }
-        else 
-            res = 0;
+    if (res >= 0) { 
+        outarg.size = res;
+        res = 0;
     }
 
-    send_reply(f, in, res, NULL, 0);
+    send_reply(f, in, res, &outarg, sizeof(outarg));
 }
 
 static int default_statfs(struct statfs *buf)
index bd52e4a5c8813db241b1a17586a52872f653ce4f..e837eb2ca6694808fc385ab04b342e0d862103ac 100644 (file)
@@ -46,6 +46,7 @@ struct fuse_opts {
     int default_permissions;
     int allow_other;
     int large_read;
+    int direct_io;
 };
 
 static const char *get_user_name()
@@ -318,6 +319,8 @@ static int do_mount(const char *dev, const char *mnt, const char *type,
         s += sprintf(s, ",allow_other");
     if (opts->large_read)
         s += sprintf(s, ",large_read");
+    if (opts->direct_io)
+        s += sprintf(s, ",direct_io");
 
     res = mount(dev, mnt, type, flags, optbuf);
     if(res == -1)
@@ -496,6 +499,7 @@ static void usage()
             " -x       allow other users to access the files (only for root)\n"
             " -n name  add 'name' as the filesystem name to mtab\n"
             " -l       issue large reads\n"
+            " -r       raw I/O\n"
             " -q       quiet: don't complain if unmount fails\n"
             " -z       lazy unmount\n",
             progname);
@@ -567,6 +571,10 @@ int main(int argc, char *argv[])
         case 'l':
             opts.large_read = 1;
             break;
+
+        case 'r':
+            opts.direct_io = 1;
+            break;
             
         case 'q':
             quiet = 1;