* The context is extended with a 'umask' field. The umask is sent
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 2 Jul 2009 12:26:36 +0000 (12:26 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 2 Jul 2009 12:26:36 +0000 (12:26 +0000)
for mknod, mkdir and create requests by linux kernel version
2.6.31 or later, otherwise the umask is set to zero.  Also
introduce a new feature flag: FUSE_CAP_DONT_MASK.  If the kernel
supports this feature, then this flag will be set in conn->capable
in the ->init() method.  If the filesystem sets this flag in in
conn->want, then the create modes will not be masked.

* Add low level interfaces for lookup cache and attribute
invalidation.  This feature is available in linux kernels 2.6.31
or later.  Patch by John Muir

* Kernel interface version is now 7.12

ChangeLog
include/fuse.h
include/fuse_common.h
include/fuse_kernel.h
include/fuse_lowlevel.h
lib/fuse.c
lib/fuse_lowlevel.c
lib/fuse_session.c
lib/fuse_versionscript

index 313a049529d6cee9fee367fb3292189d3e37633a..bfb83c4fc0a36bd13bbd74a1865aa40c9b135a5b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2009-07-02  Miklos Szeredi <miklos@szeredi.hu>
+
+       * The context is extended with a 'umask' field.  The umask is sent
+       for mknod, mkdir and create requests by linux kernel version
+       2.6.31 or later, otherwise the umask is set to zero.  Also
+       introduce a new feature flag: FUSE_CAP_DONT_MASK.  If the kernel
+       supports this feature, then this flag will be set in conn->capable
+       in the ->init() method.  If the filesystem sets this flag in in
+       conn->want, then the create modes will not be masked.
+
+       * Add low level interfaces for lookup cache and attribute
+       invalidation.  This feature is available in linux kernels 2.6.31
+       or later.  Patch by John Muir
+
+       * Kernel interface version is now 7.12
+
 2009-06-19  Miklos Szeredi <miklos@szeredi.hu>
 
        * Add fuse_getgroups (high level lib) and fuse_req_getgroups (low
index a58cd9f1aadc23b53dd06ac1e37aa3ed9baec0a2..7429922763c14e94e3e65b29642cff9b1d9cf3fb 100644 (file)
@@ -518,6 +518,9 @@ struct fuse_context {
 
        /** Private filesystem data */
        void *private_data;
+
+       /** Umask of the calling process (introduced in version 2.8) */
+       mode_t umask;
 };
 
 /**
index ba341b3abc5e93e56986cebe50319726ee13b33d..291d1b7b860ecd6b7a65bbd92d54c59134b52aa2 100644 (file)
@@ -88,12 +88,14 @@ struct fuse_file_info {
  * FUSE_CAP_ATOMIC_O_TRUNC: filesystem handles the O_TRUNC open flag
  * FUSE_CAP_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
  * FUSE_CAP_BIG_WRITES: filesystem can handle write size larger than 4kB
+ * FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
  */
 #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_EXPORT_SUPPORT        (1 << 4)
 #define FUSE_CAP_BIG_WRITES    (1 << 5)
+#define FUSE_CAP_DONT_MASK     (1 << 6)
 
 /**
  * Ioctl flags
index 541364fcccc77cd9c56c6c6b83000481bc32037a..dac35d8b9b19dec3c40ab9d48002e0d38a28262a 100644 (file)
  *  - add IOCTL message
  *  - add unsolicited notification support
  *  - add POLL message and NOTIFY_POLL notification
+ *
+ * 7.12
+ *  - add umask flag to input argument of open, mknod and mkdir
+ *  - add notification messages for invalidation of inodes and
+ *    directory entries
  */
 
 #ifndef _LINUX_FUSE_H
@@ -58,6 +63,7 @@
 
 #include <sys/types.h>
 #define __u64 uint64_t
+#define __s64 int64_t
 #define __u32 uint32_t
 #define __s32 int32_t
 
@@ -65,7 +71,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 11
+#define FUSE_KERNEL_MINOR_VERSION 12
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -141,6 +147,7 @@ struct fuse_file_lock {
  * INIT request/reply flags
  *
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -148,6 +155,7 @@ struct fuse_file_lock {
 #define FUSE_ATOMIC_O_TRUNC    (1 << 3)
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
+#define FUSE_DONT_MASK         (1 << 6)
 
 /**
  * CUSE INIT request/reply flags
@@ -253,6 +261,8 @@ enum fuse_opcode {
 
 enum fuse_notify_code {
        FUSE_NOTIFY_POLL   = 1,
+       FUSE_NOTIFY_INVAL_INODE = 2,
+       FUSE_NOTIFY_INVAL_ENTRY = 3,
        FUSE_NOTIFY_CODE_MAX,
 };
 
@@ -291,14 +301,18 @@ struct fuse_attr_out {
        struct fuse_attr attr;
 };
 
+#define FUSE_COMPAT_MKNOD_IN_SIZE 8
+
 struct fuse_mknod_in {
        __u32   mode;
        __u32   rdev;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_mkdir_in {
        __u32   mode;
-       __u32   padding;
+       __u32   umask;
 };
 
 struct fuse_rename_in {
@@ -329,8 +343,15 @@ struct fuse_setattr_in {
 };
 
 struct fuse_open_in {
+       __u32   flags;
+       __u32   unused;
+};
+
+struct fuse_create_in {
        __u32   flags;
        __u32   mode;
+       __u32   umask;
+       __u32   padding;
 };
 
 struct fuse_open_out {
@@ -537,4 +558,16 @@ struct fuse_dirent {
 #define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
 
+struct fuse_notify_inval_inode_out {
+       __u64   ino;
+       __s64   off;
+       __s64   len;
+};
+
+struct fuse_notify_inval_entry_out {
+       __u64   parent;
+       __u32   namelen;
+       __u32   padding;
+};
+
 #endif /* _LINUX_FUSE_H */
index a495e15d0b5d25685406fdc16d4d99715044c3cf..8c04cd4c52fe1d7362f376f184b20805694e0b02 100644 (file)
@@ -109,6 +109,9 @@ struct fuse_ctx {
 
        /** Thread ID of the calling process */
        pid_t pid;
+
+       /** Umask of the calling process (introduced in version 2.8) */
+       mode_t umask;
 };
 
 /* 'to_set' flags in setattr */
@@ -1151,6 +1154,32 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents);
  */
 int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
 
+/**
+ * Notify to invalidate cache for an inode
+ *
+ * @param ch the channel through which to send the invalidation
+ * @param ino the inode number
+ * @param off the offset in the inode where to start invalidating
+ *            or negative to invalidate attributes only
+ * @param len the amount of cache to invalidate or 0 for all
+ * @return zero for success, -errno for failure
+ */
+int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
+                                     off_t off, off_t len);
+
+/**
+ * Notify to invalidate parent attributes and the dentry matching
+ * parent/name
+ *
+ * @param ch the channel through which to send the invalidation
+ * @param parent inode number
+ * @param name file name
+ * @param namelen strlen() of file name
+ * @return zero for success, -errno for failure
+ */
+int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
+                                     const char *name, size_t namelen);
+
 /* ----------------------------------------------------------- *
  * Utility functions                                          *
  * ----------------------------------------------------------- */
@@ -1375,6 +1404,14 @@ void fuse_session_reset(struct fuse_session *se);
  */
 int fuse_session_exited(struct fuse_session *se);
 
+/**
+ * Get the user data provided to the session
+ *
+ * @param se the session
+ * @return the user data
+ */
+void *fuse_session_data(struct fuse_session *se);
+
 /**
  * Enter a single threaded event loop
  *
index dad9a711bd75a52858548eb78f8903a118db2223..68cb60394d2fd814b1b6cf8bea27b0cbb8b901d2 100644 (file)
@@ -1422,8 +1422,10 @@ int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
                int err;
 
                if (fs->debug)
-                       fprintf(stderr, "create flags: 0x%x %s\n", fi->flags,
-                               path);
+                       fprintf(stderr,
+                               "create flags: 0x%x %s 0%o umask=0%03o\n",
+                               fi->flags, path, mode,
+                               fuse_get_context()->umask);
 
                err = fs->op.create(path, mode, fi);
 
@@ -1572,8 +1574,9 @@ int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
        fuse_get_context()->private_data = fs->user_data;
        if (fs->op.mknod) {
                if (fs->debug)
-                       fprintf(stderr, "mknod %s 0%o 0x%llx\n", path,
-                               mode, (unsigned long long) rdev);
+                       fprintf(stderr, "mknod %s 0%o 0x%llx umask=0%03o\n",
+                               path, mode, (unsigned long long) rdev,
+                               fuse_get_context()->umask);
 
                return fs->op.mknod(path, mode, rdev);
        } else {
@@ -1586,7 +1589,8 @@ int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
        fuse_get_context()->private_data = fs->user_data;
        if (fs->op.mkdir) {
                if (fs->debug)
-                       fprintf(stderr, "mkdir %s 0%o\n", path, mode);
+                       fprintf(stderr, "mkdir %s 0%o umask=0%03o\n",
+                               path, mode, fuse_get_context()->umask);
 
                return fs->op.mkdir(path, mode);
        } else {
@@ -1909,6 +1913,7 @@ static struct fuse *req_fuse_prepare(fuse_req_t req)
        c->ctx.uid = ctx->uid;
        c->ctx.gid = ctx->gid;
        c->ctx.pid = ctx->pid;
+       c->ctx.umask = ctx->umask;
        return c->ctx.fuse;
 }
 
index 89e8f2fe630888057f80542fc245d9f115e5c57d..32b9db312245672057a4429b16a375670cdd3041 100644 (file)
@@ -606,9 +606,15 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 {
        struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
+       char *name = PARAM(arg);
+
+       if (req->f->conn.proto_minor >= 12)
+               req->ctx.umask = arg->umask;
+       else
+               name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
 
        if (req->f->op.mknod)
-               req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
+               req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
        else
                fuse_reply_err(req, ENOSYS);
 }
@@ -617,6 +623,9 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 {
        struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
 
+       if (req->f->conn.proto_minor >= 12)
+               req->ctx.umask = arg->umask;
+
        if (req->f->op.mkdir)
                req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
        else
@@ -678,15 +687,21 @@ static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 
 static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 {
-       struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
+       struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
 
        if (req->f->op.create) {
                struct fuse_file_info fi;
+               char *name = PARAM(arg);
 
                memset(&fi, 0, sizeof(fi));
                fi.flags = arg->flags;
 
-               req->f->op.create(req, nodeid, PARAM(arg), arg->mode, &fi);
+               if (req->f->conn.proto_minor >= 12)
+                       req->ctx.umask = arg->umask;
+               else
+                       name = (char *) inarg + sizeof(struct fuse_open_in);
+
+               req->f->op.create(req, nodeid, name, arg->mode, &fi);
        } else
                fuse_reply_err(req, ENOSYS);
 }
@@ -1168,6 +1183,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
                        f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
                if (arg->flags & FUSE_BIG_WRITES)
                        f->conn.capable |= FUSE_CAP_BIG_WRITES;
+               if (arg->flags & FUSE_DONT_MASK)
+                       f->conn.capable |= FUSE_CAP_DONT_MASK;
        } else {
                f->conn.async_read = 0;
                f->conn.max_readahead = 0;
@@ -1207,6 +1224,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
                outarg.flags |= FUSE_EXPORT_SUPPORT;
        if (f->conn.want & FUSE_CAP_BIG_WRITES)
                outarg.flags |= FUSE_BIG_WRITES;
+       if (f->conn.want & FUSE_CAP_DONT_MASK)
+               outarg.flags |= FUSE_DONT_MASK;
        outarg.max_readahead = f->conn.max_readahead;
        outarg.max_write = f->conn.max_write;
 
@@ -1270,6 +1289,56 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
        }
 }
 
+int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
+                                     off_t off, off_t len)
+{
+       struct fuse_notify_inval_inode_out outarg;
+       struct fuse_ll *f;
+       struct iovec iov[2];
+
+       if (!ch)
+               return -EINVAL;
+
+       f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
+       if (!f)
+               return -ENODEV;
+
+       outarg.ino = ino;
+       outarg.off = off;
+       outarg.len = len;
+
+       iov[1].iov_base = &outarg;
+       iov[1].iov_len = sizeof(outarg);
+
+       return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+}
+
+int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
+                                     const char *name, size_t namelen)
+{
+       struct fuse_notify_inval_entry_out outarg;
+       struct fuse_ll *f;
+       struct iovec iov[3];
+
+       if (!ch)
+               return -EINVAL;
+
+       f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
+       if (!f)
+               return -ENODEV;
+
+       outarg.parent = parent;
+       outarg.namelen = namelen;
+       outarg.padding = 0;
+
+       iov[1].iov_base = &outarg;
+       iov[1].iov_len = sizeof(outarg);
+       iov[2].iov_base = (void *)name;
+       iov[2].iov_len = namelen + 1;
+
+       return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+}
+
 void *fuse_req_userdata(fuse_req_t req)
 {
        return req->f->userdata;
@@ -1280,6 +1349,19 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
        return &req->ctx;
 }
 
+/*
+ * The size of fuse_ctx got extended, so need to be careful about
+ * incompatibility (i.e. a new binary cannot work with an old
+ * library).
+ */
+const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
+const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
+{
+       return fuse_req_ctx(req);
+}
+FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
+
+
 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
                             void *data)
 {
index 7df47950e194fa0f21eb5b9f87984d3d696fde4d..3758627de4e627c3694a5ac08b974625e8b123f4 100644 (file)
@@ -111,6 +111,11 @@ int fuse_session_exited(struct fuse_session *se)
                return se->exited;
 }
 
+void *fuse_session_data(struct fuse_session *se)
+{
+       return se->data;
+}
+
 static struct fuse_chan *fuse_chan_new_common(struct fuse_chan_ops *op, int fd,
                                              size_t bufsize, void *data,
                                              int compat)
index 463c74f654a85f219e0e549394a3071f9bb43797..4ab02918841657c67c2d3a0a2988cfa343bac1fa 100644 (file)
@@ -3,7 +3,6 @@ FUSE_2.2 {
                fuse_destroy;
                fuse_exit;
                fuse_exited;
-               fuse_get_context;
                fuse_invalidate;
                fuse_is_lib_option;
                fuse_loop;
@@ -43,7 +42,6 @@ FUSE_2.4 {
                fuse_reply_readlink;
                fuse_reply_write;
                fuse_reply_xattr;
-               fuse_req_ctx;
                fuse_req_userdata;
                fuse_session_add_chan;
                fuse_session_destroy;
@@ -176,6 +174,10 @@ FUSE_2.8 {
                fuse_reply_poll;
                fuse_req_getgroups;
                fuse_getgroups;
+               fuse_req_ctx;
+               fuse_get_context;
+               fuse_lowlevel_notify_inval_inode;
+               fuse_lowlevel_notify_inval_entry;
 
        local:
                *;