From: Miklos Szeredi Date: Thu, 2 Jul 2009 12:26:36 +0000 (+0000) Subject: * The context is extended with a 'umask' field. The umask is sent X-Git-Tag: fuse_2_8_0~5 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=24b35c3d97ffdbf0a1f8e8b4e94ed892343603a6;p=qemu-gpiodev%2Flibfuse.git * 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 --- diff --git a/ChangeLog b/ChangeLog index 313a049..bfb83c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2009-07-02 Miklos Szeredi + + * 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 * Add fuse_getgroups (high level lib) and fuse_req_getgroups (low diff --git a/include/fuse.h b/include/fuse.h index a58cd9f..7429922 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -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; }; /** diff --git a/include/fuse_common.h b/include/fuse_common.h index ba341b3..291d1b7 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -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 diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index 541364f..dac35d8 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -51,6 +51,11 @@ * - 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 #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 */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index a495e15..8c04cd4 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -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 * diff --git a/lib/fuse.c b/lib/fuse.c index dad9a71..68cb603 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -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; } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 89e8f2f..32b9db3 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -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) { diff --git a/lib/fuse_session.c b/lib/fuse_session.c index 7df4795..3758627 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -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) diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 463c74f..4ab0291 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -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: *;