Add mmap() and munmap() methods to low level API
authorMiklos Szeredi <mszeredi@suse.cz>
Tue, 6 Dec 2011 17:06:18 +0000 (18:06 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Tue, 6 Dec 2011 17:06:18 +0000 (18:06 +0100)
Currently this is only useful for CUSE.  Also update retrieve_reply()
method.

ChangeLog
include/cuse_lowlevel.h
include/fuse_kernel.h
include/fuse_lowlevel.h
lib/cuse_lowlevel.c
lib/fuse_lowlevel.c
lib/fuse_versionscript

index 62699544674fc43ba4ff05595341b333eeb39abf..636dddcf3b0fb955009117543b2b5849e98e296d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2011-12-06  Miklos Szeredi <miklos@szeredi.hu>
+
+       * 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 <miklos@szeredi.hu>
 
        * Low level API: lock argument of fuse_reply_lock should have a
index e147fa26d96fb0692ea7626ed0683343459c0643..b8824fbb4ff77a142ad80fa773be7d66a33ddc3f 100644 (file)
@@ -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,
index eb8c790b57a31047ab4b46b8d312d5970b7f909b..039eb1ffb877381c146c9cf81641a50ca8e9be21 100644 (file)
@@ -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;
index 51aea39b634af45148c60abab67bc7447561c293..643593740daab596d65b2312b38a36e3821bbad4 100644 (file)
@@ -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                                                       *
  * ----------------------------------------------------------- */
index 402cf4bd1f5262fff609fe65c693abf1df3a5e72..7bd289aaec0183dde33f878667860c8f3024b78e 100644 (file)
@@ -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) {
index 8012d49f0c7dc70bd8885537b6e6014b7029027a..f69b2b122824fee1a6cc8120f59930a5d1fd768e 100644 (file)
@@ -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"   },
 };
 
index 96403c5f4e8b4d6cef697b48723ec6ddba1262e5..1ee1c9d9af28b46d56f94b83a0cc62195cbae862 100644 (file)
@@ -194,6 +194,7 @@ FUSE_2.9 {
                fuse_start_cleanup_thread;
                fuse_stop_cleanup_thread;
                fuse_clean_cache;
+               fuse_reply_mmap;
 
        local:
                *;