fix
diff --git a/ChangeLog b/ChangeLog
index 846268a..f823e11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2004-01-26 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Fix typo (thanks Marcos Dione)
+
+2004-01-23 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Fix CONFIG_MODVERSIONS compile on 2.6
+
+2004-01-22 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Write all pending data before a RELEASE operation
+
+ * Suppress 'Bad file descriptor' warning on exit
+
+ * Replaced fusermount option '-d xxx' with '-n xxx' so it doesn't
+ get confused with '-d' of fuse_main() (sorry for the change)
+
+ * New fusermount option '-l' which enables big reads
+
+ * fuse_main() can accept fusermount arguments after a '--'
+
2004-01-19 Miklos Szeredi <mszeredi@inf.bme.hu>
* Support for exporting filesystem over NFS (see README.NFS)
diff --git a/README.NFS b/README.NFS
index f3d0146..fecc436 100644
--- a/README.NFS
+++ b/README.NFS
@@ -1,11 +1,12 @@
-For the moment NFS exporting is supported on kernels versions >=
-2.6.0.
+NFS exporting is supported on kernels versions >= 2.6.0. For 2.4.X
+kernels the exporting infrastructure is not refined enough, so don't
+expect this to work.
You need to add an fsid=NNN option to /etc/exports to make exporting a
FUSE directory work.
You may get ESTALE (Stale NFS file handle) errors with this. This is
because the current FUSE kernel API and the userspace library cannot
-handle a situation where the kernel forgets about a dentry which is
+handle a situation where the kernel forgets about an inode which is
still referenced by the remote NFS client. This problem will be
addressed in a later version.
diff --git a/example/null.c b/example/null.c
index 91f2cda..f9ead78 100644
--- a/example/null.c
+++ b/example/null.c
@@ -23,7 +23,7 @@
stbuf->st_nlink = 1;
stbuf->st_uid = getuid();
stbuf->st_gid = getgid();
- stbuf->st_size = (1 << 30); /* 1G */
+ stbuf->st_size = (1ULL << 32); /* 4G */
stbuf->st_blocks = 0;
stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL);
diff --git a/include/fuse.h b/include/fuse.h
index b85f0d8..c2f0be4 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -86,7 +86,9 @@
*
* - read(), write() are not passed a filehandle, but rather a
* pathname. The offset of the read and write is passed as the last
- * argument, like the pread() and pwrite() system calls.
+ * argument, like the pread() and pwrite() system calls. (NOTE:
+ * read() should always return the number of bytes requested, except
+ * at end of file)
*
* - release() is called when an open file has:
* 1) all file descriptors closed
@@ -142,10 +144,11 @@
* main() function.
*
* This function does the following:
- * - mounts the filesystem
+ * - parses command line options (-d -s and -h)
+ * - passes all options after '--' to the fusermount program
+ * - mounts the filesystem by calling fusermount
* - installs signal handlers for INT, HUP, TERM and PIPE
* - registers an exit handler to unmount the filesystem on program exit
- * - parses command line options (-d -s and -h)
* - creates a fuse handle
* - registers the operations
* - calls either the single-threaded or the multi-threaded event loop
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index bcd85b0..909c8b0 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -12,7 +12,7 @@
#define FUSE_KERNEL_VERSION 2
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 1
+#define FUSE_KERNEL_MINOR_VERSION 2
/** The inode number of the root indode */
#define FUSE_ROOT_INO 1
@@ -53,6 +53,12 @@
until the INVALIDATE operation is invoked */
#define FUSE_KERNEL_CACHE (1 << 2)
+/** 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)
+
struct fuse_attr {
unsigned int mode;
unsigned int nlink;
diff --git a/kernel/dev.c b/kernel/dev.c
index d3c56a6..9851327 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -298,8 +298,7 @@
if(ret < 0) {
req->out->h.error = -EPROTO;
req->finished = 1;
- }
- else {
+ } else {
list_add_tail(&req->list, &fc->processing);
req->sent = 1;
}
diff --git a/kernel/dir.c b/kernel/dir.c
index 7e91639..608de2d 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -18,7 +18,7 @@
static struct file_operations fuse_dir_operations;
-static struct dentry_operations fuse_dentry_opertations;
+static struct dentry_operations fuse_dentry_operations;
/* FIXME: This should be user configurable */
#define FUSE_REVALIDATE_TIME (1 * HZ)
@@ -137,7 +137,7 @@
return err;
entry->d_time = jiffies;
- entry->d_op = &fuse_dentry_opertations;
+ entry->d_op = &fuse_dentry_operations;
*inodep = inode;
return 0;
}
@@ -769,7 +769,7 @@
#endif
};
-static struct dentry_operations fuse_dentry_opertations = {
+static struct dentry_operations fuse_dentry_operations = {
.d_revalidate = fuse_dentry_revalidate,
};
diff --git a/kernel/file.c b/kernel/file.c
index 0752943..04eb729 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -60,6 +60,9 @@
struct fuse_open_in *inarg = NULL;
unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_open_in);
+ if(file->f_mode & FMODE_WRITE)
+ filemap_fdatawrite(inode->i_mapping);
+
in = kmalloc(s, GFP_NOFS);
if(!in)
return -ENOMEM;
@@ -189,7 +192,6 @@
char *buffer;
page = grab_cache_page(mapping, index);
-
if (!page)
return -1;
@@ -241,38 +243,40 @@
return out.h.error;
}
+static void fuse_file_bigread(struct address_space *mapping,
+ struct inode *inode, loff_t pos, size_t count)
+{
+ size_t bl_index = pos >> FUSE_BLOCK_SHIFT;
+ size_t bl_end_index = (pos + count) >> FUSE_BLOCK_SHIFT;
+ size_t bl_file_end_index = inode->i_size >> FUSE_BLOCK_SHIFT;
+
+ if (bl_end_index > bl_file_end_index)
+ bl_end_index = bl_file_end_index;
+
+ while (bl_index <= bl_end_index) {
+ int res;
+ char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
+ if (!bl_buf)
+ break;
+ res = fuse_is_block_uptodate(mapping, 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);
+ kfree(bl_buf);
+ bl_index++;
+ }
+}
+
static ssize_t fuse_file_read(struct file *filp, 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 fuse_conn *fc = INO_FC(inode);
- size_t bl_index = *ppos >> FUSE_BLOCK_SHIFT;
- size_t bl_end_index = (*ppos + count) >> FUSE_BLOCK_SHIFT;
- size_t bl_file_end_index = inode->i_size >> FUSE_BLOCK_SHIFT;
-
- if (bl_end_index > bl_file_end_index)
- bl_end_index = bl_file_end_index;
-
- while (bl_index <= bl_end_index) {
- int res;
- char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS);
-
- if (!bl_buf)
- break;
-
- res = fuse_is_block_uptodate(mapping, 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);
-
- kfree(bl_buf);
-
- bl_index++;
- }
+ if(fc->flags & FUSE_LARGE_READ)
+ fuse_file_bigread(mapping, inode, *ppos, count);
return generic_file_read(filp, buf, count, ppos);
}
@@ -466,11 +470,15 @@
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;
-#ifdef KERNEL_2_6
- inode->i_mapping->backing_dev_info->ra_pages = 0;
-#endif
}
/*
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index f2e55d4..cc386ac 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -8,15 +8,25 @@
#include <linux/fuse.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#error Kernel version 2.5.* not supported
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define KERNEL_2_6
+#endif
+
+#ifndef KERNEL_2_6
#include <linux/config.h>
#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif
+#endif
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -28,15 +38,6 @@
#define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#error Kernel version 2.5.* not supported
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-#define KERNEL_2_6
-#endif
-
-
/**
* A Fuse connection.
*
diff --git a/kernel/inode.c b/kernel/inode.c
index 4a16051..f5c3a97 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -201,38 +201,35 @@
sb->s_export_op = &fuse_export_operations;
#endif
+ fc = get_conn(d);
+ if(fc == NULL)
+ return -EINVAL;
+ spin_lock(&fuse_lock);
+ if(fc->sb != NULL) {
+ printk("fuse_read_super: connection already mounted\n");
+ spin_unlock(&fuse_lock);
+ return -EINVAL;
+ }
+ fc->sb = sb;
+ fc->flags = d->flags;
+ fc->uid = d->uid;
+ spin_unlock(&fuse_lock);
+
+ /* fc is needed in fuse_init_file_inode which could be called
+ from get_root_inode */
+ SB_FC(sb) = fc;
+
root = get_root_inode(sb, d->rootmode);
if(root == NULL) {
printk("fuse_read_super: failed to get root inode\n");
return -EINVAL;
}
- spin_lock(&fuse_lock);
- fc = get_conn(d);
- if(fc == NULL)
- goto err;
-
- if(fc->sb != NULL) {
- printk("fuse_read_super: connection already mounted\n");
- goto err;
- }
-
- SB_FC(sb) = fc;
sb->s_root = d_alloc_root(root);
if(!sb->s_root)
- goto err;
+ return -EINVAL;
- fc->sb = sb;
- fc->flags = d->flags;
- fc->uid = d->uid;
- spin_unlock(&fuse_lock);
-
return 0;
-
- err:
- spin_unlock(&fuse_lock);
- iput(root);
- return -EINVAL;
}
#ifdef KERNEL_2_6
diff --git a/lib/fuse.c b/lib/fuse.c
index d382707..50ae3a8 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -1006,7 +1006,7 @@
res = read(f->fd, cmd->buf, FUSE_MAX_IN);
if(res == -1) {
free_cmd(cmd);
- if(errno == EINTR)
+ if(f->exited || errno == EINTR)
return NULL;
/* ENODEV means we got unmounted, so we silenty return failure */
diff --git a/lib/helper.c b/lib/helper.c
index d3b8b1c..d417d90 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -23,15 +23,24 @@
static void usage(char *progname)
{
fprintf(stderr,
- "usage: %s mountpoint [options] \n"
+ "usage: %s mountpoint [options] [-- [fusermount options]]\n"
"Options:\n"
" -d enable debug output\n"
" -s disable multithreaded operation\n"
- " -h print help\n",
+ " -h print help\n"
+ "\n"
+ "Fusermount options:\n"
+ " see 'fusermount -h'\n",
progname);
exit(1);
}
+static void invalid_option(char *argv[], int argctr)
+{
+ fprintf(stderr, "invalid option: %s\n", argv[argctr]);
+ usage(argv[0]);
+}
+
static void exit_handler()
{
if(fuse != NULL)
@@ -71,19 +80,51 @@
int fuse_fd;
char *fuse_mountpoint = NULL;
char umount_cmd[1024] = "";
-
- if(isreexec == NULL) {
+ char **fusermount_args = NULL;
+
+ if(!isreexec) {
if(argc < 2 || argv[1][0] == '-')
usage(argv[0]);
+ argctr ++;
+ }
+ flags = 0;
+ multithreaded = 1;
+ for(; argctr < argc && !fusermount_args; argctr ++) {
+ if(argv[argctr][0] == '-' && strlen(argv[argctr]) == 2)
+ switch(argv[argctr][1]) {
+ case 'd':
+ flags |= FUSE_DEBUG;
+ break;
+
+ case 's':
+ multithreaded = 0;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ break;
+
+ case '-':
+ if(!isreexec)
+ fusermount_args = &argv[argctr+1];
+ else
+ invalid_option(argv, argctr);
+ break;
+
+ default:
+ invalid_option(argv, argctr);
+ }
+ else
+ invalid_option(argv, argctr);
+ }
+
+ if(!isreexec) {
fuse_mountpoint = strdup(argv[1]);
- fuse_fd = fuse_mount(fuse_mountpoint, NULL);
+ fuse_fd = fuse_mount(fuse_mountpoint, (const char **) fusermount_args);
if(fuse_fd == -1)
exit(1);
-
- argctr++;
- }
- else {
+ } else {
char *tmpstr;
/* Old (obsolescent) way of doing the mount:
@@ -101,32 +142,6 @@
set_signal_handlers();
- flags = 0;
- multithreaded = 1;
- for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
- switch(argv[argctr][1]) {
- case 'd':
- flags |= FUSE_DEBUG;
- break;
-
- case 's':
- multithreaded = 0;
- break;
-
- case 'h':
- usage(argv[0]);
- break;
-
- default:
- fprintf(stderr, "invalid option: %s\n", argv[argctr]);
- exit(1);
- }
- }
- if(argctr != argc) {
- fprintf(stderr, "missing or surplus argument\n");
- exit(1);
- }
-
fuse = fuse_new(fuse_fd, flags, op);
if(multithreaded)
diff --git a/util/fusermount.c b/util/fusermount.c
index 1a6db91..1d8afd2 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -487,7 +487,8 @@
" -p check default permissions on files\n"
" -c cache in kernel space if possible\n"
" -x allow other users to access the files (only for root)\n"
- " -d name add 'name' as the filesystem name to mtab\n",
+ " -n name add 'name' as the filesystem name to mtab\n"
+ " -l issue large reads\n",
progname);
exit(1);
}
@@ -541,15 +542,19 @@
flags |= FUSE_ALLOW_OTHER;
break;
- case 'd':
+ case 'n':
a++;
if(a == argc) {
- fprintf(stderr, "%s: Missing argument to -d\n", progname);
+ fprintf(stderr, "%s: Missing argument to -n\n", progname);
exit(1);
}
fsname = argv[a];
break;
+ case 'l':
+ flags |= FUSE_LARGE_READ;
+ break;
+
default:
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]);
exit(1);