fix
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 <miklos@szeredi.hu>
* 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 @@
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 @@
/** 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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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));
}