Patchwork [RFC,3/5] block: plumb up open-hook-fd option

login
register
mail settings
Submitter Stefan Hajnoczi
Date May 1, 2012, 3:31 p.m.
Message ID <1335886307-27586-4-git-send-email-stefanha@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/156142/
State New
Headers show

Comments

Stefan Hajnoczi - May 1, 2012, 3:31 p.m.
From: Anthony Liguori <aliguori@us.ibm.com>

Implement the open hook UNIX domain socket protocol and accept passed
file descriptors.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 block.c           |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 block.h           |    2 +
 block/raw-posix.c |    2 +-
 qemu-options.hx   |    4 +-
 vl.c              |    3 ++
 5 files changed, 114 insertions(+), 4 deletions(-)

Patch

diff --git a/block.c b/block.c
index f9c4633..d3bf443 100644
--- a/block.c
+++ b/block.c
@@ -31,6 +31,7 @@ 
 #include "qemu-coroutine.h"
 #include "qmp-commands.h"
 #include "qemu-timer.h"
+#include "qemu_socket.h"
 
 #ifdef CONFIG_BSD
 #include <sys/types.h>
@@ -102,9 +103,113 @@  static BlockDriverState *bs_snapshots;
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
 
+static int remote_file_fd = -1;
+
+void remote_file_open_init(int fd)
+{
+    remote_file_fd = fd;
+}
+
+typedef struct OpenRequest
+{
+    uint32_t message_len;
+    uint32_t type;
+    uint32_t flags;
+    uint32_t mode;
+    uint32_t filename_len;
+    uint8_t filename[0];
+} OpenRequest;
+
+typedef struct OpenResponse
+{
+    uint32_t message_len;
+    uint32_t type;
+    int32_t result;
+} OpenResponse;
+
 int file_open(const char *filename, int flags, mode_t mode)
 {
-    return open(filename, flags, mode);
+#ifdef _WIN32
+    return qemu_open(filename, flags, mode);
+#else
+    struct msghdr msg = { NULL, };
+    struct cmsghdr *cmsg;
+    struct iovec iov[1];
+    union {
+        struct cmsghdr cmsg;
+        char control[CMSG_SPACE(sizeof(int))];
+    } msg_control;
+    ssize_t ret;
+    uint8_t buffer[1024];
+    OpenRequest *req = (void *)buffer;
+    OpenResponse *rsp = (void *)buffer;
+
+    if (remote_file_fd == -1) {
+        return qemu_open(filename, flags, mode);
+    }
+
+    req->filename_len = strlen(filename);
+    req->message_len = sizeof(OpenRequest) + req->filename_len;
+    req->type = 1; /* OpenRequest */
+    req->flags = flags;
+    req->mode = mode;
+
+    if (req->message_len > sizeof(buffer)) {
+        errno = EFAULT;
+        return -1;
+    }
+    memcpy(req->filename, filename, req->filename_len);
+
+    do {
+        ret = send(remote_file_fd, req, req->message_len, 0);
+    } while (ret == -1 && errno == EINTR);
+    if (ret != req->message_len) {
+        errno = EPIPE;
+        return -1;
+    }
+
+    iov[0].iov_base = buffer;
+    iov[0].iov_len = sizeof(buffer);
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &msg_control;
+    msg.msg_controllen = sizeof(msg_control);
+
+    do {
+        ret = recvmsg(remote_file_fd, &msg, 0);
+    } while (ret == -1 && errno == EINTR);
+    if (ret != sizeof(OpenResponse)) {
+        errno = EPIPE;
+        return -1;
+    }
+
+    rsp = (void *)buffer;
+    if (rsp->result < 0) {
+        errno = -rsp->result;
+        return -1;
+    }
+
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+        int fd;
+
+        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
+            cmsg->cmsg_level != SOL_SOCKET ||
+            cmsg->cmsg_type != SCM_RIGHTS) {
+            continue;
+        }
+
+        fd = *((int *)CMSG_DATA(cmsg));
+        if (fd < 0) {
+            continue;
+        }
+
+        return fd;
+    }
+
+    errno = ENOENT;
+    return -1;
+#endif
 }
 
 #ifdef _WIN32
diff --git a/block.h b/block.h
index f163e54..b8b78c7 100644
--- a/block.h
+++ b/block.h
@@ -336,6 +336,8 @@  int bdrv_img_create(const char *filename, const char *fmt,
 void bdrv_set_buffer_alignment(BlockDriverState *bs, int align);
 void *qemu_blockalign(BlockDriverState *bs, size_t size);
 
+void remote_file_open_init(int fd);
+
 #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
 
 void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index b6bc6bc..9946e5f 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -208,7 +208,7 @@  static int raw_open_common(BlockDriverState *bs, const char *filename,
         s->open_flags |= O_DSYNC;
 
     s->fd = -1;
-    fd = qemu_open(filename, s->open_flags, 0644);
+    fd = file_open(filename, s->open_flags, 0644);
     if (fd < 0) {
         ret = -errno;
         if (ret == -EROFS)
diff --git a/qemu-options.hx b/qemu-options.hx
index ccf4d1d..0c54cd5 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2730,8 +2730,8 @@  DEF("open-hook-fd", HAS_ARG, QEMU_OPTION_open_hook_fd,
 STEXI
 @item -open-hook-fd @var{fd}
 @findex -open-hook-fd
-Delegates open()s to an external process using @var<fd> to communicate commands.
-@var<fd> should be an open Unix Domain socket pipe that file descriptors can be
+Delegates open()s to an external process using @var{fd} to communicate commands.
+@var{fd} should be an open Unix Domain socket pipe that file descriptors can be
 received from.  The protocol the socket uses is a simple request/response initiated
 by the client.  All integers are in host byte order.  It is assumed that this protocol
 is only ever used on the same physical machine.  It is currently defined as:
diff --git a/vl.c b/vl.c
index ae91a8a..b418865 100644
--- a/vl.c
+++ b/vl.c
@@ -3191,6 +3191,9 @@  int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_qtest_log:
                 qtest_log = optarg;
                 break;
+            case QEMU_OPTION_open_hook_fd:
+                remote_file_open_init(atoi(optarg));
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }