mirror of https://github.com/proxmox/mirror_qemu
blockdev: convert qemu-nbd server to QIONetListener
Instead of creating a QIOChannelSocket directly for the NBD server socket, use a QIONetListener. This provides the ability to listen on multiple sockets at the same time, so enables full support for IPv4/IPv6 dual stack. This also means we can honour multiple FDs received during socket activation. Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Message-Id: <20171218101643.20360-3-berrange@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>master
parent
862172f45c
commit
e4849c1d7c
53
qemu-nbd.c
53
qemu-nbd.c
|
@ -37,6 +37,7 @@
|
||||||
#include "qapi/qmp/qstring.h"
|
#include "qapi/qmp/qstring.h"
|
||||||
#include "qom/object_interfaces.h"
|
#include "qom/object_interfaces.h"
|
||||||
#include "io/channel-socket.h"
|
#include "io/channel-socket.h"
|
||||||
|
#include "io/net-listener.h"
|
||||||
#include "crypto/init.h"
|
#include "crypto/init.h"
|
||||||
#include "trace/control.h"
|
#include "trace/control.h"
|
||||||
#include "qemu-version.h"
|
#include "qemu-version.h"
|
||||||
|
@ -62,8 +63,7 @@ static int persistent = 0;
|
||||||
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
|
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
|
||||||
static int shared = 1;
|
static int shared = 1;
|
||||||
static int nb_fds;
|
static int nb_fds;
|
||||||
static QIOChannelSocket *server_ioc;
|
static QIONetListener *server;
|
||||||
static int server_watch = -1;
|
|
||||||
static QCryptoTLSCreds *tlscreds;
|
static QCryptoTLSCreds *tlscreds;
|
||||||
|
|
||||||
static void usage(const char *name)
|
static void usage(const char *name)
|
||||||
|
@ -344,44 +344,25 @@ static void nbd_client_closed(NBDClient *client, bool negotiated)
|
||||||
nbd_client_put(client);
|
nbd_client_put(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
|
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
|
||||||
|
gpointer opaque)
|
||||||
{
|
{
|
||||||
QIOChannelSocket *cioc;
|
|
||||||
|
|
||||||
cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
|
|
||||||
NULL);
|
|
||||||
if (!cioc) {
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state >= TERMINATE) {
|
if (state >= TERMINATE) {
|
||||||
object_unref(OBJECT(cioc));
|
return;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nb_fds++;
|
nb_fds++;
|
||||||
nbd_update_server_watch();
|
nbd_update_server_watch();
|
||||||
nbd_client_new(newproto ? NULL : exp, cioc,
|
nbd_client_new(newproto ? NULL : exp, cioc,
|
||||||
tlscreds, NULL, nbd_client_closed);
|
tlscreds, NULL, nbd_client_closed);
|
||||||
object_unref(OBJECT(cioc));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nbd_update_server_watch(void)
|
static void nbd_update_server_watch(void)
|
||||||
{
|
{
|
||||||
if (nbd_can_accept()) {
|
if (nbd_can_accept()) {
|
||||||
if (server_watch == -1) {
|
qio_net_listener_set_client_func(server, nbd_accept, NULL, NULL);
|
||||||
server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
|
|
||||||
G_IO_IN,
|
|
||||||
nbd_accept,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (server_watch != -1) {
|
qio_net_listener_set_client_func(server, NULL, NULL, NULL);
|
||||||
g_source_remove(server_watch);
|
|
||||||
server_watch = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,24 +896,30 @@ int main(int argc, char **argv)
|
||||||
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
|
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server = qio_net_listener_new();
|
||||||
if (socket_activation == 0) {
|
if (socket_activation == 0) {
|
||||||
server_ioc = qio_channel_socket_new();
|
|
||||||
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
saddr = nbd_build_socket_address(sockpath, bindto, port);
|
||||||
if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
|
if (qio_net_listener_open_sync(server, saddr, &local_err) < 0) {
|
||||||
object_unref(OBJECT(server_ioc));
|
object_unref(OBJECT(server));
|
||||||
error_report_err(local_err);
|
error_report_err(local_err);
|
||||||
return 1;
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
size_t i;
|
||||||
/* See comment in check_socket_activation above. */
|
/* See comment in check_socket_activation above. */
|
||||||
assert(socket_activation == 1);
|
for (i = 0; i < socket_activation; i++) {
|
||||||
server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
|
QIOChannelSocket *sioc;
|
||||||
|
sioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD + i,
|
||||||
&local_err);
|
&local_err);
|
||||||
if (server_ioc == NULL) {
|
if (sioc == NULL) {
|
||||||
|
object_unref(OBJECT(server));
|
||||||
error_report("Failed to use socket activation: %s",
|
error_report("Failed to use socket activation: %s",
|
||||||
error_get_pretty(local_err));
|
error_get_pretty(local_err));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
qio_net_listener_add(server, sioc);
|
||||||
|
object_unref(OBJECT(sioc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_init_main_loop(&local_err)) {
|
if (qemu_init_main_loop(&local_err)) {
|
||||||
|
|
Loading…
Reference in New Issue