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@xxxxxxxxxxxxxxxxxx> --- 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@xxxxxxxxxxxxxxxxxx> + * Corey Bryant <coreyb@xxxxxxxxxxxxxxxxxx> + * + * 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list