+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
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,
*
* 7.18
* - add FUSE_IOCTL_DIR flag
+ * - add FUSE_MMAP and FUSE_MUNMAP
*/
#ifndef _LINUX_FUSE_H
FUSE_POLL = 40,
FUSE_NOTIFY_REPLY = 41,
FUSE_BATCH_FORGET = 42,
+ FUSE_MMAP = 43,
+ FUSE_MUNMAP = 44,
/* CUSE specific operations */
CUSE_INIT = 4096,
__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;
/**
* 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
*/
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);
};
/**
*/
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 *
* ----------------------------------------------------------- */
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;
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) {
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;
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;
}
}
+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;
}
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);
}
[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" },
};
fuse_start_cleanup_thread;
fuse_stop_cleanup_thread;
fuse_clean_cache;
+ fuse_reply_mmap;
local:
*;