aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2004-07-24 19:56:16 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2004-07-24 19:56:16 +0000
commit209f5d053bae91fe404a0d08aaf5bb0be1d614f0 (patch)
tree79d20999e8e392c5231894d52d69a0ead679a421
parentd66d3947d5d4fdda0bdde3f5299553673d4ee64e (diff)
downloadlibfuse-209f5d053bae91fe404a0d08aaf5bb0be1d614f0.tar.gz
security fixes + other enhancements
-rw-r--r--ChangeLog22
-rw-r--r--configure.in5
-rw-r--r--include/linux/fuse.h17
-rw-r--r--kernel/file.c187
-rw-r--r--kernel/fuse_i.h18
-rw-r--r--kernel/inode.c34
-rw-r--r--lib/fuse.c52
-rw-r--r--lib/fuse_i.h1
-rw-r--r--util/fusermount.c8
9 files changed, 273 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 0e22882..01885b9 100644
--- 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>
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 <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;
}
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 <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) {