From 307242f21bf3ca7a0fb0f30da45b5956f47b0250 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 26 Jan 2004 11:28:44 +0000 Subject: [PATCH] fix --- ChangeLog | 21 +++++++++++ README.NFS | 7 ++-- example/null.c | 2 +- include/fuse.h | 9 +++-- include/linux/fuse.h | 8 ++++- kernel/dev.c | 3 +- kernel/dir.c | 6 ++-- kernel/file.c | 46 ++++++++++++++---------- kernel/fuse_i.h | 21 +++++------ kernel/inode.c | 39 ++++++++++---------- lib/fuse.c | 2 +- lib/helper.c | 85 ++++++++++++++++++++++++++------------------ util/fusermount.c | 11 ++++-- 13 files changed, 158 insertions(+), 102 deletions(-) diff --git a/ChangeLog b/ChangeLog index 846268a..f823e11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2004-01-26 Miklos Szeredi + + * Fix typo (thanks Marcos Dione) + +2004-01-23 Miklos Szeredi + + * Fix CONFIG_MODVERSIONS compile on 2.6 + +2004-01-22 Miklos Szeredi + + * 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 * 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 @@ static int null_getattr(const char *path, struct stat *stbuf) 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 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type); * * - 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 @@ extern "C" { * 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 @@ permission checking is done in the kernel */ 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 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, 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 inode_operations fuse_symlink_inode_operations; 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 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, 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 @@ static struct inode_operations fuse_symlink_inode_operations = #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 @@ static int fuse_release(struct inode *inode, struct file *file) 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 @@ static int fuse_cache_block(struct address_space *mapping, char *buffer; page = grab_cache_page(mapping, index); - if (!page) return -1; @@ -241,38 +243,40 @@ static int fuse_file_read_block(struct inode *inode, char *bl_buf, return out.h.error; } -static ssize_t fuse_file_read(struct file *filp, char *buf, - size_t count, loff_t * ppos) +static void fuse_file_bigread(struct address_space *mapping, + struct inode *inode, loff_t pos, size_t count) { - struct address_space *mapping = filp->f_dentry->d_inode->i_mapping; - struct inode *inode = mapping->host; - - size_t bl_index = *ppos >> FUSE_BLOCK_SHIFT; - size_t bl_end_index = (*ppos + count) >> FUSE_BLOCK_SHIFT; + 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); + + 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 @@ static struct address_space_operations fuse_file_aops = { void fuse_init_file_inode(struct inode *inode) { - 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; + 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 f2e55d4..cc386ac 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -8,15 +8,25 @@ #include +#include + +#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 #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include #endif +#endif #include #include -#include #include #include #include @@ -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 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &fuse_export_operations; #endif - 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; - + return -EINVAL; + spin_lock(&fuse_lock); if(fc->sb != NULL) { printk("fuse_read_super: connection already mounted\n"); - goto err; + spin_unlock(&fuse_lock); + return -EINVAL; } - - SB_FC(sb) = fc; - sb->s_root = d_alloc_root(root); - if(!sb->s_root) - goto err; - fc->sb = sb; fc->flags = d->flags; fc->uid = d->uid; spin_unlock(&fuse_lock); - return 0; + /* fc is needed in fuse_init_file_inode which could be called + from get_root_inode */ + SB_FC(sb) = fc; - err: - spin_unlock(&fuse_lock); - iput(root); - return -EINVAL; + root = get_root_inode(sb, d->rootmode); + if(root == NULL) { + printk("fuse_read_super: failed to get root inode\n"); + return -EINVAL; + } + + sb->s_root = d_alloc_root(root); + if(!sb->s_root) + return -EINVAL; + + return 0; } #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 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) 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 struct fuse *fuse; 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 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op) 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 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op) 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 @@ static void usage() " -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 @@ int main(int argc, char *argv[]) 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); -- 2.30.2