@@ -1899,8 +1899,17 @@ static void do_setupmapping(fuse_req_t req, fuse_ino_t nodeid,
}
if (req->se->op.setupmapping) {
- req->se->op.setupmapping(req, nodeid, arg->foffset, arg->len,
- arg->moffset, genflags, &fi);
+ /*
+ * TODO: Add a flag to request which tells if arg->fh is
+ * valid or not.
+ */
+ if (fi.fh == (uint64_t)-1) {
+ req->se->op.setupmapping(req, nodeid, arg->foffset, arg->len,
+ arg->moffset, genflags, NULL);
+ } else {
+ req->se->op.setupmapping(req, nodeid, arg->foffset, arg->len,
+ arg->moffset, genflags, &fi);
+ }
} else {
fuse_reply_err(req, ENOSYS);
}
@@ -3149,8 +3149,61 @@ static void lo_setupmapping(fuse_req_t req, fuse_ino_t ino, uint64_t foffset,
uint64_t len, uint64_t moffset, uint64_t flags,
struct fuse_file_info *fi)
{
- /* TODO */
- fuse_reply_err(req, ENOSYS);
+ struct lo_data *lo = lo_data(req);
+ int ret = 0, fd;
+ VhostUserFSSlaveMsg *msg = g_malloc0(sizeof(VhostUserFSSlaveMsg) +
+ sizeof(VhostUserFSSlaveMsgEntry));
+ uint64_t vhu_flags;
+ char *buf;
+ bool writable = flags & O_RDWR;
+
+ fuse_log(FUSE_LOG_DEBUG,
+ "lo_setupmapping(ino=%" PRIu64 ", fi=0x%p,"
+ " foffset=%" PRIu64 ", len=%" PRIu64 ", moffset=%" PRIu64
+ ", flags=%" PRIu64 ")\n",
+ ino, (void *)fi, foffset, len, moffset, flags);
+
+ vhu_flags = VHOST_USER_FS_FLAG_MAP_R;
+ if (writable) {
+ vhu_flags |= VHOST_USER_FS_FLAG_MAP_W;
+ }
+
+ msg->count = 1;
+ msg->entries[0].fd_offset = foffset;
+ msg->entries[0].len = len;
+ msg->entries[0].c_offset = moffset;
+ msg->entries[0].flags = vhu_flags;
+
+ if (fi) {
+ fd = lo_fi_fd(req, fi);
+ } else {
+ ret = asprintf(&buf, "%i", lo_fd(req, ino));
+ if (ret == -1) {
+ g_free(msg);
+ return (void)fuse_reply_err(req, errno);
+ }
+
+ fd = openat(lo->proc_self_fd, buf, flags);
+ free(buf);
+ if (fd == -1) {
+ g_free(msg);
+ return (void)fuse_reply_err(req, errno);
+ }
+ }
+
+ ret = fuse_virtio_map(req, msg, fd);
+ if (ret < 0) {
+ fuse_log(FUSE_LOG_ERR,
+ "%s: map over virtio failed (ino=%" PRId64
+ "fd=%d moffset=0x%" PRIx64 "). err = %d\n",
+ __func__, ino, fd, moffset, ret);
+ }
+
+ if (!fi) {
+ close(fd);
+ }
+ fuse_reply_err(req, -ret);
+ g_free(msg);
}
static void lo_removemapping(fuse_req_t req, struct fuse_session *se,