security fixes + other enhancements
authorMiklos Szeredi <miklos@szeredi.hu>
Sat, 24 Jul 2004 19:56:16 +0000 (19:56 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sat, 24 Jul 2004 19:56:16 +0000 (19:56 +0000)
ChangeLog
configure.in
include/linux/fuse.h
kernel/file.c
kernel/fuse_i.h
kernel/inode.c
lib/fuse.c
lib/fuse_i.h
util/fusermount.c

index 0e2288228c1e926f42dcfacc0610b774ab9070dd..01885b98a3216fd5fe0ce551776af560fb93f86b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,24 @@
 2004-07-24  Miklos Szeredi <miklos@szeredi.hu>
 
-       * Make the non-user mounting more secure by changing the current
-       directory to the mountpoint before checking the permissions and
-       mounting on "." after this
+       * 'large_read' mount option removed for 2.6 kernels, since the
+       default (dynamic read size) is better
+
+       * Extend kernel API with file handles.  A file handle is returned
+       by open, and passed to read, write, flush, fsync and release.
+       This is currently only used for debug output in the library.
+       
+       * Security changes:
+
+       * Change the current directory to the mountpoint before checking
+       the permissions and mount filesystem on "."
+
+       * By default don't modprobe the fuse module for non-root.  The old
+       behavior can be restored with the '--enable-auto-modprobe' flag of
+       ./configure
+
+       * By default don't allow shared writable mappings for non-root.
+       The old behavior can be restored with the 'user_mmap=1' module
+       parameter
 
 2004-07-23  Miklos Szeredi <miklos@szeredi.hu>
 
index 9b931239689f1ed0ee8a0db75391a77529e49700..b5c25d1041f5609a83500ada7e5b675cf5e2823e 100644 (file)
@@ -29,6 +29,8 @@ AC_ARG_ENABLE(util,
        [  --enable-util           Compile with util ])
 AC_ARG_ENABLE(example,
        [  --enable-example        Compile with examples ])
+AC_ARG_ENABLE(auto-modprobe,
+       [  --enable-auto-modprobe  Automatically insert kernel module])
 
 subdirs="include patch"
 
@@ -107,6 +109,9 @@ fi
 if test "$enable_example" != "no"; then
        subdirs="$subdirs example";
 fi
+if test "$enable_auto_modprobe" = "yes"; then
+       AC_DEFINE(AUTO_MODPROBE, 1, [Automatically insert kernel module])
+fi
 
 AC_CHECK_FUNCS([setxattr])
 AC_CHECK_MEMBERS([struct stat.st_atim])
index d45a85b9d61afaabc7a2433562fce8e5fa8d27cd..77ad8d647e388932b47e7d53bc6c3cd45f20b072 100644 (file)
@@ -143,12 +143,28 @@ struct fuse_open_in {
        unsigned int flags;
 };
 
+struct fuse_open_out {
+       unsigned int fh;
+};
+
+struct fuse_release_in {
+       unsigned int fh;
+       unsigned int flags;
+};
+
+struct fuse_flush_in {
+       unsigned int fh;
+};
+
 struct fuse_read_in {
+       unsigned int fh;
        unsigned long long offset;
        unsigned int size;
 };
 
 struct fuse_write_in {
+       int writepage;
+       unsigned int fh;
        unsigned long long offset;
        unsigned int size;
 };
@@ -162,6 +178,7 @@ struct fuse_statfs_out {
 };
 
 struct fuse_fsync_in {
+       unsigned int fh;
        int datasync;
 };
 
index 285957e85fc39e2756ae34b0d01e63d96bfa0494..facd36cda3510d0de421ad19bbf76542c776decf 100644 (file)
 #define PageUptodate(page) Page_Uptodate(page)
 #endif
 
+static int user_mmap;
+#ifdef KERNEL_2_6
+#include <linux/moduleparam.h>
+module_param(user_mmap, int, 0);
+#else
+MODULE_PARM(user_mmap, "i");
+#endif
+
+MODULE_PARM_DESC(user_mmap, "Allow non root user to create a shared writable mapping");
+
+
 static int fuse_open(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc = INO_FC(inode);
        struct fuse_req *req;
-       struct fuse_req *req2;
        struct fuse_open_in inarg;
+       struct fuse_open_out outarg;
+       struct fuse_file *ff;
        int err;
 
        err = generic_file_open(inode, file);
@@ -46,10 +58,17 @@ static int fuse_open(struct inode *inode, struct file *file)
                goto out;
 
        err = -ENOMEM;
-       req2 = fuse_request_alloc();
-       if (!req2)
+       ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+       if (!ff)
                goto out_put_request;
 
+       ff->release_req = fuse_request_alloc();
+       if (!ff->release_req) {
+               kfree(ff);
+               goto out_put_request;
+       }
+
+
        memset(&inarg, 0, sizeof(inarg));
        inarg.flags = file->f_flags & ~O_EXCL;
        req->in.h.opcode = FUSE_OPEN;
@@ -57,6 +76,9 @@ 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;
+       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;
        if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) {
@@ -66,10 +88,15 @@ static int fuse_open(struct inode *inode, struct file *file)
                invalidate_inode_pages(inode);
 #endif
        }
-       if (err)
-               fuse_request_free(req2);
-       else
-               file->private_data = req2;
+       if (err) {
+               fuse_request_free(ff->release_req);
+               kfree(ff);
+       }
+       else {
+               ff->fh = outarg.fh;
+               file->private_data = ff;
+               INIT_LIST_HEAD(&ff->ff_list);
+       }
 
  out_put_request:
        fuse_put_request(fc, req);
@@ -94,22 +121,32 @@ void fuse_sync_inode(struct inode *inode)
 static int fuse_release(struct inode *inode, struct file *file)
 {
        struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_open_in *inarg;
-       struct fuse_req *req = file->private_data;
+       struct fuse_inode *fi = INO_FI(inode);
+       struct fuse_release_in *inarg;
+       struct fuse_file *ff = file->private_data;
+       struct fuse_req *req = ff->release_req;
        
        down(&inode->i_sem);
        if (file->f_mode & FMODE_WRITE)
                fuse_sync_inode(inode);
 
-       inarg = &req->misc.open_in;
+       if (!list_empty(&ff->ff_list)) {
+               down_write(&fi->write_sem);
+               list_del(&ff->ff_list);
+               up_write(&fi->write_sem);
+       }
+
+       inarg = &req->misc.release_in;
+       inarg->fh = ff->fh;
        inarg->flags = file->f_flags & ~O_EXCL;
        req->in.h.opcode = FUSE_RELEASE;
        req->in.h.ino = inode->i_ino;
        req->in.numargs = 1;
-       req->in.args[0].size = sizeof(struct fuse_open_in);
+       req->in.args[0].size = sizeof(struct fuse_release_in);
        req->in.args[0].value = inarg;
        request_send(fc, req);
        fuse_put_request(fc, req);
+       kfree(ff);
        up(&inode->i_sem);
 
        /* Return value is ignored by VFS */
@@ -120,7 +157,9 @@ static int fuse_flush(struct file *file)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        struct fuse_req *req;
+       struct fuse_flush_in inarg;
        int err;
        
        if (fc->no_flush)
@@ -130,8 +169,13 @@ static int fuse_flush(struct file *file)
        if (!req)
                return -EINTR;
 
+       memset(&inarg, 0, sizeof(inarg));
+       inarg.fh = ff->fh;
        req->in.h.opcode = FUSE_FLUSH;
        req->in.h.ino = inode->i_ino;
+       req->in.numargs = 1;
+       req->in.args[0].size = sizeof(inarg);
+       req->in.args[0].value = &inarg;
        request_send(fc, req);
        err = req->out.h.error;
        if (err == -ENOSYS) {
@@ -147,6 +191,7 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        struct inode *inode = de->d_inode;
        struct fuse_inode *fi = INO_FI(inode);
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        struct fuse_req *req;
        struct fuse_fsync_in inarg;
        int err;
@@ -164,6 +209,7 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        up_write(&fi->write_sem);
 
        memset(&inarg, 0, sizeof(inarg));
+       inarg.fh = ff->fh;
        inarg.datasync = datasync;
        req->in.h.opcode = FUSE_FSYNC;
        req->in.h.ino = inode->i_ino;
@@ -180,10 +226,11 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
        return err;
 }
 
-static ssize_t fuse_send_read(struct inode *inode, char *buf, loff_t pos,
-                             size_t count)
+static ssize_t fuse_send_read(struct file *file, struct inode *inode,
+                             char *buf, loff_t pos, size_t count)
 {
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        struct fuse_req *req;
        struct fuse_read_in inarg;
        ssize_t res;
@@ -193,6 +240,7 @@ static ssize_t fuse_send_read(struct inode *inode, char *buf, loff_t pos,
                return -ERESTARTSYS;
        
        memset(&inarg, 0, sizeof(inarg));
+       inarg.fh = ff->fh;
        inarg.offset = pos;
        inarg.size = count;
        req->in.h.opcode = FUSE_READ;
@@ -222,7 +270,7 @@ static int fuse_readpage(struct file *file, struct page *page)
 
        pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
        buffer = kmap(page);
-       res = fuse_send_read(inode, buffer, pos, PAGE_CACHE_SIZE);
+       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);
@@ -283,9 +331,11 @@ static void read_pages_end(struct fuse_conn *fc, struct fuse_req *req)
        fuse_put_request(fc, req);
 }
 
-static void fuse_send_readpages(struct fuse_req *req, struct inode *inode)
+static void fuse_send_readpages(struct fuse_req *req, struct file *file,
+                               struct inode *inode)
 {
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        struct fuse_read_in *inarg;
        loff_t pos;
        unsigned numpages;
@@ -296,6 +346,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct inode *inode)
                - 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;
@@ -307,20 +358,26 @@ static void fuse_send_readpages(struct fuse_req *req, struct inode *inode)
        request_send_nonblock(fc, req, read_pages_end, NULL);
 }
 
-static int fuse_readpages_fill(void *_reqp, struct page *page)
+struct fuse_readpages_data {
+       struct fuse_req *req;
+       struct file *file;
+       struct inode *inode;
+};
+
+static int fuse_readpages_fill(void *_data, struct page *page)
 {
-       struct inode *inode = page->mapping->host;
+       struct fuse_readpages_data *data = _data;
+       struct fuse_req *req = data->req;
+       struct inode *inode = data->inode;
        struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_req **reqp = (struct fuse_req **) _reqp; 
-       struct fuse_req *req = *reqp;
        
        if (req->num_pages && 
            (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
             (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
             req->pages[req->num_pages - 1]->index + 1 != page->index)) {
                struct fuse_conn *fc = INO_FC(page->mapping->host);
-               fuse_send_readpages(req, inode);
-               *reqp = req = fuse_get_request(fc);
+               fuse_send_readpages(req, data->file, inode);
+               data->req = req = fuse_get_request(fc);
        }
        req->pages[req->num_pages] = page;
        req->num_pages ++;
@@ -332,18 +389,23 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
 {
        struct inode *inode = mapping->host;
        struct fuse_conn *fc = INO_FC(inode);
-       struct fuse_req *req = fuse_get_request(fc);
+       struct fuse_readpages_data data;
+
+       data.req = fuse_get_request(fc);
+       data.file = file;
+       data.inode = inode;
        
-       read_cache_pages(mapping, pages, fuse_readpages_fill, &req);
-       if (req->num_pages)
-               fuse_send_readpages(req, inode);
+       read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
+       if (data.req->num_pages)
+               fuse_send_readpages(data.req, file, inode);
        else
-               fuse_put_request(fc, req);
+               fuse_put_request(fc, data.req);
 
        return 0;
 }
 #endif
 
+#ifndef 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;
@@ -408,14 +470,14 @@ static int fuse_cache_block(struct inode *inode, char *bl_buf,
        return 0;
 } 
 
-static int fuse_file_read_block(struct inode *inode, char *bl_buf,
-                               size_t bl_index)
+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(inode, bl_buf, offset, FUSE_BLOCK_SIZE);
+       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);
@@ -424,7 +486,8 @@ static int fuse_file_read_block(struct inode *inode, char *bl_buf,
        return res;
 }   
 
-static void fuse_file_bigread(struct inode *inode, loff_t pos, size_t count)
+static void 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;
@@ -440,13 +503,15 @@ static void fuse_file_bigread(struct inode *inode, loff_t pos, size_t count)
                        break;
                res = fuse_is_block_uptodate(inode, bl_index);
                if (!res)
-                       res = fuse_file_read_block(inode, bl_buf, bl_index);
+                       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++;
        }
 }
+#endif
 
 static ssize_t fuse_read(struct file *file, char *buf, size_t count,
                         loff_t *ppos)
@@ -471,7 +536,7 @@ static ssize_t fuse_read(struct file *file, char *buf, size_t count,
        while (count) {
                size_t nbytes = count < max_read ? count : max_read;
                ssize_t res1;
-               res1 = fuse_send_read(inode, tmpbuf, pos, nbytes);
+               res1 = fuse_send_read(file, inode, tmpbuf, pos, nbytes);
                if (res1 < 0) {
                        if (!res)
                                res = res1;
@@ -507,18 +572,21 @@ static ssize_t fuse_file_read(struct file *file, char *buf,
                res = fuse_read(file, buf, count, ppos);
        }
        else {
+#ifndef KERNEL_2_6
                if (fc->flags & FUSE_LARGE_READ) {
                        down(&inode->i_sem);
-                       fuse_file_bigread(inode, *ppos, count);
+                       fuse_file_bigread(file, inode, *ppos, count);
                        up(&inode->i_sem);
                }
+#endif
                res = generic_file_read(file, buf, count, ppos);
        }
 
        return res;
 }  
 
-static ssize_t fuse_send_write(struct fuse_req *req, struct inode *inode,
+static ssize_t fuse_send_write(struct fuse_req *req, int writepage,
+                              struct fuse_file *ff, struct inode *inode,
                               const char *buf, loff_t pos, size_t count)
 {
        struct fuse_conn *fc = INO_FC(inode);
@@ -527,6 +595,8 @@ static ssize_t fuse_send_write(struct fuse_req *req, struct inode *inode,
        ssize_t res;
        
        memset(&inarg, 0, sizeof(inarg));
+       inarg.writepage = writepage;
+       inarg.fh = ff->fh;
        inarg.offset = pos;
        inarg.size = count;
        req->in.h.opcode = FUSE_WRITE;
@@ -547,10 +617,11 @@ static ssize_t fuse_send_write(struct fuse_req *req, struct inode *inode,
                return res;
 }
 
-static int write_buffer(struct inode *inode, struct page *page,
-                       unsigned offset, size_t count)
+static int write_buffer(struct inode *inode, struct file *file,
+                       struct page *page, unsigned offset, size_t count)
 {
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        char *buffer;
        ssize_t res;
        loff_t pos;
@@ -562,7 +633,7 @@ static int write_buffer(struct inode *inode, struct page *page,
        
        pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
        buffer = kmap(page);
-       res = fuse_send_write(req, inode, buffer + offset, pos, count);
+       res = fuse_send_write(req, 0, ff, inode, buffer + offset, pos, count);
        fuse_put_request(fc, req);
        if (res >= 0) {
                if (res < count) {
@@ -613,9 +684,12 @@ static int write_page_block(struct inode *inode, struct page *page)
        count = get_write_count(inode, page);
        res = 0;
        if (count) {
+               struct fuse_file *ff;
+               BUG_ON(list_empty(&fi->write_files));
+               ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
                pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
                buffer = kmap(page);
-               res = fuse_send_write(req, inode, buffer, pos, count);
+               res = fuse_send_write(req, 1, ff, inode, buffer, pos, count);
                if (res >= 0) {
                        if (res < count) {
                                printk("fuse: short write\n");
@@ -665,11 +739,18 @@ static void send_write_nonblock(struct fuse_req *req, struct inode *inode,
                                    struct page *page, unsigned count)
 {
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_inode *fi = INO_FI(inode);
        struct fuse_write_in *inarg;
+       struct fuse_file *ff;
        char *buffer;
-
+       
+       BUG_ON(list_empty(&fi->write_files));
+       ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
+       
        inarg = &req->misc.write.in;
        buffer = kmap(page);
+       inarg->writepage = 1;
+       inarg->fh = ff->fh;
        inarg->offset = ((loff_t) page->index << PAGE_CACHE_SHIFT);
        inarg->size = count;
        req->in.h.opcode = FUSE_WRITE;
@@ -754,7 +835,7 @@ static int fuse_commit_write(struct file *file, struct page *page,
        int err;
        struct inode *inode = page->mapping->host;
 
-       err = write_buffer(inode, page, offset, to - offset);
+       err = write_buffer(inode, file, page, offset, to - offset);
        if (!err) {
                loff_t pos = (page->index << PAGE_CACHE_SHIFT) + to;
                if (pos > i_size_read(inode))
@@ -778,6 +859,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct fuse_conn *fc = INO_FC(inode);
+       struct fuse_file *ff = file->private_data;
        char *tmpbuf;
        ssize_t res = 0;
        loff_t pos = *ppos;
@@ -801,7 +883,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count,
                        res = -EFAULT;
                        break;
                }
-               res1 = fuse_send_write(req, inode, tmpbuf, pos, nbytes);
+               res1 = fuse_send_write(req, 0, ff, inode, tmpbuf, pos, nbytes);
                if (res1 < 0) {
                        res = res1;
                        break;
@@ -852,8 +934,22 @@ static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
 
        if (fc->flags & FUSE_DIRECT_IO)
                return -ENODEV;
-       else
+       else {
+               if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) == 
+                   (VM_WRITE | VM_SHARED)) {
+                       struct fuse_inode *fi = INO_FI(inode);
+                       struct fuse_file *ff = file->private_data;
+
+                       if (!user_mmap && current->uid != 0)
+                               return -EPERM;
+
+                       down_write(&fi->write_sem);
+                       if (list_empty(&ff->ff_list))
+                               list_add(&ff->ff_list, &fi->write_files);
+                       up_write(&fi->write_sem);
+               }
                return generic_file_mmap(file, vma);
+       }
 }
 
 static struct file_operations fuse_file_operations = {
@@ -882,13 +978,6 @@ static struct address_space_operations fuse_file_aops  = {
 
 void fuse_init_file_inode(struct inode *inode)
 {
-#ifdef KERNEL_2_6
-       struct fuse_conn *fc = INO_FC(inode);
-       /* Readahead somehow defeats big reads on 2.6 (says Michael
-           Grigoriev) */
-       if (fc->flags & FUSE_LARGE_READ)
-               inode->i_mapping->backing_dev_info->ra_pages = 0;
-#endif
        inode->i_fop = &fuse_file_operations;
        inode->i_data.a_ops = &fuse_file_aops;
 }
index 2b165e941ffedb82e7fb7693d57826724a349847..c1211489aae4824932496af023df13e51ccd894e 100644 (file)
@@ -58,20 +58,32 @@ permission checking is done in the kernel */
     until the INVALIDATE operation is invoked */
 #define FUSE_KERNEL_CACHE        (1 << 2)
 
+#ifndef KERNEL_2_6
 /** Allow FUSE to combine reads into 64k chunks.  This is useful if
     the filesystem is better at handling large chunks.  NOTE: in
     current implementation the raw throughput is worse for large reads
     than for small. */
-#define FUSE_LARGE_READ          (1 << 3)
+#define FUSE_LARGE_READ          (1 << 31)
+#endif
 
 /** Bypass the page cache for read and write operations  */
-#define FUSE_DIRECT_IO           (1 << 4)
+#define FUSE_DIRECT_IO           (1 << 3)
 
 /** FUSE specific inode data */
 struct fuse_inode {
        struct fuse_req *forget_req;
        struct rw_semaphore write_sem;
        unsigned long i_time;
+       /* Files which can provide file handles in writepage.
+          Protected by write_sem  */
+       struct list_head write_files;
+};
+
+/** FUSE specific file data */
+struct fuse_file {
+       struct fuse_req *release_req;
+       unsigned int fh;
+       struct list_head ff_list;
 };
 
 /** One input argument of a request */
@@ -158,7 +170,7 @@ struct fuse_req {
                        
                } write;
                struct fuse_read_in read_in;
-               struct fuse_open_in open_in;
+               struct fuse_release_in release_in;
                struct fuse_forget_in forget_in;
        } misc;
 
index 36ec0380bdbd57f15b57f8e996c78cfb1ac58fff..894d031b6edbefe8516d9af2ff553ece98201a4c 100644 (file)
@@ -65,8 +65,10 @@ struct fuse_inode *fuse_inode_alloc(void)
                if (!fi->forget_req) {
                        kmem_cache_free(fuse_inode_cachep, fi);
                        fi = NULL;
-               } else
+               } else {
                        init_rwsem(&fi->write_sem);
+                       INIT_LIST_HEAD(&fi->write_files);
+               }
        }
 
        return fi;
@@ -74,6 +76,9 @@ struct fuse_inode *fuse_inode_alloc(void)
 
 static void fuse_inode_free(struct fuse_inode *fi)
 {
+       BUG_ON(!list_empty(&fi->write_files));
+       if (fi->forget_req)
+               fuse_request_free(fi->forget_req);
        kmem_cache_free(fuse_inode_cachep, fi);
 }
 
@@ -101,11 +106,11 @@ static void fuse_clear_inode(struct inode *inode)
        struct fuse_inode *fi = INO_FI(inode);
        
        if (fi) {
-               if (fc == NULL)
-                       fuse_request_free(fi->forget_req);
-               else 
+               if (fc) {
                        fuse_send_forget(fc, fi->forget_req, inode->i_ino,
                                         inode->i_version);
+                       fi->forget_req = NULL;
+               }
                fuse_inode_free(fi);
        }
 }
@@ -162,9 +167,18 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
        return err;
 }
 
-enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions, 
-       opt_allow_other, opt_kernel_cache, opt_large_read, opt_direct_io,
-       opt_max_read, opt_err };
+enum { opt_fd,
+       opt_rootmode,
+       opt_uid,
+       opt_default_permissions, 
+       opt_allow_other,
+       opt_kernel_cache,
+#ifndef KERNEL_2_6
+       opt_large_read,
+#endif
+       opt_direct_io,
+       opt_max_read,
+       opt_err };
 
 static match_table_t tokens = {
        {opt_fd, "fd=%u"},
@@ -173,7 +187,9 @@ static match_table_t tokens = {
        {opt_default_permissions, "default_permissions"},
        {opt_allow_other, "allow_other"},
        {opt_kernel_cache, "kernel_cache"},
+#ifndef KERNEL_2_6
        {opt_large_read, "large_read"},
+#endif
        {opt_direct_io, "direct_io"},
        {opt_max_read, "max_read=%u" },
        {opt_err, NULL}
@@ -225,9 +241,11 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
                        d->flags |= FUSE_KERNEL_CACHE;
                        break;
                        
+#ifndef KERNEL_2_6
                case opt_large_read:
                        d->flags |= FUSE_LARGE_READ;
                        break;
+#endif
                        
                case opt_direct_io:
                        d->flags |= FUSE_DIRECT_IO;
@@ -260,8 +278,10 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",allow_other");
        if (fc->flags & FUSE_KERNEL_CACHE)
                seq_puts(m, ",kernel_cache");
+#ifndef KERNEL_2_6
        if (fc->flags & FUSE_LARGE_READ)
                seq_puts(m, ",large_read");
+#endif
        if (fc->flags & FUSE_DIRECT_IO)
                seq_puts(m, ",direct_io");
        if (fc->max_read != ~0)
index 2b79d85ab9155ad3fb8e0c7650cf41e8361aa94f..80c14883d024bcb2f31f3e5ca192b75a233d40de 100644 (file)
@@ -812,6 +812,10 @@ static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name)
     res = -ENOENT;
     path = get_path_name(f, in->ino, name);
     if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("UNLINK %s\n", path);
+            fflush(stdout);
+        }
         res = -ENOSYS;
         if (f->op.unlink) {
             if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->ino, name))
@@ -835,6 +839,10 @@ static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name)
     res = -ENOENT;
     path = get_path_name(f, in->ino, name);
     if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("RMDIR %s\n", path);
+            fflush(stdout);
+        }
         res = -ENOSYS;
         if (f->op.rmdir) {
             res = f->op.rmdir(path);
@@ -891,6 +899,10 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in,
     if (oldpath != NULL) {
         newpath = get_path_name(f, newdir, newname);
         if (newpath != NULL) {
+            if (f->flags & FUSE_DEBUG) {
+                printf("RENAME %s -> %s\n", oldpath, newpath);
+                fflush(stdout);
+            }
             res = -ENOSYS;
             if (f->op.rename) {
                 res = 0;
@@ -950,6 +962,7 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
 {
     int res;
     char *path;
+    struct fuse_open_out outarg;
 
     res = -ENOENT;
     path = get_path(f, in->ino);
@@ -966,7 +979,14 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
            races with rename/unlink, against which the kernel can't
            protect */
         pthread_mutex_lock(&f->lock);
-        res2 = __send_reply(f, in, res, NULL, 0, 1);
+        f->fh_ctr ++;
+        outarg.fh = f->fh_ctr;
+        if (f->flags & FUSE_DEBUG) {
+            printf("OPEN[%u] flags: 0x%x\n", outarg.fh, arg->flags);
+            fflush(stdout);
+        }
+
+        res2 = __send_reply(f, in, res, &outarg, sizeof(outarg), 1);
         if(res2 == -ENOENT) {
             /* The open syscall was interrupted, so it must be cancelled */
             if(f->op.release)
@@ -982,7 +1002,8 @@ static void do_open(struct fuse *f, struct fuse_in_header *in,
         free(path);
 }
 
-static void do_flush(struct fuse *f, struct fuse_in_header *in)
+static void do_flush(struct fuse *f, struct fuse_in_header *in,
+                     struct fuse_flush_in *arg)
 {
     char *path;
     int res;
@@ -990,6 +1011,10 @@ static void do_flush(struct fuse *f, struct fuse_in_header *in)
     res = -ENOENT;
     path = get_path(f, in->ino);
     if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("FLUSH[%u]\n", arg->fh);
+            fflush(stdout);
+        }
         res = -ENOSYS;
         if (f->op.flush)
             res = f->op.flush(path);
@@ -999,7 +1024,7 @@ static void do_flush(struct fuse *f, struct fuse_in_header *in)
 }
 
 static void do_release(struct fuse *f, struct fuse_in_header *in,
-                       struct fuse_open_in *arg)
+                       struct fuse_release_in *arg)
 {
     struct node *node;
     char *path;
@@ -1011,6 +1036,10 @@ static void do_release(struct fuse *f, struct fuse_in_header *in,
 
     path = get_path(f, in->ino);
     if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("RELEASE[%u]\n", arg->fh);
+            fflush(stdout);
+        }
         if (f->op.release)
             f->op.release(path, arg->flags);
 
@@ -1038,7 +1067,8 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
     path = get_path(f, in->ino);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
-            printf("READ %u bytes from %llu\n", arg->size, arg->offset);
+            printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
+                   arg->offset);
             fflush(stdout);
         }
 
@@ -1053,7 +1083,7 @@ static void do_read(struct fuse *f, struct fuse_in_header *in,
         size = res;
         res = 0;
         if (f->flags & FUSE_DEBUG) {
-            printf("   READ %u bytes\n", size);
+            printf("   READ[%u] %u bytes\n", arg->fh, size);
             fflush(stdout);
         }
     }
@@ -1077,7 +1107,9 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
     path = get_path(f, in->ino);
     if (path != NULL) {
         if (f->flags & FUSE_DEBUG) {
-            printf("WRITE %u bytes to %llu\n", arg->size, arg->offset);
+            printf("WRITE%s[%u] %u bytes to %llu\n",
+                   arg->writepage ? "PAGE" : "", arg->fh, arg->size,
+                   arg->offset);
             fflush(stdout);
         }
 
@@ -1140,6 +1172,10 @@ static void do_fsync(struct fuse *f, struct fuse_in_header *in,
     res = -ENOENT;
     path = get_path(f, in->ino);
     if (path != NULL) {
+        if (f->flags & FUSE_DEBUG) {
+            printf("FSYNC[%u]\n", inarg->fh);
+            fflush(stdout);
+        }
         res = -ENOSYS;
         if (f->op.fsync)
             res = f->op.fsync(path, inarg->datasync);
@@ -1392,11 +1428,11 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
         break;
 
     case FUSE_FLUSH:
-        do_flush(f, in);
+        do_flush(f, in, (struct fuse_flush_in *) inarg);
         break;
 
     case FUSE_RELEASE:
-        do_release(f, in, (struct fuse_open_in *) inarg);
+        do_release(f, in, (struct fuse_release_in *) inarg);
         break;
 
     case FUSE_READ:
index 58c0a419a477cc1cbbec34da4a13150324a17819..38170627a13d8eb582509e15c0a9b31645d05c87 100644 (file)
@@ -47,6 +47,7 @@ struct fuse {
     fino_t ctr;
     unsigned int generation;
     unsigned int hidectr;
+    unsigned int fh_ctr;
     pthread_mutex_t lock;
     int numworker;
     int numavail;
index 7ed8300a88890a6c235056b9695d6ccd29b0a0b4..9903bcfd8e581ea941ac9ac165b921ce5575fd21 100644 (file)
@@ -16,6 +16,8 @@
  * isn't).  
  */
 
+#include <config.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -440,7 +442,11 @@ static int mount_fuse(const char *mnt, const char *opts)
     int currdir_fd = -1;
 
     fd = open(dev, O_RDWR);
-    if (fd == -1) {
+    if (fd == -1 
+#ifndef AUTO_MODPROBE
+        && getuid() == 0
+#endif
+        ) {
         int status;
         pid_t pid = fork();
         if (pid == 0) {