Commit 3fc63c3f authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging



* Coverity fixes for IPMI and mptsas
* qemu-char fixes from Daniel and Marc-André
* Bug fixes that break qemu-iotests
* Changes to fix reset from panicked state
* checkpatch false positives for designated initializers
* TLS support in the NBD servers and clients

# gpg: Signature made Tue 16 Feb 2016 16:27:17 GMT using RSA key ID 78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"

* remotes/bonzini/tags/for-upstream: (28 commits)
  nbd: enable use of TLS with nbd-server-start command
  nbd: enable use of TLS with qemu-nbd server
  nbd: enable use of TLS with NBD block driver
  nbd: implement TLS support in the protocol negotiation
  nbd: use "" as a default export name if none provided
  nbd: always query export list in fixed new style protocol
  nbd: allow setting of an export name for qemu-nbd server
  nbd: make client request fixed new style if advertised
  nbd: make server compliant with fixed newstyle spec
  nbd: invert client logic for negotiating protocol version
  nbd: convert to using I/O channels for actual socket I/O
  nbd: convert blockdev NBD server to use I/O channels for connection setup
  nbd: convert qemu-nbd server to use I/O channels for connection setup
  nbd: convert block client to use I/O channels for connection setup
  qemu-nbd: add support for --object command line arg
  qom: add helpers for UserCreatable object types
  ipmi: sensor number should not exceed MAX_SENSORS
  mptsas: fix wrong formula
  mptsas: fix memory leak
  mptsas: add missing va_end
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 250f53dd ddffee39
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -234,9 +234,9 @@ util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'

qemu-img.o: qemu-img-cmds.h

qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a

qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o

+60 −31
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@

#include "qemu/osdep.h"
#include "nbd-client.h"
#include "qemu/sockets.h"

#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
#define INDEX_TO_HANDLE(bs, index)  ((index)  ^ ((uint64_t)(intptr_t)bs))
@@ -48,13 +47,21 @@ static void nbd_teardown_connection(BlockDriverState *bs)
{
    NbdClientSession *client = nbd_get_client_session(bs);

    if (!client->ioc) { /* Already closed */
        return;
    }

    /* finish any pending coroutines */
    shutdown(client->sock, 2);
    qio_channel_shutdown(client->ioc,
                         QIO_CHANNEL_SHUTDOWN_BOTH,
                         NULL);
    nbd_recv_coroutines_enter_all(client);

    nbd_client_detach_aio_context(bs);
    closesocket(client->sock);
    client->sock = -1;
    object_unref(OBJECT(client->sioc));
    client->sioc = NULL;
    object_unref(OBJECT(client->ioc));
    client->ioc = NULL;
}

static void nbd_reply_ready(void *opaque)
@@ -64,12 +71,16 @@ static void nbd_reply_ready(void *opaque)
    uint64_t i;
    int ret;

    if (!s->ioc) { /* Already closed */
        return;
    }

    if (s->reply.handle == 0) {
        /* No reply already in flight.  Fetch a header.  It is possible
         * that another thread has done the same thing in parallel, so
         * the socket is not readable anymore.
         */
        ret = nbd_receive_reply(s->sock, &s->reply);
        ret = nbd_receive_reply(s->ioc, &s->reply);
        if (ret == -EAGAIN) {
            return;
        }
@@ -120,32 +131,35 @@ static int nbd_co_send_request(BlockDriverState *bs,
        }
    }

    g_assert(qemu_in_coroutine());
    assert(i < MAX_NBD_REQUESTS);
    request->handle = INDEX_TO_HANDLE(s, i);

    if (!s->ioc) {
        qemu_co_mutex_unlock(&s->send_mutex);
        return -EPIPE;
    }

    s->send_coroutine = qemu_coroutine_self();
    aio_context = bdrv_get_aio_context(bs);

    aio_set_fd_handler(aio_context, s->sock, false,
    aio_set_fd_handler(aio_context, s->sioc->fd, false,
                       nbd_reply_ready, nbd_restart_write, bs);
    if (qiov) {
        if (!s->is_unix) {
            socket_set_cork(s->sock, 1);
        }
        rc = nbd_send_request(s->sock, request);
        qio_channel_set_cork(s->ioc, true);
        rc = nbd_send_request(s->ioc, request);
        if (rc >= 0) {
            ret = qemu_co_sendv(s->sock, qiov->iov, qiov->niov,
                                offset, request->len);
            ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov,
                               offset, request->len, 0);
            if (ret != request->len) {
                rc = -EIO;
            }
        }
        if (!s->is_unix) {
            socket_set_cork(s->sock, 0);
        }
        qio_channel_set_cork(s->ioc, false);
    } else {
        rc = nbd_send_request(s->sock, request);
        rc = nbd_send_request(s->ioc, request);
    }
    aio_set_fd_handler(aio_context, s->sock, false,
    aio_set_fd_handler(aio_context, s->sioc->fd, false,
                       nbd_reply_ready, NULL, bs);
    s->send_coroutine = NULL;
    qemu_co_mutex_unlock(&s->send_mutex);
@@ -162,12 +176,13 @@ static void nbd_co_receive_reply(NbdClientSession *s,
     * peek at the next reply and avoid yielding if it's ours?  */
    qemu_coroutine_yield();
    *reply = s->reply;
    if (reply->handle != request->handle) {
    if (reply->handle != request->handle ||
        !s->ioc) {
        reply->error = EIO;
    } else {
        if (qiov && reply->error == 0) {
            ret = qemu_co_recvv(s->sock, qiov->iov, qiov->niov,
                                offset, request->len);
            ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov,
                               offset, request->len, 1);
            if (ret != request->len) {
                reply->error = EIO;
            }
@@ -350,14 +365,14 @@ int nbd_client_co_discard(BlockDriverState *bs, int64_t sector_num,
void nbd_client_detach_aio_context(BlockDriverState *bs)
{
    aio_set_fd_handler(bdrv_get_aio_context(bs),
                       nbd_get_client_session(bs)->sock,
                       nbd_get_client_session(bs)->sioc->fd,
                       false, NULL, NULL, NULL);
}

void nbd_client_attach_aio_context(BlockDriverState *bs,
                                   AioContext *new_context)
{
    aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sock,
    aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sioc->fd,
                       false, nbd_reply_ready, NULL, bs);
}

@@ -370,16 +385,20 @@ void nbd_client_close(BlockDriverState *bs)
        .len = 0
    };

    if (client->sock == -1) {
    if (client->ioc == NULL) {
        return;
    }

    nbd_send_request(client->sock, &request);
    nbd_send_request(client->ioc, &request);

    nbd_teardown_connection(bs);
}

int nbd_client_init(BlockDriverState *bs, int sock, const char *export,
int nbd_client_init(BlockDriverState *bs,
                    QIOChannelSocket *sioc,
                    const char *export,
                    QCryptoTLSCreds *tlscreds,
                    const char *hostname,
                    Error **errp)
{
    NbdClientSession *client = nbd_get_client_session(bs);
@@ -387,22 +406,32 @@ int nbd_client_init(BlockDriverState *bs, int sock, const char *export,

    /* NBD handshake */
    logout("session init %s\n", export);
    qemu_set_block(sock);
    ret = nbd_receive_negotiate(sock, export,
                                &client->nbdflags, &client->size, errp);
    qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);

    ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
                                &client->nbdflags,
                                tlscreds, hostname,
                                &client->ioc,
                                &client->size, errp);
    if (ret < 0) {
        logout("Failed to negotiate with the NBD server\n");
        closesocket(sock);
        return ret;
    }

    qemu_co_mutex_init(&client->send_mutex);
    qemu_co_mutex_init(&client->free_sema);
    client->sock = sock;
    client->sioc = sioc;
    object_ref(OBJECT(client->sioc));

    if (!client->ioc) {
        client->ioc = QIO_CHANNEL(sioc);
        object_ref(OBJECT(client->ioc));
    }

    /* Now that we're connected, set the socket to be non-blocking and
     * kick the reply mechanism.  */
    qemu_set_nonblock(sock);
    qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);

    nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));

    logout("Established connection with NBD server\n");
+8 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include "qemu-common.h"
#include "block/nbd.h"
#include "block/block_int.h"
#include "io/channel-socket.h"

/* #define DEBUG_NBD */

@@ -17,7 +18,8 @@
#define MAX_NBD_REQUESTS    16

typedef struct NbdClientSession {
    int sock;
    QIOChannelSocket *sioc; /* The master data channel */
    QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
    uint32_t nbdflags;
    off_t size;

@@ -34,7 +36,11 @@ typedef struct NbdClientSession {

NbdClientSession *nbd_get_client_session(BlockDriverState *bs);

int nbd_client_init(BlockDriverState *bs, int sock, const char *export_name,
int nbd_client_init(BlockDriverState *bs,
                    QIOChannelSocket *sock,
                    const char *export_name,
                    QCryptoTLSCreds *tlscreds,
                    const char *hostname,
                    Error **errp);
void nbd_client_close(BlockDriverState *bs);

+83 −22
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "qemu/sockets.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qint.h"
@@ -238,55 +237,113 @@ NbdClientSession *nbd_get_client_session(BlockDriverState *bs)
    return &s->client;
}

static int nbd_establish_connection(BlockDriverState *bs,
                                    SocketAddress *saddr,
static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
                                                  Error **errp)
{
    BDRVNBDState *s = bs->opaque;
    int sock;
    QIOChannelSocket *sioc;
    Error *local_err = NULL;

    sock = socket_connect(saddr, errp, NULL, NULL);
    sioc = qio_channel_socket_new();

    if (sock < 0) {
        logout("Failed to establish connection to NBD server\n");
        return -EIO;
    qio_channel_socket_connect_sync(sioc,
                                    saddr,
                                    &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return NULL;
    }

    if (!s->client.is_unix) {
        socket_set_nodelay(sock);
    qio_channel_set_delay(QIO_CHANNEL(sioc), false);

    return sioc;
}

    return sock;

static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
    Object *obj;
    QCryptoTLSCreds *creds;

    obj = object_resolve_path_component(
        object_get_objects_root(), id);
    if (!obj) {
        error_setg(errp, "No TLS credentials with id '%s'",
                   id);
        return NULL;
    }
    creds = (QCryptoTLSCreds *)
        object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
    if (!creds) {
        error_setg(errp, "Object with id '%s' is not TLS credentials",
                   id);
        return NULL;
    }

    if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
        error_setg(errp,
                   "Expecting TLS credentials with a client endpoint");
        return NULL;
    }
    object_ref(obj);
    return creds;
}


static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
                    Error **errp)
{
    BDRVNBDState *s = bs->opaque;
    char *export = NULL;
    int result, sock;
    QIOChannelSocket *sioc = NULL;
    SocketAddress *saddr;
    const char *tlscredsid;
    QCryptoTLSCreds *tlscreds = NULL;
    const char *hostname = NULL;
    int ret = -EINVAL;

    /* Pop the config into our state object. Exit if invalid. */
    saddr = nbd_config(s, options, &export, errp);
    if (!saddr) {
        return -EINVAL;
        goto error;
    }

    tlscredsid = g_strdup(qdict_get_try_str(options, "tls-creds"));
    if (tlscredsid) {
        qdict_del(options, "tls-creds");
        tlscreds = nbd_get_tls_creds(tlscredsid, errp);
        if (!tlscreds) {
            goto error;
        }

        if (saddr->type != SOCKET_ADDRESS_KIND_INET) {
            error_setg(errp, "TLS only supported over IP sockets");
            goto error;
        }
        hostname = saddr->u.inet->host;
    }

    /* establish TCP connection, return error if it fails
     * TODO: Configurable retry-until-timeout behaviour.
     */
    sock = nbd_establish_connection(bs, saddr, errp);
    qapi_free_SocketAddress(saddr);
    if (sock < 0) {
        g_free(export);
        return sock;
    sioc = nbd_establish_connection(saddr, errp);
    if (!sioc) {
        ret = -ECONNREFUSED;
        goto error;
    }

    /* NBD handshake */
    result = nbd_client_init(bs, sock, export, errp);
    ret = nbd_client_init(bs, sioc, export,
                          tlscreds, hostname, errp);
 error:
    if (sioc) {
        object_unref(OBJECT(sioc));
    }
    if (tlscreds) {
        object_unref(OBJECT(tlscreds));
    }
    qapi_free_SocketAddress(saddr);
    g_free(export);
    return result;
    return ret;
}

static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num,
@@ -348,6 +405,7 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
    const char *host   = qdict_get_try_str(options, "host");
    const char *port   = qdict_get_try_str(options, "port");
    const char *export = qdict_get_try_str(options, "export");
    const char *tlscreds = qdict_get_try_str(options, "tls-creds");

    qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));

@@ -382,6 +440,9 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
    if (export) {
        qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
    }
    if (tlscreds) {
        qdict_put_obj(opts, "tls-creds", QOBJECT(qstring_from_str(tlscreds)));
    }

    bs->full_open_options = opts;
}
+112 −19
Original line number Diff line number Diff line
@@ -18,32 +18,128 @@
#include "qmp-commands.h"
#include "trace.h"
#include "block/nbd.h"
#include "qemu/sockets.h"
#include "io/channel-socket.h"

static int server_fd = -1;
typedef struct NBDServerData {
    QIOChannelSocket *listen_ioc;
    int watch;
    QCryptoTLSCreds *tlscreds;
} NBDServerData;

static void nbd_accept(void *opaque)
static NBDServerData *nbd_server;


static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition,
                           gpointer opaque)
{
    QIOChannelSocket *cioc;

    if (!nbd_server) {
        return FALSE;
    }

    cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
                                     NULL);
    if (!cioc) {
        return TRUE;
    }

    nbd_client_new(NULL, cioc,
                   nbd_server->tlscreds, NULL,
                   nbd_client_put);
    object_unref(OBJECT(cioc));
    return TRUE;
}


static void nbd_server_free(NBDServerData *server)
{
    if (!server) {
        return;
    }

    if (server->watch != -1) {
        g_source_remove(server->watch);
    }
    object_unref(OBJECT(server->listen_ioc));
    if (server->tlscreds) {
        object_unref(OBJECT(server->tlscreds));
    }

    g_free(server);
}

static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
    struct sockaddr_in addr;
    socklen_t addr_len = sizeof(addr);
    Object *obj;
    QCryptoTLSCreds *creds;

    obj = object_resolve_path_component(
        object_get_objects_root(), id);
    if (!obj) {
        error_setg(errp, "No TLS credentials with id '%s'",
                   id);
        return NULL;
    }
    creds = (QCryptoTLSCreds *)
        object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
    if (!creds) {
        error_setg(errp, "Object with id '%s' is not TLS credentials",
                   id);
        return NULL;
    }

    int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
    if (fd >= 0) {
        nbd_client_new(NULL, fd, nbd_client_put);
    if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
        error_setg(errp,
                   "Expecting TLS credentials with a server endpoint");
        return NULL;
    }
    object_ref(obj);
    return creds;
}

void qmp_nbd_server_start(SocketAddress *addr, Error **errp)

void qmp_nbd_server_start(SocketAddress *addr,
                          bool has_tls_creds, const char *tls_creds,
                          Error **errp)
{
    if (server_fd != -1) {
    if (nbd_server) {
        error_setg(errp, "NBD server already running");
        return;
    }

    server_fd = socket_listen(addr, errp);
    if (server_fd != -1) {
        qemu_set_fd_handler(server_fd, nbd_accept, NULL, NULL);
    nbd_server = g_new0(NBDServerData, 1);
    nbd_server->watch = -1;
    nbd_server->listen_ioc = qio_channel_socket_new();
    if (qio_channel_socket_listen_sync(
            nbd_server->listen_ioc, addr, errp) < 0) {
        goto error;
    }

    if (has_tls_creds) {
        nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
        if (!nbd_server->tlscreds) {
            goto error;
        }

        if (addr->type != SOCKET_ADDRESS_KIND_INET) {
            error_setg(errp, "TLS is only supported with IPv4/IPv6");
            goto error;
        }
    }

    nbd_server->watch = qio_channel_add_watch(
        QIO_CHANNEL(nbd_server->listen_ioc),
        G_IO_IN,
        nbd_accept,
        NULL,
        NULL);

    return;

 error:
    nbd_server_free(nbd_server);
    nbd_server = NULL;
}

void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
@@ -52,7 +148,7 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
    BlockBackend *blk;
    NBDExport *exp;

    if (server_fd == -1) {
    if (!nbd_server) {
        error_setg(errp, "NBD server not running");
        return;
    }
@@ -98,9 +194,6 @@ void qmp_nbd_server_stop(Error **errp)
{
    nbd_export_close_all();

    if (server_fd != -1) {
        qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
        close(server_fd);
        server_fd = -1;
    }
    nbd_server_free(nbd_server);
    nbd_server = NULL;
}
Loading