fix
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 1 Aug 2005 11:58:51 +0000 (11:58 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 1 Aug 2005 11:58:51 +0000 (11:58 +0000)
ChangeLog
doc/kernel.txt
include/fuse_common.h
kernel/file.c
kernel/fuse_i.h
kernel/fuse_kernel.h
kernel/inode.c
lib/fuse.c
lib/fuse_lowlevel.c

index 7a9fd98fd5d468c035a70aea13416147e6c004c0..37b13d8c22906621b52a1bb65899eef412f07555 100644 (file)
--- 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
index 83f96cf56960344f1911b8107e1055511ca9cc69..6b5741e651a2a11aef2590fb4b100030756bad1c 100644 (file)
@@ -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.
index b78e977aa0b29ab4538fe1c5c03ed0ef27a27878..21109461eb2a37a8d1d4c994733035cd6633e930 100644 (file)
@@ -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 */
index 5ceea6e6ecd8ab071b3bbdb8e79792b71b4193aa..013093d1ba1d58e45873982f6c1313f1693c8f79 100644 (file)
@@ -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;
 }
index 7843a9670548452c4cbd0c555e7341e21fe45f05..4faaff7ae25bf7ffba81eb77f0b56b08dafd810c 100644 (file)
@@ -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 {
index a470bedb683e15eda8911e266dadaf805afcf965..fc99b7d67214b2d78b6d42b7066074eabae14474 100644 (file)
@@ -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 */
index 60c5ade4aff9bdd971602ebc514587b0e75dd42e..2bc2ac8bd1e2c86ac9851d1aee9f497ea87f9b70 100644 (file)
@@ -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;
index a00ef1aeea37cc6004485c13d03fdbef0412f74e..91a1e525144f2fc04c3ddfb3ed00e9a89aaa682f 100644 (file)
     '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)
index d8756641935032b3984719acc5a41f288dfed7df..98ce673aa210b274a652d9465f479aabaa05a744 100644 (file)
@@ -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));
 }