qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC 3/5] block: plumb up open-hook-fd option


From: Stefan Hajnoczi
Subject: [Qemu-devel] [RFC 3/5] block: plumb up open-hook-fd option
Date: Tue, 1 May 2012 16:31:45 +0100

From: Anthony Liguori <address@hidden>

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

Signed-off-by: Anthony Liguori <address@hidden>
Signed-off-by: Stefan Hajnoczi <address@hidden>
---
 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(-)

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.
address@hidden<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.
address@hidden 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);
             }
-- 
1.7.10




reply via email to

[Prev in Thread] Current Thread [Next in Thread]