mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'bonzini/nbd-next' into staging
* bonzini/nbd-next: (30 commits) qmp: add NBD server commands block: add close notifiers block: prepare code for adding block notifiers qemu-sockets: add socket_listen, socket_connect, socket_parse tests: do not include tools-obj-y Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> qemu-sockets: return InetSocketAddress from inet_parse qapi: add socket address types build: add QAPI files to the tools vnc: drop QERR_VNC_SERVER_FAILED qemu-sockets: add error propagation to Unix socket functions qemu-sockets: add error propagation to inet_parse qemu-sockets: add error propagation to inet_dgram_opts qemu-sockets: add error propagation to inet_connect_addr qemu-sockets: include strerror or gai_strerror output in error messages vnc: add error propagation to vnc_display_open vnc: reorganize code for reverse mode vnc: introduce a single label for error returns vnc: avoid Yoda conditionals qemu-ga: ask and print error information from qemu-sockets nbd: ask and print error information from qemu-sockets ...
This commit is contained in:
@@ -161,11 +161,10 @@ qemu-img.o: qemu-img-cmds.h
|
||||
|
||||
tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \
|
||||
qemu-timer-common.o main-loop.o notify.o \
|
||||
iohandler.o cutils.o iov.o async.o
|
||||
iohandler.o cutils.o iov.o async.o error.o
|
||||
tools-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) $(qapi-obj-y) \
|
||||
qapi-visit.o qapi-types.o
|
||||
qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
|
||||
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
|
||||
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
|
||||
|
||||
|
||||
+5
-4
@@ -43,11 +43,12 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
|
||||
|
||||
block-obj-y = cutils.o iov.o cache-utils.o qemu-option.o module.o async.o
|
||||
block-obj-y += nbd.o block.o blockjob.o aio.o aes.o qemu-config.o
|
||||
block-obj-y += qemu-progress.o qemu-sockets.o uri.o
|
||||
block-obj-y += qemu-progress.o qemu-sockets.o uri.o notify.o
|
||||
block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
|
||||
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-y += block/
|
||||
block-obj-y += $(qapi-obj-y) qapi-types.o qapi-visit.o
|
||||
|
||||
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
|
||||
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
|
||||
@@ -60,7 +61,7 @@ endif
|
||||
# suppress *all* target specific code in case of system emulation, i.e. a
|
||||
# single QEMU executable should support all CPUs and machines.
|
||||
|
||||
common-obj-y = $(block-obj-y) blockdev.o block/
|
||||
common-obj-y = $(block-obj-y) blockdev.o blockdev-nbd.o block/
|
||||
common-obj-y += net.o net/
|
||||
common-obj-y += qom/
|
||||
common-obj-y += readline.o console.o cursor.o
|
||||
@@ -93,7 +94,7 @@ common-obj-y += bt-host.o bt-vhci.o
|
||||
common-obj-y += dma-helpers.o
|
||||
common-obj-y += iov.o acl.o
|
||||
common-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
common-obj-y += notify.o event_notifier.o
|
||||
common-obj-y += event_notifier.o
|
||||
common-obj-y += qemu-timer.o qemu-timer-common.o
|
||||
common-obj-y += qtest.o
|
||||
common-obj-y += vl.o
|
||||
@@ -239,9 +240,9 @@ QEMU_CFLAGS+=$(GLIB_CFLAGS)
|
||||
|
||||
nested-vars += \
|
||||
qga-obj-y \
|
||||
block-obj-y \
|
||||
qom-obj-y \
|
||||
qapi-obj-y \
|
||||
block-obj-y \
|
||||
user-obj-y \
|
||||
common-obj-y \
|
||||
extra-obj-y
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "module.h"
|
||||
#include "qjson.h"
|
||||
#include "sysemu.h"
|
||||
#include "notify.h"
|
||||
#include "qemu-coroutine.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qemu-timer.h"
|
||||
@@ -312,9 +313,16 @@ BlockDriverState *bdrv_new(const char *device_name)
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, list);
|
||||
}
|
||||
bdrv_iostatus_disable(bs);
|
||||
notifier_list_init(&bs->close_notifiers);
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
|
||||
{
|
||||
notifier_list_add(&bs->close_notifiers, notify);
|
||||
}
|
||||
|
||||
BlockDriver *bdrv_find_format(const char *format_name)
|
||||
{
|
||||
BlockDriver *drv1;
|
||||
@@ -1098,12 +1106,13 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
bdrv_flush(bs);
|
||||
if (bs->drv) {
|
||||
if (bs->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
}
|
||||
bdrv_drain_all();
|
||||
if (bs->job) {
|
||||
block_job_cancel_sync(bs->job);
|
||||
}
|
||||
bdrv_drain_all();
|
||||
notifier_list_notify(&bs->close_notifiers, bs);
|
||||
|
||||
if (bs->drv) {
|
||||
if (bs == bs_snapshots) {
|
||||
bs_snapshots = NULL;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
|
||||
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
|
||||
void bdrv_reopen_abort(BDRVReopenState *reopen_state);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
|
||||
int bdrv_attach_dev(BlockDriverState *bs, void *dev);
|
||||
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
|
||||
void bdrv_detach_dev(BlockDriverState *bs, void *dev);
|
||||
|
||||
@@ -233,6 +233,8 @@ struct BlockDriverState {
|
||||
BlockDriverState *backing_hd;
|
||||
BlockDriverState *file;
|
||||
|
||||
NotifierList close_notifiers;
|
||||
|
||||
/* number of in-flight copy-on-read requests */
|
||||
unsigned int copy_on_read_in_flight;
|
||||
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Serving QEMU block devices via NBD
|
||||
*
|
||||
* Copyright (c) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "blockdev.h"
|
||||
#include "hw/block-common.h"
|
||||
#include "monitor.h"
|
||||
#include "qerror.h"
|
||||
#include "sysemu.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "trace.h"
|
||||
#include "nbd.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
static int server_fd = -1;
|
||||
|
||||
static void nbd_accept(void *opaque)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
|
||||
if (fd >= 0) {
|
||||
nbd_client_new(NULL, fd, nbd_client_put);
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
|
||||
{
|
||||
if (server_fd != -1) {
|
||||
error_setg(errp, "NBD server already running");
|
||||
return;
|
||||
}
|
||||
|
||||
server_fd = socket_listen(addr, errp);
|
||||
if (server_fd != -1) {
|
||||
qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hook into the BlockDriverState notifiers to close the export when
|
||||
* the file is closed.
|
||||
*/
|
||||
typedef struct NBDCloseNotifier {
|
||||
Notifier n;
|
||||
NBDExport *exp;
|
||||
QTAILQ_ENTRY(NBDCloseNotifier) next;
|
||||
} NBDCloseNotifier;
|
||||
|
||||
static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
|
||||
QTAILQ_HEAD_INITIALIZER(close_notifiers);
|
||||
|
||||
static void nbd_close_notifier(Notifier *n, void *data)
|
||||
{
|
||||
NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
|
||||
|
||||
notifier_remove(&cn->n);
|
||||
QTAILQ_REMOVE(&close_notifiers, cn, next);
|
||||
|
||||
nbd_export_close(cn->exp);
|
||||
nbd_export_put(cn->exp);
|
||||
g_free(cn);
|
||||
}
|
||||
|
||||
static void nbd_server_put_ref(NBDExport *exp)
|
||||
{
|
||||
BlockDriverState *bs = nbd_export_get_blockdev(exp);
|
||||
drive_put_ref(drive_get_by_blockdev(bs));
|
||||
}
|
||||
|
||||
void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
NBDExport *exp;
|
||||
NBDCloseNotifier *n;
|
||||
|
||||
if (nbd_export_find(device)) {
|
||||
error_setg(errp, "NBD server already exporting device '%s'", device);
|
||||
return;
|
||||
}
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
|
||||
nbd_server_put_ref);
|
||||
|
||||
nbd_export_set_name(exp, device);
|
||||
drive_get_ref(drive_get_by_blockdev(bs));
|
||||
|
||||
n = g_malloc0(sizeof(NBDCloseNotifier));
|
||||
n->n.notify = nbd_close_notifier;
|
||||
n->exp = exp;
|
||||
bdrv_add_close_notifier(bs, &n->n);
|
||||
QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
|
||||
}
|
||||
|
||||
void qmp_nbd_server_stop(Error **errp)
|
||||
{
|
||||
while (!QTAILQ_EMPTY(&close_notifiers)) {
|
||||
NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
|
||||
nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
|
||||
close(server_fd);
|
||||
server_fd = -1;
|
||||
}
|
||||
@@ -378,7 +378,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen);
|
||||
/* vnc.c */
|
||||
void vnc_display_init(DisplayState *ds);
|
||||
void vnc_display_close(DisplayState *ds);
|
||||
int vnc_display_open(DisplayState *ds, const char *display);
|
||||
void vnc_display_open(DisplayState *ds, const char *display, Error **errp);
|
||||
void vnc_display_add_client(DisplayState *ds, int csock, int skipauth);
|
||||
int vnc_display_disable_login(DisplayState *ds);
|
||||
char *vnc_display_local_addr(DisplayState *ds);
|
||||
|
||||
@@ -43,6 +43,34 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
|
||||
*errp = err;
|
||||
}
|
||||
|
||||
void error_set_errno(Error **errp, int os_errno, ErrorClass err_class,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
char *msg1;
|
||||
va_list ap;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
msg1 = g_strdup_vprintf(fmt, ap);
|
||||
if (os_errno != 0) {
|
||||
err->msg = g_strdup_printf("%s: %s", msg1, strerror(os_errno));
|
||||
g_free(msg1);
|
||||
} else {
|
||||
err->msg = msg1;
|
||||
}
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
*errp = err;
|
||||
}
|
||||
|
||||
Error *error_copy(const Error *err)
|
||||
{
|
||||
Error *err_new;
|
||||
|
||||
@@ -29,11 +29,20 @@ typedef struct Error Error;
|
||||
*/
|
||||
void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(3, 4);
|
||||
|
||||
/**
|
||||
* Set an indirect pointer to an error given a ErrorClass value and a
|
||||
* printf-style human message, followed by a strerror() string if
|
||||
* @os_error is not zero.
|
||||
*/
|
||||
void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5);
|
||||
|
||||
/**
|
||||
* Same as error_set(), but sets a generic error
|
||||
*/
|
||||
#define error_setg(err, fmt, ...) \
|
||||
error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__)
|
||||
#define error_setg_errno(err, os_error, fmt, ...) \
|
||||
error_set_errno(err, os_error, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Returns true if an indirect pointer to an error is pointing to a valid
|
||||
|
||||
+7
-19
@@ -60,22 +60,18 @@ static int exec_close(MigrationState *s)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exec_start_outgoing_migration(MigrationState *s, const char *command)
|
||||
void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = popen(command, "w");
|
||||
if (f == NULL) {
|
||||
DPRINTF("Unable to popen exec target\n");
|
||||
goto err_after_popen;
|
||||
error_setg_errno(errp, errno, "failed to popen the migration target");
|
||||
return;
|
||||
}
|
||||
|
||||
s->fd = fileno(f);
|
||||
if (s->fd == -1) {
|
||||
DPRINTF("Unable to retrieve file descriptor for popen'd handle\n");
|
||||
goto err_after_open;
|
||||
}
|
||||
|
||||
assert(s->fd != -1);
|
||||
socket_set_nonblock(s->fd);
|
||||
|
||||
s->opaque = qemu_popen(f, "w");
|
||||
@@ -85,12 +81,6 @@ int exec_start_outgoing_migration(MigrationState *s, const char *command)
|
||||
s->write = file_write;
|
||||
|
||||
migrate_fd_connect(s);
|
||||
return 0;
|
||||
|
||||
err_after_open:
|
||||
pclose(f);
|
||||
err_after_popen:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void exec_accept_incoming_migration(void *opaque)
|
||||
@@ -102,19 +92,17 @@ static void exec_accept_incoming_migration(void *opaque)
|
||||
qemu_fclose(f);
|
||||
}
|
||||
|
||||
int exec_start_incoming_migration(const char *command)
|
||||
void exec_start_incoming_migration(const char *command, Error **errp)
|
||||
{
|
||||
QEMUFile *f;
|
||||
|
||||
DPRINTF("Attempting to start an incoming migration\n");
|
||||
f = qemu_popen_cmd(command, "r");
|
||||
if(f == NULL) {
|
||||
DPRINTF("Unable to apply qemu wrapper to popen file\n");
|
||||
return -errno;
|
||||
error_setg_errno(errp, errno, "failed to popen the migration source");
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(qemu_stdio_fd(f), NULL,
|
||||
exec_accept_incoming_migration, NULL, f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+7
-20
@@ -73,30 +73,19 @@ static int fd_close(MigrationState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_start_outgoing_migration(MigrationState *s, const char *fdname)
|
||||
void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp)
|
||||
{
|
||||
s->fd = monitor_get_fd(cur_mon, fdname, NULL);
|
||||
s->fd = monitor_get_fd(cur_mon, fdname, errp);
|
||||
if (s->fd == -1) {
|
||||
DPRINTF("fd_migration: invalid file descriptor identifier\n");
|
||||
goto err_after_get_fd;
|
||||
}
|
||||
|
||||
if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
DPRINTF("Unable to set nonblocking mode on file descriptor\n");
|
||||
goto err_after_open;
|
||||
return;
|
||||
}
|
||||
|
||||
fcntl(s->fd, F_SETFL, O_NONBLOCK);
|
||||
s->get_error = fd_errno;
|
||||
s->write = fd_write;
|
||||
s->close = fd_close;
|
||||
|
||||
migrate_fd_connect(s);
|
||||
return 0;
|
||||
|
||||
err_after_open:
|
||||
close(s->fd);
|
||||
err_after_get_fd:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fd_accept_incoming_migration(void *opaque)
|
||||
@@ -108,7 +97,7 @@ static void fd_accept_incoming_migration(void *opaque)
|
||||
qemu_fclose(f);
|
||||
}
|
||||
|
||||
int fd_start_incoming_migration(const char *infd)
|
||||
void fd_start_incoming_migration(const char *infd, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
QEMUFile *f;
|
||||
@@ -118,11 +107,9 @@ int fd_start_incoming_migration(const char *infd)
|
||||
fd = strtol(infd, NULL, 0);
|
||||
f = qemu_fdopen(fd, "rb");
|
||||
if(f == NULL) {
|
||||
DPRINTF("Unable to apply qemu wrapper to file descriptor\n");
|
||||
return -errno;
|
||||
error_setg_errno(errp, errno, "failed to open the source descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL, f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-15
@@ -68,21 +68,13 @@ static void tcp_wait_for_connect(int fd, void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||
Error **errp)
|
||||
void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp)
|
||||
{
|
||||
s->get_error = socket_errno;
|
||||
s->write = socket_write;
|
||||
s->close = tcp_close;
|
||||
|
||||
s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s,
|
||||
errp);
|
||||
if (error_is_set(errp)) {
|
||||
migrate_fd_error(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, errp);
|
||||
}
|
||||
|
||||
static void tcp_accept_incoming_migration(void *opaque)
|
||||
@@ -119,18 +111,15 @@ out2:
|
||||
close(s);
|
||||
}
|
||||
|
||||
int tcp_start_incoming_migration(const char *host_port, Error **errp)
|
||||
void tcp_start_incoming_migration(const char *host_port, Error **errp)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
|
||||
|
||||
if (s < 0) {
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
|
||||
(void *)(intptr_t)s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+13
-82
@@ -53,69 +53,28 @@ static int unix_close(MigrationState *s)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void unix_wait_for_connect(void *opaque)
|
||||
static void unix_wait_for_connect(int fd, void *opaque)
|
||||
{
|
||||
MigrationState *s = opaque;
|
||||
int val, ret;
|
||||
socklen_t valsize = sizeof(val);
|
||||
|
||||
DPRINTF("connect completed\n");
|
||||
do {
|
||||
ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
if (fd < 0) {
|
||||
DPRINTF("migrate connect error\n");
|
||||
s->fd = -1;
|
||||
migrate_fd_error(s);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (val == 0)
|
||||
} else {
|
||||
DPRINTF("migrate connect success\n");
|
||||
s->fd = fd;
|
||||
migrate_fd_connect(s);
|
||||
else {
|
||||
DPRINTF("error connecting %d\n", val);
|
||||
migrate_fd_error(s);
|
||||
}
|
||||
}
|
||||
|
||||
int unix_start_outgoing_migration(MigrationState *s, const char *path)
|
||||
void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int ret;
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
|
||||
s->get_error = unix_errno;
|
||||
s->write = unix_write;
|
||||
s->close = unix_close;
|
||||
|
||||
s->fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (s->fd == -1) {
|
||||
DPRINTF("Unable to open socket");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
socket_set_nonblock(s->fd);
|
||||
|
||||
do {
|
||||
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
}
|
||||
if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, unix_wait_for_connect, s);
|
||||
return 0;
|
||||
}
|
||||
} while (ret == -EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
DPRINTF("connect failed\n");
|
||||
migrate_fd_error(s);
|
||||
return ret;
|
||||
}
|
||||
migrate_fd_connect(s);
|
||||
return 0;
|
||||
s->fd = unix_nonblocking_connect(path, unix_wait_for_connect, s, errp);
|
||||
}
|
||||
|
||||
static void unix_accept_incoming_migration(void *opaque)
|
||||
@@ -152,43 +111,15 @@ out2:
|
||||
close(s);
|
||||
}
|
||||
|
||||
int unix_start_incoming_migration(const char *path)
|
||||
void unix_start_incoming_migration(const char *path, Error **errp)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int s;
|
||||
int ret;
|
||||
|
||||
DPRINTF("Attempting to start an incoming migration\n");
|
||||
|
||||
s = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (s == -1) {
|
||||
fprintf(stderr, "Could not open unix socket: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
|
||||
|
||||
unlink(addr.sun_path);
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "bind(unix:%s): %s\n", addr.sun_path, strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
if (listen(s, 1) == -1) {
|
||||
fprintf(stderr, "listen(unix:%s): %s\n", addr.sun_path,
|
||||
strerror(errno));
|
||||
ret = -errno;
|
||||
goto err;
|
||||
s = unix_listen(path, NULL, 0, errp);
|
||||
if (s < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(s, NULL, unix_accept_incoming_migration, NULL,
|
||||
(void *)(intptr_t)s);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
close(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+14
-20
@@ -64,26 +64,23 @@ MigrationState *migrate_get_current(void)
|
||||
return ¤t_migration;
|
||||
}
|
||||
|
||||
int qemu_start_incoming_migration(const char *uri, Error **errp)
|
||||
void qemu_start_incoming_migration(const char *uri, Error **errp)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
|
||||
if (strstart(uri, "tcp:", &p))
|
||||
ret = tcp_start_incoming_migration(p, errp);
|
||||
tcp_start_incoming_migration(p, errp);
|
||||
#if !defined(WIN32)
|
||||
else if (strstart(uri, "exec:", &p))
|
||||
ret = exec_start_incoming_migration(p);
|
||||
exec_start_incoming_migration(p, errp);
|
||||
else if (strstart(uri, "unix:", &p))
|
||||
ret = unix_start_incoming_migration(p);
|
||||
unix_start_incoming_migration(p, errp);
|
||||
else if (strstart(uri, "fd:", &p))
|
||||
ret = fd_start_incoming_migration(p);
|
||||
fd_start_incoming_migration(p, errp);
|
||||
#endif
|
||||
else {
|
||||
fprintf(stderr, "unknown migration protocol: %s\n", uri);
|
||||
ret = -EPROTONOSUPPORT;
|
||||
error_setg(errp, "unknown migration protocol: %s\n", uri);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void process_incoming_migration(QEMUFile *f)
|
||||
@@ -483,10 +480,10 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
|
||||
bool has_inc, bool inc, bool has_detach, bool detach,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
MigrationState *s = migrate_get_current();
|
||||
MigrationParams params;
|
||||
const char *p;
|
||||
int ret;
|
||||
|
||||
params.blk = blk;
|
||||
params.shared = inc;
|
||||
@@ -508,26 +505,23 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
|
||||
s = migrate_init(¶ms);
|
||||
|
||||
if (strstart(uri, "tcp:", &p)) {
|
||||
ret = tcp_start_outgoing_migration(s, p, errp);
|
||||
tcp_start_outgoing_migration(s, p, &local_err);
|
||||
#if !defined(WIN32)
|
||||
} else if (strstart(uri, "exec:", &p)) {
|
||||
ret = exec_start_outgoing_migration(s, p);
|
||||
exec_start_outgoing_migration(s, p, &local_err);
|
||||
} else if (strstart(uri, "unix:", &p)) {
|
||||
ret = unix_start_outgoing_migration(s, p);
|
||||
unix_start_outgoing_migration(s, p, &local_err);
|
||||
} else if (strstart(uri, "fd:", &p)) {
|
||||
ret = fd_start_outgoing_migration(s, p);
|
||||
fd_start_outgoing_migration(s, p, &local_err);
|
||||
#endif
|
||||
} else {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (!error_is_set(errp)) {
|
||||
DPRINTF("migration failed: %s\n", strerror(-ret));
|
||||
/* FIXME: we should return meaningful errors */
|
||||
error_set(errp, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
if (local_err) {
|
||||
migrate_fd_error(s);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -49,7 +49,7 @@ struct MigrationState
|
||||
|
||||
void process_incoming_migration(QEMUFile *f);
|
||||
|
||||
int qemu_start_incoming_migration(const char *uri, Error **errp);
|
||||
void qemu_start_incoming_migration(const char *uri, Error **errp);
|
||||
|
||||
uint64_t migrate_max_downtime(void);
|
||||
|
||||
@@ -57,22 +57,21 @@ void do_info_migrate_print(Monitor *mon, const QObject *data);
|
||||
|
||||
void do_info_migrate(Monitor *mon, QObject **ret_data);
|
||||
|
||||
int exec_start_incoming_migration(const char *host_port);
|
||||
void exec_start_incoming_migration(const char *host_port, Error **errp);
|
||||
|
||||
int exec_start_outgoing_migration(MigrationState *s, const char *host_port);
|
||||
void exec_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp);
|
||||
|
||||
int tcp_start_incoming_migration(const char *host_port, Error **errp);
|
||||
void tcp_start_incoming_migration(const char *host_port, Error **errp);
|
||||
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||
Error **errp);
|
||||
void tcp_start_outgoing_migration(MigrationState *s, const char *host_port, Error **errp);
|
||||
|
||||
int unix_start_incoming_migration(const char *path);
|
||||
void unix_start_incoming_migration(const char *path, Error **errp);
|
||||
|
||||
int unix_start_outgoing_migration(MigrationState *s, const char *path);
|
||||
void unix_start_outgoing_migration(MigrationState *s, const char *path, Error **errp);
|
||||
|
||||
int fd_start_incoming_migration(const char *path);
|
||||
void fd_start_incoming_migration(const char *path, Error **errp);
|
||||
|
||||
int fd_start_outgoing_migration(MigrationState *s, const char *fdname);
|
||||
void fd_start_outgoing_migration(MigrationState *s, const char *fdname, Error **errp);
|
||||
|
||||
void migrate_fd_error(MigrationState *s);
|
||||
|
||||
|
||||
@@ -208,7 +208,14 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
|
||||
|
||||
int tcp_socket_outgoing_spec(const char *address_and_port)
|
||||
{
|
||||
return inet_connect(address_and_port, NULL);
|
||||
Error *local_err = NULL;
|
||||
int fd = inet_connect(address_and_port, &local_err);
|
||||
|
||||
if (local_err != NULL) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int tcp_socket_incoming(const char *address, uint16_t port)
|
||||
@@ -220,22 +227,38 @@ int tcp_socket_incoming(const char *address, uint16_t port)
|
||||
|
||||
int tcp_socket_incoming_spec(const char *address_and_port)
|
||||
{
|
||||
char *ostr = NULL;
|
||||
int olen = 0;
|
||||
return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0, NULL);
|
||||
Error *local_err = NULL;
|
||||
int fd = inet_listen(address_and_port, NULL, 0, SOCK_STREAM, 0, &local_err);
|
||||
|
||||
if (local_err != NULL) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int unix_socket_incoming(const char *path)
|
||||
{
|
||||
char *ostr = NULL;
|
||||
int olen = 0;
|
||||
Error *local_err = NULL;
|
||||
int fd = unix_listen(path, NULL, 0, &local_err);
|
||||
|
||||
return unix_listen(path, ostr, olen);
|
||||
if (local_err != NULL) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int unix_socket_outgoing(const char *path)
|
||||
{
|
||||
return unix_connect(path);
|
||||
Error *local_err = NULL;
|
||||
int fd = unix_connect(path, &local_err);
|
||||
|
||||
if (local_err != NULL) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Basic flow for negotiation
|
||||
|
||||
@@ -2518,6 +2518,59 @@
|
||||
'id': 'str',
|
||||
'opts': 'NetClientOptions' } }
|
||||
|
||||
##
|
||||
# @InetSocketAddress
|
||||
#
|
||||
# Captures a socket address or address range in the Internet namespace.
|
||||
#
|
||||
# @host: host part of the address
|
||||
#
|
||||
# @port: port part of the address, or lowest port if @to is present
|
||||
#
|
||||
# @to: highest port to try
|
||||
#
|
||||
# @ipv4: whether to accept IPv4 addresses, default try both IPv4 and IPv6
|
||||
# #optional
|
||||
#
|
||||
# @ipv6: whether to accept IPv6 addresses, default try both IPv4 and IPv6
|
||||
# #optional
|
||||
#
|
||||
# Since 1.3
|
||||
##
|
||||
{ 'type': 'InetSocketAddress',
|
||||
'data': {
|
||||
'host': 'str',
|
||||
'port': 'str',
|
||||
'*to': 'uint16',
|
||||
'*ipv4': 'bool',
|
||||
'*ipv6': 'bool' } }
|
||||
|
||||
##
|
||||
# @UnixSocketAddress
|
||||
#
|
||||
# Captures a socket address in the local ("Unix socket") namespace.
|
||||
#
|
||||
# @path: filesystem path to use
|
||||
#
|
||||
# Since 1.3
|
||||
##
|
||||
{ 'type': 'UnixSocketAddress',
|
||||
'data': {
|
||||
'path': 'str' } }
|
||||
|
||||
##
|
||||
# @SocketAddress
|
||||
#
|
||||
# Captures the address of a socket, which could also be a named file descriptor
|
||||
#
|
||||
# Since 1.3
|
||||
##
|
||||
{ 'union': 'SocketAddress',
|
||||
'data': {
|
||||
'inet': 'InetSocketAddress',
|
||||
'unix': 'UnixSocketAddress',
|
||||
'fd': 'String' } }
|
||||
|
||||
##
|
||||
# @getfd:
|
||||
#
|
||||
@@ -2810,3 +2863,46 @@
|
||||
# Since: 0.14.0
|
||||
##
|
||||
{ 'command': 'screendump', 'data': {'filename': 'str'} }
|
||||
|
||||
##
|
||||
# @nbd-server-start:
|
||||
#
|
||||
# Start an NBD server listening on the given host and port. Block
|
||||
# devices can then be exported using @nbd-server-add. The NBD
|
||||
# server will present them as named exports; for example, another
|
||||
# QEMU instance could refer to them as "nbd:HOST:PORT:exportname=NAME".
|
||||
#
|
||||
# @addr: Address on which to listen.
|
||||
#
|
||||
# Returns: error if the server is already running.
|
||||
#
|
||||
# Since: 1.3.0
|
||||
##
|
||||
{ 'command': 'nbd-server-start',
|
||||
'data': { 'addr': 'SocketAddress' } }
|
||||
|
||||
##
|
||||
# @nbd-server-add:
|
||||
#
|
||||
# Export a device to QEMU's embedded NBD server.
|
||||
#
|
||||
# @device: Block device to be exported
|
||||
#
|
||||
# @writable: Whether clients should be able to write to the device via the
|
||||
# NBD connection (default false). #optional
|
||||
#
|
||||
# Returns: error if the device is already marked for export.
|
||||
#
|
||||
# Since: 1.3.0
|
||||
##
|
||||
{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool'} }
|
||||
|
||||
##
|
||||
# @nbd-server-stop:
|
||||
#
|
||||
# Stop QEMU's embedded NBD server, and unregister all devices previously
|
||||
# added via @nbd-server-add.
|
||||
#
|
||||
# Since: 1.3.0
|
||||
##
|
||||
{ 'command': 'nbd-server-stop' }
|
||||
|
||||
+17
-7
@@ -2097,14 +2097,14 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
|
||||
{
|
||||
CharDriverState *chr = NULL;
|
||||
NetCharDriver *s = NULL;
|
||||
Error *local_err = NULL;
|
||||
int fd = -1;
|
||||
|
||||
chr = g_malloc0(sizeof(CharDriverState));
|
||||
s = g_malloc0(sizeof(NetCharDriver));
|
||||
|
||||
fd = inet_dgram_opts(opts);
|
||||
fd = inet_dgram_opts(opts, &local_err);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "inet_dgram_opts failed\n");
|
||||
goto return_err;
|
||||
}
|
||||
|
||||
@@ -2118,6 +2118,10 @@ static CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
|
||||
return chr;
|
||||
|
||||
return_err:
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
g_free(chr);
|
||||
g_free(s);
|
||||
if (fd >= 0) {
|
||||
@@ -2428,6 +2432,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
{
|
||||
CharDriverState *chr = NULL;
|
||||
TCPCharDriver *s = NULL;
|
||||
Error *local_err = NULL;
|
||||
int fd = -1;
|
||||
int is_listen;
|
||||
int is_waitconnect;
|
||||
@@ -2448,15 +2453,15 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
|
||||
if (is_unix) {
|
||||
if (is_listen) {
|
||||
fd = unix_listen_opts(opts);
|
||||
fd = unix_listen_opts(opts, &local_err);
|
||||
} else {
|
||||
fd = unix_connect_opts(opts);
|
||||
fd = unix_connect_opts(opts, &local_err, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
if (is_listen) {
|
||||
fd = inet_listen_opts(opts, 0, NULL);
|
||||
fd = inet_listen_opts(opts, 0, &local_err);
|
||||
} else {
|
||||
fd = inet_connect_opts(opts, NULL, NULL, NULL);
|
||||
fd = inet_connect_opts(opts, &local_err, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
@@ -2517,8 +2522,13 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
return chr;
|
||||
|
||||
fail:
|
||||
if (fd >= 0)
|
||||
if (local_err) {
|
||||
qerror_report_err(local_err);
|
||||
error_free(local_err);
|
||||
}
|
||||
if (fd >= 0) {
|
||||
closesocket(fd);
|
||||
}
|
||||
g_free(s);
|
||||
g_free(chr);
|
||||
return NULL;
|
||||
|
||||
+283
-143
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,12 @@ const char *qemu_get_vm_name(void)
|
||||
|
||||
Monitor *cur_mon;
|
||||
|
||||
int monitor_get_fd(Monitor *mon, const char *name, Error **errp)
|
||||
{
|
||||
error_setg(errp, "only QEMU supports file descriptor passing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void vm_stop(RunState state)
|
||||
{
|
||||
abort();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user