[PATCH] fuse: more flexible caching
Make data caching behavior selectable on a per-open basis instead of per-mount. Compatibility for the old mount options 'kernel_cache' and 'direct_io' is retained in the userspace library (version 2.4.0-pre1 or later). Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
04730fef1f
commit
45323fb764
|
@ -80,32 +80,6 @@ Mount options
|
||||||
allowed to root, but this restriction can be removed with a
|
allowed to root, but this restriction can be removed with a
|
||||||
(userspace) configuration option.
|
(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'
|
'max_read=N'
|
||||||
|
|
||||||
With this option the maximum size of read operations can be set.
|
With this option the maximum size of read operations can be set.
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
static struct file_operations fuse_direct_io_file_operations;
|
||||||
|
|
||||||
int fuse_open_common(struct inode *inode, struct file *file, int isdir)
|
int fuse_open_common(struct inode *inode, struct file *file, int isdir)
|
||||||
{
|
{
|
||||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||||
|
@ -70,12 +72,14 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
|
||||||
else
|
else
|
||||||
request_send(fc, req);
|
request_send(fc, req);
|
||||||
err = req->out.h.error;
|
err = req->out.h.error;
|
||||||
if (!err && !(fc->flags & FUSE_KERNEL_CACHE))
|
|
||||||
invalidate_inode_pages(inode->i_mapping);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
fuse_request_free(ff->release_req);
|
fuse_request_free(ff->release_req);
|
||||||
kfree(ff);
|
kfree(ff);
|
||||||
} else {
|
} else {
|
||||||
|
if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO))
|
||||||
|
file->f_op = &fuse_direct_io_file_operations;
|
||||||
|
if (!(outarg.open_flags & FOPEN_KEEP_CACHE))
|
||||||
|
invalidate_inode_pages(inode->i_mapping);
|
||||||
ff->fh = outarg.fh;
|
ff->fh = outarg.fh;
|
||||||
file->private_data = ff;
|
file->private_data = ff;
|
||||||
}
|
}
|
||||||
|
@ -544,12 +548,6 @@ static struct address_space_operations fuse_file_aops = {
|
||||||
|
|
||||||
void fuse_init_file_inode(struct inode *inode)
|
void fuse_init_file_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
inode->i_fop = &fuse_file_operations;
|
||||||
|
inode->i_data.a_ops = &fuse_file_aops;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,6 @@
|
||||||
doing the mount will be allowed to access the filesystem */
|
doing the mount will be allowed to access the filesystem */
|
||||||
#define FUSE_ALLOW_OTHER (1 << 1)
|
#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)
|
|
||||||
|
|
||||||
/** Bypass the page cache for read and write operations */
|
|
||||||
#define FUSE_DIRECT_IO (1 << 3)
|
|
||||||
|
|
||||||
/** FUSE inode */
|
/** FUSE inode */
|
||||||
struct fuse_inode {
|
struct fuse_inode {
|
||||||
|
|
|
@ -257,8 +257,6 @@ enum {
|
||||||
OPT_GROUP_ID,
|
OPT_GROUP_ID,
|
||||||
OPT_DEFAULT_PERMISSIONS,
|
OPT_DEFAULT_PERMISSIONS,
|
||||||
OPT_ALLOW_OTHER,
|
OPT_ALLOW_OTHER,
|
||||||
OPT_KERNEL_CACHE,
|
|
||||||
OPT_DIRECT_IO,
|
|
||||||
OPT_MAX_READ,
|
OPT_MAX_READ,
|
||||||
OPT_ERR
|
OPT_ERR
|
||||||
};
|
};
|
||||||
|
@ -270,8 +268,6 @@ static match_table_t tokens = {
|
||||||
{OPT_GROUP_ID, "group_id=%u"},
|
{OPT_GROUP_ID, "group_id=%u"},
|
||||||
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
|
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
|
||||||
{OPT_ALLOW_OTHER, "allow_other"},
|
{OPT_ALLOW_OTHER, "allow_other"},
|
||||||
{OPT_KERNEL_CACHE, "kernel_cache"},
|
|
||||||
{OPT_DIRECT_IO, "direct_io"},
|
|
||||||
{OPT_MAX_READ, "max_read=%u"},
|
{OPT_MAX_READ, "max_read=%u"},
|
||||||
{OPT_ERR, NULL}
|
{OPT_ERR, NULL}
|
||||||
};
|
};
|
||||||
|
@ -327,14 +323,6 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
|
||||||
d->flags |= FUSE_ALLOW_OTHER;
|
d->flags |= FUSE_ALLOW_OTHER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPT_KERNEL_CACHE:
|
|
||||||
d->flags |= FUSE_KERNEL_CACHE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_DIRECT_IO:
|
|
||||||
d->flags |= FUSE_DIRECT_IO;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPT_MAX_READ:
|
case OPT_MAX_READ:
|
||||||
if (match_int(&args[0], &value))
|
if (match_int(&args[0], &value))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -363,10 +351,6 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||||
seq_puts(m, ",default_permissions");
|
seq_puts(m, ",default_permissions");
|
||||||
if (fc->flags & FUSE_ALLOW_OTHER)
|
if (fc->flags & FUSE_ALLOW_OTHER)
|
||||||
seq_puts(m, ",allow_other");
|
seq_puts(m, ",allow_other");
|
||||||
if (fc->flags & FUSE_KERNEL_CACHE)
|
|
||||||
seq_puts(m, ",kernel_cache");
|
|
||||||
if (fc->flags & FUSE_DIRECT_IO)
|
|
||||||
seq_puts(m, ",direct_io");
|
|
||||||
if (fc->max_read != ~0)
|
if (fc->max_read != ~0)
|
||||||
seq_printf(m, ",max_read=%u", fc->max_read);
|
seq_printf(m, ",max_read=%u", fc->max_read);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#define FUSE_KERNEL_VERSION 7
|
#define FUSE_KERNEL_VERSION 7
|
||||||
|
|
||||||
/** Minor version number of this interface */
|
/** Minor version number of this interface */
|
||||||
#define FUSE_KERNEL_MINOR_VERSION 1
|
#define FUSE_KERNEL_MINOR_VERSION 2
|
||||||
|
|
||||||
/** The node ID of the root inode */
|
/** The node ID of the root inode */
|
||||||
#define FUSE_ROOT_ID 1
|
#define FUSE_ROOT_ID 1
|
||||||
|
@ -63,6 +63,15 @@ struct fuse_kstatfs {
|
||||||
#define FATTR_MTIME (1 << 5)
|
#define FATTR_MTIME (1 << 5)
|
||||||
#define FATTR_CTIME (1 << 6)
|
#define FATTR_CTIME (1 << 6)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags returned by the OPEN request
|
||||||
|
*
|
||||||
|
* FOPEN_DIRECT_IO: bypass page cache for this open file
|
||||||
|
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
|
||||||
|
*/
|
||||||
|
#define FOPEN_DIRECT_IO (1 << 0)
|
||||||
|
#define FOPEN_KEEP_CACHE (1 << 1)
|
||||||
|
|
||||||
enum fuse_opcode {
|
enum fuse_opcode {
|
||||||
FUSE_LOOKUP = 1,
|
FUSE_LOOKUP = 1,
|
||||||
FUSE_FORGET = 2, /* no reply */
|
FUSE_FORGET = 2, /* no reply */
|
||||||
|
|
Loading…
Reference in a new issue