* 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
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.
/** 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 */
#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);
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;
}
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;
}
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 {
#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 */
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;
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;
'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
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 */
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="))
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)
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));
}