Don't allow bigger than 4kB writes by default...
authorMiklos Szeredi <miklos@szeredi.hu>
Mon, 9 Jun 2008 10:52:50 +0000 (10:52 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Mon, 9 Jun 2008 10:52:50 +0000 (10:52 +0000)
ChangeLog
include/fuse_common.h
kernel/fuse_kernel.h
lib/fuse_lowlevel.c

index 411df3c88acad15f506aa8f9caf03d949128030a..84d92ae61d32fd87ccaeba19e94b25109d398984 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,14 @@
 
        * Fix mounting over symlink.  Reported by Szabolcs Szakacsits
 
+2008-05-09  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Don't allow bigger than 4kB writes by default on 2.6.26 and
+       later kernels, so that filesystems not expecting this are not
+       broken on a kernel upgrade.  Provide a 'big_writes' mount option
+       to enable this feature.  In future API revisions this may become
+       the default.
+
 2008-04-09  Miklos Szeredi <miklos@szeredi.hu>
 
        * Update warning message for missing newline at end of fuse.conf
index 103013919d5a7e180d9e09e474a9bc6f157b9a44..2543225d40001be6f96caccb2f79a2d79ce17cf8 100644 (file)
@@ -76,6 +76,19 @@ struct fuse_file_info {
        uint64_t lock_owner;
 };
 
+/**
+ * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want'
+ *
+ * FUSE_CAP_ASYNC_READ: filesystem supports asynchronous read requests
+ * FUSE_CAP_POSIX_LOCKS: filesystem supports "remote" locking
+ * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
+ * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
+ */
+#define FUSE_CAP_ASYNC_READ    (1 << 0)
+#define FUSE_CAP_POSIX_LOCKS   (1 << 1)
+#define FUSE_CAP_ATOMIC_O_TRUNC        (1 << 3)
+#define FUSE_CAP_BIG_WRITES    (1 << 5)
+
 /**
  * Connection information, passed to the ->init() method
  *
@@ -110,14 +123,19 @@ struct fuse_conn_info {
        unsigned max_readahead;
 
        /**
-        * Is atomic open+truncate supported
+        * Capability flags, that the kernel supports
+        */
+       unsigned capable;
+
+       /**
+        * Capability flags, that the filesystem wants to enable
         */
-       unsigned atomic_o_trunc;
+       unsigned want;
 
        /**
         * For future use.
         */
-       unsigned reserved[26];
+       unsigned reserved[25];
 };
 
 struct fuse_session;
index 53682cf0f051a1a0ff433a23fdc0ec61195c9736..c9c4c7e557bf0324e6dec22069e3da4a2d6b512b 100644 (file)
@@ -142,6 +142,7 @@ struct fuse_file_lock {
 #define FUSE_POSIX_LOCKS       (1 << 1)
 #define FUSE_FILE_OPS          (1 << 2)
 #define FUSE_ATOMIC_O_TRUNC    (1 << 3)
+#define FUSE_BIG_WRITES                (1 << 5)
 
 /**
  * Release flags
index bae6199e5bb19a56840e8a85409db9788c1446fc..048b2ccb76736bb0e6b0bf3e97a965945ca3622e 100644 (file)
@@ -51,6 +51,8 @@ struct fuse_req {
 struct fuse_ll {
        int debug;
        int allow_root;
+       int atomic_o_trunc;
+       int big_writes;
        struct fuse_lowlevel_ops op;
        int got_init;
        void *userdata;
@@ -1009,6 +1011,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
        }
        f->conn.proto_major = arg->major;
        f->conn.proto_minor = arg->minor;
+       f->conn.capable = 0;
+       f->conn.want = 0;
 
        if (arg->major < 7) {
                fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
@@ -1022,14 +1026,26 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
                        f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
                if (arg->max_readahead < f->conn.max_readahead)
                        f->conn.max_readahead = arg->max_readahead;
-               if (f->conn.atomic_o_trunc)
-                       f->conn.atomic_o_trunc = arg->flags & FUSE_ATOMIC_O_TRUNC;
+               if (arg->flags & FUSE_ASYNC_READ)
+                       f->conn.capable |= FUSE_CAP_ASYNC_READ;
+               if (arg->flags & FUSE_POSIX_LOCKS)
+                       f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
+               if (arg->flags & FUSE_ATOMIC_O_TRUNC)
+                       f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
+               if (arg->flags & FUSE_BIG_WRITES)
+                       f->conn.capable |= FUSE_CAP_BIG_WRITES;
        } else {
                f->conn.async_read = 0;
                f->conn.max_readahead = 0;
-               f->conn.atomic_o_trunc = 0;
        }
 
+       if (f->atomic_o_trunc)
+               f->conn.want |= FUSE_CAP_ATOMIC_O_TRUNC;
+       if (f->op.getlk && f->op.setlk)
+               f->conn.want |= FUSE_CAP_POSIX_LOCKS;
+       if (f->big_writes)
+               f->conn.want |= FUSE_CAP_BIG_WRITES;
+
        if (bufsize < FUSE_MIN_READ_BUFFER) {
                fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
                        bufsize);
@@ -1047,12 +1063,14 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
        memset(&outarg, 0, sizeof(outarg));
        outarg.major = FUSE_KERNEL_VERSION;
        outarg.minor = FUSE_KERNEL_MINOR_VERSION;
-       if (f->conn.async_read)
+       if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
                outarg.flags |= FUSE_ASYNC_READ;
-       if (f->op.getlk && f->op.setlk)
+       if (f->conn.want & FUSE_CAP_POSIX_LOCKS)
                outarg.flags |= FUSE_POSIX_LOCKS;
-       if (f->conn.atomic_o_trunc)
+       if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
                outarg.flags |= FUSE_ATOMIC_O_TRUNC;
+       if (f->conn.want & FUSE_CAP_BIG_WRITES)
+               outarg.flags |= FUSE_BIG_WRITES;
        outarg.max_readahead = f->conn.max_readahead;
        outarg.max_write = f->conn.max_write;
 
@@ -1233,7 +1251,8 @@ static struct fuse_opt fuse_ll_opts[] = {
        { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
        { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
        { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
-       { "atomic_o_trunc", offsetof(struct fuse_ll, conn.atomic_o_trunc), 1},
+       { "atomic_o_trunc", offsetof(struct fuse_ll, atomic_o_trunc), 1},
+       { "big_writes", offsetof(struct fuse_ll, big_writes), 1},
        FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
        FUSE_OPT_KEY("-h", KEY_HELP),
        FUSE_OPT_KEY("--help", KEY_HELP),
@@ -1255,7 +1274,8 @@ static void fuse_ll_help(void)
 "    -o max_readahead=N     set maximum readahead\n"
 "    -o async_read          perform reads asynchronously (default)\n"
 "    -o sync_read           perform reads synchronously\n"
-"    -o atomic_o_trunc      enable atomic open+truncate support\n");
+"    -o atomic_o_trunc      enable atomic open+truncate support\n"
+"    -o big_writes          enable larger than 4kB writes\n");
 }
 
 static int fuse_ll_opt_proc(void *data, const char *arg, int key,
@@ -1327,7 +1347,7 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
        f->conn.async_read = 1;
        f->conn.max_write = UINT_MAX;
        f->conn.max_readahead = UINT_MAX;
-       f->conn.atomic_o_trunc = 0;
+       f->atomic_o_trunc = 0;
        list_init_req(&f->list);
        list_init_req(&f->interrupts);
        fuse_mutex_init(&f->lock);