From e77cc07e755c1e360455e707653f705d0bd25622 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 1 Aug 2005 11:58:51 +0000 Subject: [PATCH] fix --- ChangeLog | 9 +++++++++ doc/kernel.txt | 26 -------------------------- include/fuse_common.h | 4 ++++ kernel/file.c | 27 +++++++++++++-------------- kernel/fuse_i.h | 6 ------ kernel/fuse_kernel.h | 3 +++ kernel/inode.c | 12 ------------ lib/fuse.c | 17 +++++++++++++++++ lib/fuse_lowlevel.c | 4 ++++ 9 files changed, 50 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7a9fd98..37b13d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,15 @@ * Do not limit number of file locks being waited upon + * kernel: implement two flags, open can set: 'direct_io' and + 'keep_cache'. These correspond exactly to mount options + 'direct_io' and 'kernel_cache', but allow a per-open setting. + + * Move 'direct_io' and 'kernel_cache' mount option handling to + userspace. For both mount options, if the option is given, then + the respective open flag is set, otherwise the open flag is left + unmodified (so the filesystem can set it). + 2005-07-28 Miklos Szeredi * kernel: invalidate attributes for read/readdir/readlink diff --git a/doc/kernel.txt b/doc/kernel.txt index 83f96cf..6b5741e 100644 --- a/doc/kernel.txt +++ b/doc/kernel.txt @@ -80,32 +80,6 @@ Mount options allowed to root, but this restriction can be removed with a (userspace) configuration option. -'kernel_cache' - - This option disables flushing the cache of the file contents on - every open(). This should only be enabled on filesystems, where the - file data is never changed externally (not through the mounted FUSE - filesystem). Thus it is not suitable for network filesystems and - other "intermediate" filesystems. - - NOTE: if this option is not specified (and neither 'direct_io') data - is still cached after the open(), so a read() system call will not - always initiate a read operation. - -'direct_io' - - This option disables the use of page cache (file content cache) in - the kernel for this filesystem. This has several affects: - - - Each read() or write() system call will initiate one or more - read or write operations, data will not be cached in the - kernel. - - - The return value of the read() and write() system calls will - correspond to the return values of the read and write - operations. This is useful for example if the file size is not - known in advance (before reading it). - 'max_read=N' With this option the maximum size of read operations can be set. diff --git a/include/fuse_common.h b/include/fuse_common.h index b78e977..2110946 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -28,6 +28,10 @@ struct fuse_file_info { /** Can be filled in by open, to use direct I/O on this file */ unsigned int direct_io : 1; + + /** Can be filled in by open, to indicate, that cached file data + need not be invalidated */ + unsigned int keep_cache : 1; }; /** Structure containing a raw command */ diff --git a/kernel/file.c b/kernel/file.c index 5ceea6e..013093d 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -16,6 +16,8 @@ #define PageUptodate(page) Page_Uptodate(page) #define clear_page_dirty(page) ClearPageDirty(page) #endif +static struct file_operations fuse_direct_io_file_operations; + int fuse_open_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -65,16 +67,19 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; - if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) -#ifdef KERNEL_2_6 - invalidate_inode_pages(inode->i_mapping); -#else - invalidate_inode_pages(inode); -#endif if (err) { fuse_request_free(ff->release_req); kfree(ff); } else { + if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO)) + file->f_op = &fuse_direct_io_file_operations; + if (!(outarg.open_flags & FOPEN_KEEP_CACHE)) { +#ifdef KERNEL_2_6 + invalidate_inode_pages(inode->i_mapping); +#else + invalidate_inode_pages(inode); +#endif + } ff->fh = outarg.fh; file->private_data = ff; } @@ -814,12 +819,6 @@ static struct address_space_operations fuse_file_aops = { void fuse_init_file_inode(struct inode *inode) { - struct fuse_conn *fc = get_fuse_conn(inode); - - if (fc->flags & FUSE_DIRECT_IO) - inode->i_fop = &fuse_direct_io_file_operations; - else { - inode->i_fop = &fuse_file_operations; - inode->i_data.a_ops = &fuse_file_aops; - } + 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 7843a96..4faaff7 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -90,17 +90,11 @@ static inline void set_page_dirty_lock(struct page *page) doing the mount will be allowed to access the filesystem */ #define FUSE_ALLOW_OTHER (1 << 1) -/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not - be flushed on open */ -#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 */ #define FUSE_LARGE_READ (1 << 31) #endif -/** Bypass the page cache for read and write operations */ -#define FUSE_DIRECT_IO (1 << 3) /** FUSE inode */ struct fuse_inode { diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index a470bed..fc99b7d 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -71,6 +71,9 @@ struct fuse_file_lock { #define FATTR_MTIME (1 << 5) #define FATTR_CTIME (1 << 6) +#define FOPEN_DIRECT_IO (1 << 0) +#define FOPEN_KEEP_CACHE (1 << 1) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ diff --git a/kernel/inode.c b/kernel/inode.c index 60c5ade..2bc2ac8 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -402,19 +402,11 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->flags |= FUSE_ALLOW_OTHER; break; - case OPT_KERNEL_CACHE: - 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; - break; - case OPT_MAX_READ: if (match_int(&args[0], &value)) return 0; @@ -443,14 +435,10 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",default_permissions"); if (fc->flags & FUSE_ALLOW_OTHER) 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) seq_printf(m, ",max_read=%u", fc->max_read); return 0; diff --git a/lib/fuse.c b/lib/fuse.c index a00ef1a..91a1e52 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -53,6 +53,12 @@ 'gid' option*/ #define FUSE_SET_GID (1 << 8) +/** Bypass the page cache for read and write operations */ +#define FUSE_DIRECT_IO (1 << 9) + +/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not + be flushed on open */ +#define FUSE_KERNEL_CACHE (1 << 10) #define FUSE_MAX_PATH 4096 @@ -978,6 +984,11 @@ static void fuse_open(fuse_req_t req, fuse_ino_t ino, fflush(stdout); } + if (f->flags & FUSE_DIRECT_IO) + fi->direct_io = 1; + if (f->flags & FUSE_KERNEL_CACHE) + fi->keep_cache = 1; + pthread_mutex_lock(&f->lock); if (fuse_reply_open(req, fi) == -ENOENT) { /* The open syscall was interrupted, so it must be cancelled */ @@ -1673,6 +1684,8 @@ int fuse_is_lib_option(const char *opt) strcmp(opt, "use_ino") == 0 || strcmp(opt, "allow_root") == 0 || strcmp(opt, "readdir_ino") == 0 || + strcmp(opt, "direct_io") == 0 || + strcmp(opt, "kernel_cache") == 0 || begins_with(opt, "umask=") || begins_with(opt, "uid=") || begins_with(opt, "gid=")) @@ -1708,6 +1721,10 @@ static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts) f->flags |= FUSE_USE_INO; else if (strcmp(opt, "readdir_ino") == 0) f->flags |= FUSE_READDIR_INO; + else if (strcmp(opt, "direct_io") == 0) + f->flags |= FUSE_DIRECT_IO; + else if (strcmp(opt, "kernel_cache") == 0) + f->flags |= FUSE_KERNEL_CACHE; else if (sscanf(opt, "umask=%o", &f->umask) == 1) f->flags |= FUSE_SET_MODE; else if (sscanf(opt, "uid=%u", &f->uid) == 1) diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index d875664..98ce673 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -342,6 +342,10 @@ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) memset(&arg, 0, sizeof(arg)); arg.fh = f->fh; + if (f->direct_io) + arg.open_flags |= FOPEN_DIRECT_IO; + if (f->keep_cache) + arg.open_flags |= FOPEN_KEEP_CACHE; return send_reply_req(req, &arg, sizeof(arg)); } -- 2.30.2