From: Miklos Szeredi Date: Sat, 24 Jul 2004 19:56:16 +0000 (+0000) Subject: security fixes + other enhancements X-Git-Tag: fuse_1_9~21 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=209f5d053bae91fe404a0d08aaf5bb0be1d614f0;p=qemu-gpiodev%2Flibfuse.git security fixes + other enhancements --- diff --git a/ChangeLog b/ChangeLog index 0e22882..01885b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,24 @@ 2004-07-24 Miklos Szeredi - * 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 diff --git a/configure.in b/configure.in index 9b93123..b5c25d1 100644 --- a/configure.in +++ b/configure.in @@ -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]) diff --git a/include/linux/fuse.h b/include/linux/fuse.h index d45a85b..77ad8d6 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -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; }; diff --git a/kernel/file.c b/kernel/file.c index 285957e..facd36c 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -19,12 +19,24 @@ #define PageUptodate(page) Page_Uptodate(page) #endif +static int user_mmap; +#ifdef KERNEL_2_6 +#include +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; } diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 2b165e9..c121148 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -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; diff --git a/kernel/inode.c b/kernel/inode.c index 36ec038..894d031 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -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) diff --git a/lib/fuse.c b/lib/fuse.c index 2b79d85..80c1488 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -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: diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 58c0a41..3817062 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -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; diff --git a/util/fusermount.c b/util/fusermount.c index 7ed8300..9903bcf 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -16,6 +16,8 @@ * isn't). */ +#include + #include #include #include @@ -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) {