From 4b2157c44e6ad7e692fcffb7450143e83151d36b Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 6 Dec 2011 18:06:18 +0100 Subject: [PATCH] Add mmap() and munmap() methods to low level API Currently this is only useful for CUSE. Also update retrieve_reply() method. --- ChangeLog | 7 +++++ include/cuse_lowlevel.h | 7 +++++ include/fuse_kernel.h | 25 +++++++++++++++ include/fuse_lowlevel.h | 53 +++++++++++++++++++++++++++++-- lib/cuse_lowlevel.c | 26 +++++++++++++++ lib/fuse_lowlevel.c | 70 +++++++++++++++++++++++++++++++++++++---- lib/fuse_versionscript | 1 + 7 files changed, 181 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6269954..636dddc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-12-06 Miklos Szeredi + + * Add mmap() and munmap() methods to low level API. Currently + this is only useful for CUSE + + * Update retrieve_reply() method + 2011-12-05 Miklos Szeredi * Low level API: lock argument of fuse_reply_lock should have a diff --git a/include/cuse_lowlevel.h b/include/cuse_lowlevel.h index e147fa2..b8824fb 100644 --- a/include/cuse_lowlevel.h +++ b/include/cuse_lowlevel.h @@ -63,6 +63,13 @@ struct cuse_lowlevel_ops { const void *in_buf, size_t in_bufsz, size_t out_bufsz); void (*poll) (fuse_req_t req, struct fuse_file_info *fi, struct fuse_pollhandle *ph); + void (*mmap) (fuse_req_t req, uint64_t addr, size_t length, + int prot, int flags, off_t offset, + struct fuse_file_info *fi); + void (*munmap) (fuse_req_t req, uint64_t map_id, size_t length, + struct fuse_file_info *fi); + void (*retrieve_reply) (fuse_req_t req, void *cookie, uint64_t map_id, + off_t offset, struct fuse_bufvec *bufv); }; struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index eb8c790..039eb1f 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -79,6 +79,7 @@ * * 7.18 * - add FUSE_IOCTL_DIR flag + * - add FUSE_MMAP and FUSE_MUNMAP */ #ifndef _LINUX_FUSE_H @@ -308,6 +309,8 @@ enum fuse_opcode { FUSE_POLL = 40, FUSE_NOTIFY_REPLY = 41, FUSE_BATCH_FORGET = 42, + FUSE_MMAP = 43, + FUSE_MUNMAP = 44, /* CUSE specific operations */ CUSE_INIT = 4096, @@ -600,6 +603,28 @@ struct fuse_notify_poll_wakeup_out { __u64 kh; }; +struct fuse_mmap_in { + __u64 fh; + __u64 addr; + __u64 len; + __u32 prot; + __u32 flags; + __u64 offset; +}; + +struct fuse_mmap_out { + __u64 mapid; /* Mmap ID, same namespace as Inode ID */ + __u64 size; /* Size of memory region */ + __u64 reserved; +}; + +struct fuse_munmap_in { + __u64 fh; + __u64 mapid; + __u64 size; /* Size of memory region */ + __u64 reserved; +}; + struct fuse_in_header { __u32 len; __u32 opcode; diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 51aea39..6435937 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -911,13 +911,19 @@ struct fuse_lowlevel_ops { /** * Callback function for the retrieve request * + * Introduced in version 2.9 + * + * Valid replies: + * fuse_reply_none + * + * @param req request handle * @param cookie user data supplied to fuse_lowlevel_notify_retrieve() * @param ino the inode number supplied to fuse_lowlevel_notify_retrieve() * @param offset the offset supplied to fuse_lowlevel_notify_retrieve() * @param bufv the buffer containing the returned data */ - void (*retrieve_reply) (void *cookie, fuse_ino_t ino, off_t offset, - struct fuse_bufvec *bufv); + void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, + off_t offset, struct fuse_bufvec *bufv); /** * Forget about multiple inodes @@ -951,6 +957,37 @@ struct fuse_lowlevel_ops { */ void (*flock) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op); + + /** + * Direct mmap (CUSE only for now) + * + * @param req request handle + * @param ino the inode number + * @param addr starting address (in clients address space) + * @param length length of the mapping + * @param prot desired memory protection of the mapping + * @param flags mmap flags + * @param fi file information + * + * Introduced in version 2.9 + */ + void (*mmap) (fuse_req_t req, fuse_ino_t ino, uint64_t addr, + size_t length, int prot, int flags, off_t offset, + struct fuse_file_info *fi); + + /** + * Direct munmap (CUSE only for now) + * + * @param req request handle + * @param ino the inode number + * @param map_id identifies the mapping + * @param length length of the mapping + * @param fi file information + * + * Introduced in version 2.9 + */ + void (*munmap) (fuse_req_t req, fuse_ino_t ino, uint64_t map_id, + size_t length, struct fuse_file_info *fi); }; /** @@ -1234,6 +1271,18 @@ int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, */ int fuse_reply_poll(fuse_req_t req, unsigned revents); +/** + * Reply to an mmap request + * + * Possible requests: + * mmap + * + * @param req request handle + * @param map_id identifies the mapping + * @param length length of the mapping (from zero offset) + */ +int fuse_reply_mmap(fuse_req_t req, uint64_t map_id, size_t length); + /* ----------------------------------------------------------- * * Notification * * ----------------------------------------------------------- */ diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c index 402cf4b..7bd289a 100644 --- a/lib/cuse_lowlevel.c +++ b/lib/cuse_lowlevel.c @@ -93,6 +93,28 @@ static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino, req_clop(req)->poll(req, fi, ph); } +static void cuse_fll_mmap(fuse_req_t req, fuse_ino_t ino, uint64_t addr, + size_t length, int prot, int flags, off_t offset, + struct fuse_file_info *fi) +{ + (void)ino; + req_clop(req)->mmap(req, addr, length, prot, flags, offset, fi); +} + +static void cuse_fll_munmap(fuse_req_t req, fuse_ino_t ino, uint64_t map_id, + size_t length, struct fuse_file_info *fi) +{ + (void)ino; + req_clop(req)->munmap(req, map_id, length, fi); +} + +static void cuse_fll_retrieve_reply(fuse_req_t req, void *cookie, + fuse_ino_t ino, off_t offset, + struct fuse_bufvec *bufv) +{ + req_clop(req)->retrieve_reply(req, cookie, ino, offset, bufv); +} + static size_t cuse_pack_info(int argc, const char **argv, char *buf) { size_t size = 0; @@ -169,6 +191,10 @@ struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; lop.poll = clop->poll ? cuse_fll_poll : NULL; + lop.mmap = clop->mmap ? cuse_fll_mmap : NULL; + lop.munmap = clop->munmap ? cuse_fll_munmap : NULL; + lop.retrieve_reply = clop->retrieve_reply ? + cuse_fll_retrieve_reply : NULL; se = fuse_lowlevel_new_common(args, &lop, sizeof(lop), userdata); if (!se) { diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 8012d49..f69b2b1 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -437,7 +437,18 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, void *mbuf; int res; - /* FIXME: Avoid memory copy if none of the buffers contain an fd */ + /* Optimize common case */ + if (buf->count == 1 && buf->idx == 0 && buf->off == 0 && + !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { + /* FIXME: also avoid memory copy if there are multiple buffers + but none of them contain an fd */ + + iov[iov_count].iov_base = buf->buf[0].mem; + iov[iov_count].iov_len = len; + iov_count++; + return fuse_send_msg(f, ch, iov, iov_count); + } + res = posix_memalign(&mbuf, pagesize, len); if (res != 0) return res; @@ -956,6 +967,17 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents) return send_reply_ok(req, &arg, sizeof(arg)); } +int fuse_reply_mmap(fuse_req_t req, uint64_t map_id, size_t length) +{ + struct fuse_mmap_out arg; + + memset(&arg, 0, sizeof(arg)); + arg.mapid = map_id; + arg.size = length; + + return send_reply_ok(req, &arg, sizeof(arg)); +} + static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { char *name = (char *) inarg; @@ -1704,6 +1726,38 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) } } +static void do_mmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + struct fuse_mmap_in *arg = (struct fuse_mmap_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.mmap) + req->f->op.mmap(req, nodeid, arg->addr, arg->len, arg->prot, + arg->flags, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); + +} + +static void do_munmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +{ + struct fuse_munmap_in *arg = (struct fuse_munmap_in *) inarg; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + fi.fh_old = fi.fh; + + if (req->f->op.munmap) + req->f->op.munmap(req, nodeid, arg->mapid, arg->size, &fi); + else + fuse_reply_err(req, ENOSYS); +} + static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_init_in *arg = (struct fuse_init_in *) inarg; @@ -2069,12 +2123,14 @@ static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, } bufv.buf[0].size = arg->size; - if (req->f->op.retrieve_reply) - req->f->op.retrieve_reply(rreq->cookie, ino, arg->offset, &bufv); - fuse_reply_none(req); - free(rreq); - + if (req->f->op.retrieve_reply) { + req->f->op.retrieve_reply(req, rreq->cookie, ino, + arg->offset, &bufv); + } else { + fuse_reply_none(req); + } out: + free(rreq); if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) fuse_ll_clear_pipe(f); } @@ -2218,6 +2274,8 @@ static struct { [FUSE_DESTROY] = { do_destroy, "DESTROY" }, [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, + [FUSE_MMAP] = { do_mmap, "MMAP" }, + [FUSE_MUNMAP] = { do_munmap, "MUNMAP" }, [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 96403c5..1ee1c9d 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -194,6 +194,7 @@ FUSE_2.9 { fuse_start_cleanup_thread; fuse_stop_cleanup_thread; fuse_clean_cache; + fuse_reply_mmap; local: *; -- 2.30.2