This example demonstrates use of the -filefd command to open two
disk drives at start-up time. It also demonstrates hot attaching
a third disk drive with the getfd_file monitor command. I still
have some learning to do with regards to QMP, so the example is
using a not-so-program-friendly HMP method.
Usage:
./test-fd-passing /path/hda.img /path/hdb.img /path/hdc.img
Signed-off-by: Corey Bryant <coreyb(a)linux.vnet.ibm.com>
---
test-fd-passing.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 224 insertions(+), 0 deletions(-)
create mode 100644 test-fd-passing.c
diff --git a/test-fd-passing.c b/test-fd-passing.c
new file mode 100644
index 0000000..d568198
--- /dev/null
+++ b/test-fd-passing.c
@@ -0,0 +1,224 @@
+/*
+ * QEMU -filefd and getfd_file test server
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha(a)linux.vnet.ibm.com>
+ * Corey Bryant <coreyb(a)linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ * gcc -Wall -o test-fd-passing test-fd-passing.c
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+static int openQemuMonitor(const char *monitor)
+{
+ int i;
+ int ret;
+ struct sockaddr_un addr;
+ int monfd = 0;
+
+ if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ goto error;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, monitor);
+
+ for (i = 0; i < 100; i++) {
+ ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));
+ if (ret == 0) {
+ break;
+ }
+ usleep(.2 * 1000000);
+ }
+
+ if (ret != 0) {
+ fprintf(stderr, "no monitor socket");
+ goto error;
+ }
+
+ return monfd;
+
+error:
+ close(monfd);
+ return -1;
+}
+
+static int issueHMPCmdFD(int monfd,const char *data, size_t len, int fd)
+{
+ int ret;
+ struct msghdr msg;
+ struct iovec iov[1];
+ char control[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ iov[0].iov_base = (void *)data;
+ iov[0].iov_len = len;
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof(control);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+ do {
+ ret = sendmsg(monfd, &msg, 0);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+int main(int argc, char *argv[]) {
+ int rc;
+ int fd1, fd2, hotfd, monfd=-1;
+ int flags = O_RDWR;
+ int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ pid_t child_pid;
+ char *drive_str_1 = NULL;;
+ char *drive_str_2 = NULL;;
+ char *filefd_str_1 = NULL;
+ char *filefd_str_2 = NULL;
+ char *getfd_file_str = NULL;
+ char *drive_add_str = NULL;
+ char *device_add_str = NULL;
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s <boot-image-file-1>
<boot-image-file-2> <attach-image-file>\n", argv[0]);
+ goto error;
+ }
+
+ fd1 = open(argv[1], flags, mode);
+ if (fd1 == -1) {
+ perror("open");
+ goto error;
+ }
+
+ fd2 = open(argv[2], flags, mode);
+ if (fd2 == -1) {
+ perror("open");
+ goto error;
+ }
+
+ hotfd = open(argv[3], flags, mode);
+ if (hotfd == -1) {
+ perror("open");
+ goto error;
+ }
+
+ asprintf(&drive_str_1, "file=%s,if=none,id=drive-virtio-disk0",
argv[1]);
+ asprintf(&filefd_str_1, "file=%s,fd=%d", argv[1], fd1);
+ asprintf(&drive_str_2, "file=%s,if=none,id=drive-virtio-disk1",
argv[2]);
+ asprintf(&filefd_str_2, "file=%s,fd=%d", argv[2], fd2);
+
+ char *child_argv[] = {
+ "qemu-system-x86_64",
+ "-enable-kvm",
+ "-m", "1024",
+ "-chardev",
+
"socket,id=charmonitor,path=/var/lib/libvirt/qemu/RHEL62.monitor,server,nowait",
+ "-mon",
+ "chardev=charmonitor,id=monitor,mode=readline",
+ "-drive", drive_str_1,
+ "-device",
+
"virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0",
+ "-drive", drive_str_2,
+ "-device",
+
"virtio-blk-pci,bus=pci.0,addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1",
+ "-filefd", filefd_str_1,
+ "-filefd", filefd_str_2,
+ "-vnc", ":0",
+ NULL,
+ };
+
+ if (posix_spawn(&child_pid, "/usr/local/bin/qemu-system-x86_64",
+ NULL, NULL, child_argv, environ) != 0) {
+ perror("posix_spawn\n");
+ goto error;
+ }
+
+ monfd = openQemuMonitor("/var/lib/libvirt/qemu/RHEL62.monitor");
+ if (monfd == -1) {
+ goto error;
+ }
+
+ asprintf(&getfd_file_str, "getfd_file %s\r\n", argv[3]);
+ rc = issueHMPCmdFD(monfd, getfd_file_str,
+ strlen(getfd_file_str), hotfd);
+ if (rc < 0) {
+ perror("issueHMPCmdFD");
+ goto error;
+ }
+
+ sleep(1);
+ asprintf(&drive_add_str, "drive_add data_drive file=%s,%s", argv[3],
+ "if=none,id=drive-virtio-disk2,cache=writethrough\r\n");
+ rc = write(monfd, drive_add_str, strlen(drive_add_str));
+ if (rc < 0) {
+ perror("write");
+ goto error;
+ }
+
+ sleep(1);
+ asprintf(&device_add_str, "device_add virtio-blk-pci,bus=pci.0,%s",
+ "addr=0x8,drive=drive-virtio-disk2,id=virtio-disk2\r\n");
+ rc = write(monfd, device_add_str, strlen(device_add_str));
+ if (rc < 0) {
+ perror("write");
+ goto error;
+ }
+
+error:
+ if (drive_str_1) {
+ free(drive_str_1);
+ }
+ if (drive_str_2) {
+ free(drive_str_2);
+ }
+ if (filefd_str_1) {
+ free(filefd_str_1);
+ }
+ if (filefd_str_2) {
+ free(filefd_str_2);
+ }
+ if (getfd_file_str) {
+ free(getfd_file_str);
+ }
+ if (drive_add_str) {
+ free(drive_add_str);
+ }
+ if (device_add_str) {
+ free(device_add_str);
+ }
+ if (monfd != -1) {
+ close(monfd);
+ }
+ return -1;
+}
--
1.7.7.6