Commit 9879b758 authored by Peter Maydell's avatar Peter Maydell
Browse files

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



Block layer patches

# gpg: Signature made Thu 27 Oct 2016 18:15:47 BST
# gpg:                using RSA key 0x7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74  56FE 7F09 B272 C88F 2FD6

* remotes/kevin/tags/for-upstream: (23 commits)
  iotests: Add test for NBD's blockdev-add interface
  iotests: Add assert_json_filename_equal() method
  socket_scm_helper: Accept fd directly
  iotests.py: Allow concurrent qemu instances
  iotests.py: Add qemu_nbd function
  qapi: Allow blockdev-add for NBD
  block/nbd: Use SocketAddress options
  block/nbd: Accept SocketAddress
  block/nbd: Add nbd_has_filename_options_conflict()
  block/nbd: Use qdict_put()
  block/nbd: Default port in nbd_refresh_filename()
  block/nbd: Reject port parameter without host
  block/nbd: Drop trailing "." in error messages
  qemu-iotests: Fix typo for NFS with IMGOPTSSYNTAX
  block: Remove bdrv_aio_ioctl()
  raw: Implement .bdrv_co_ioctl instead of .bdrv_aio_ioctl
  block: Introduce .bdrv_co_ioctl() driver callback
  block: Remove bdrv_ioctl()
  raw-posix: Don't use bdrv_ioctl()
  block: Use blk_co_ioctl() for all BB level ioctls
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 86398328 b74fc7f7
Loading
Loading
Loading
Loading
+67 −27
Original line number Diff line number Diff line
@@ -1099,26 +1099,36 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
                        blk_aio_write_entry, flags, cb, opaque);
}

static void blk_aio_flush_entry(void *opaque)
{
    BlkAioEmAIOCB *acb = opaque;
    BlkRwCo *rwco = &acb->rwco;

    rwco->ret = blk_co_flush(rwco->blk);
    blk_aio_complete(acb);
}

BlockAIOCB *blk_aio_flush(BlockBackend *blk,
                          BlockCompletionFunc *cb, void *opaque)
{
    if (!blk_is_available(blk)) {
        return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
    return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque);
}

    return bdrv_aio_flush(blk_bs(blk), cb, opaque);
static void blk_aio_pdiscard_entry(void *opaque)
{
    BlkAioEmAIOCB *acb = opaque;
    BlkRwCo *rwco = &acb->rwco;

    rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, acb->bytes);
    blk_aio_complete(acb);
}

BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
                             int64_t offset, int count,
                             BlockCompletionFunc *cb, void *opaque)
{
    int ret = blk_check_byte_request(blk, offset, count);
    if (ret < 0) {
        return blk_abort_aio_request(blk, cb, opaque, ret);
    }

    return bdrv_aio_pdiscard(blk_bs(blk), offset, count, cb, opaque);
    return blk_aio_prwv(blk, offset, count, NULL, blk_aio_pdiscard_entry, 0,
                        cb, opaque);
}

void blk_aio_cancel(BlockAIOCB *acb)
@@ -1131,23 +1141,50 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
    bdrv_aio_cancel_async(acb);
}

int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
    if (!blk_is_available(blk)) {
        return -ENOMEDIUM;
    }

    return bdrv_ioctl(blk_bs(blk), req, buf);
    return bdrv_co_ioctl(blk_bs(blk), req, buf);
}

static void blk_ioctl_entry(void *opaque)
{
    BlkRwCo *rwco = opaque;
    rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
                             rwco->qiov->iov[0].iov_base);
}

int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
    return blk_prw(blk, req, buf, 0, blk_ioctl_entry, 0);
}

static void blk_aio_ioctl_entry(void *opaque)
{
    BlkAioEmAIOCB *acb = opaque;
    BlkRwCo *rwco = &acb->rwco;

    rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset,
                             rwco->qiov->iov[0].iov_base);
    blk_aio_complete(acb);
}

BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
                          BlockCompletionFunc *cb, void *opaque)
{
    if (!blk_is_available(blk)) {
        return blk_abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
    }
    QEMUIOVector qiov;
    struct iovec iov;

    iov = (struct iovec) {
        .iov_base = buf,
        .iov_len = 0,
    };
    qemu_iovec_init_external(&qiov, &iov, 1);

    return bdrv_aio_ioctl(blk_bs(blk), req, buf, cb, opaque);
    return blk_aio_prwv(blk, req, 0, &qiov, blk_aio_ioctl_entry, 0, cb, opaque);
}

int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int count)
@@ -1169,13 +1206,15 @@ int blk_co_flush(BlockBackend *blk)
    return bdrv_co_flush(blk_bs(blk));
}

int blk_flush(BlockBackend *blk)
static void blk_flush_entry(void *opaque)
{
    if (!blk_is_available(blk)) {
        return -ENOMEDIUM;
    BlkRwCo *rwco = opaque;
    rwco->ret = blk_co_flush(rwco->blk);
}

    return bdrv_flush(blk_bs(blk));
int blk_flush(BlockBackend *blk)
{
    return blk_prw(blk, 0, NULL, 0, blk_flush_entry, 0);
}

void blk_drain(BlockBackend *blk)
@@ -1555,14 +1594,15 @@ int blk_truncate(BlockBackend *blk, int64_t offset)
    return bdrv_truncate(blk_bs(blk), offset);
}

int blk_pdiscard(BlockBackend *blk, int64_t offset, int count)
static void blk_pdiscard_entry(void *opaque)
{
    int ret = blk_check_byte_request(blk, offset, count);
    if (ret < 0) {
        return ret;
    BlkRwCo *rwco = opaque;
    rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, rwco->qiov->size);
}

    return bdrv_pdiscard(blk_bs(blk), offset, count);
int blk_pdiscard(BlockBackend *blk, int64_t offset, int count)
{
    return blk_prw(blk, offset, NULL, count, blk_pdiscard_entry, 0);
}

int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
+11 −100
Original line number Diff line number Diff line
@@ -2196,35 +2196,6 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
    return &acb->common;
}

static void coroutine_fn bdrv_aio_pdiscard_co_entry(void *opaque)
{
    BlockAIOCBCoroutine *acb = opaque;
    BlockDriverState *bs = acb->common.bs;

    acb->req.error = bdrv_co_pdiscard(bs, acb->req.offset, acb->req.bytes);
    bdrv_co_complete(acb);
}

BlockAIOCB *bdrv_aio_pdiscard(BlockDriverState *bs, int64_t offset, int count,
                              BlockCompletionFunc *cb, void *opaque)
{
    Coroutine *co;
    BlockAIOCBCoroutine *acb;

    trace_bdrv_aio_pdiscard(bs, offset, count, opaque);

    acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
    acb->need_bh = true;
    acb->req.error = -EINPROGRESS;
    acb->req.offset = offset;
    acb->req.bytes = count;
    co = qemu_coroutine_create(bdrv_aio_pdiscard_co_entry, acb);
    qemu_coroutine_enter(co);

    bdrv_co_maybe_schedule_bh(acb);
    return &acb->common;
}

void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
                   BlockCompletionFunc *cb, void *opaque)
{
@@ -2521,7 +2492,7 @@ int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int count)
    return rwco.ret;
}

static int bdrv_co_do_ioctl(BlockDriverState *bs, int req, void *buf)
int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf)
{
    BlockDriver *drv = bs->drv;
    BdrvTrackedRequest tracked_req;
@@ -2531,86 +2502,26 @@ static int bdrv_co_do_ioctl(BlockDriverState *bs, int req, void *buf)
    BlockAIOCB *acb;

    tracked_request_begin(&tracked_req, bs, 0, 0, BDRV_TRACKED_IOCTL);
    if (!drv || !drv->bdrv_aio_ioctl) {
    if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) {
        co.ret = -ENOTSUP;
        goto out;
    }

    if (drv->bdrv_co_ioctl) {
        co.ret = drv->bdrv_co_ioctl(bs, req, buf);
    } else {
        acb = drv->bdrv_aio_ioctl(bs, req, buf, bdrv_co_io_em_complete, &co);
        if (!acb) {
            co.ret = -ENOTSUP;
            goto out;
        }
        qemu_coroutine_yield();
    }
out:
    tracked_request_end(&tracked_req);
    return co.ret;
}

typedef struct {
    BlockDriverState *bs;
    int req;
    void *buf;
    int ret;
} BdrvIoctlCoData;

static void coroutine_fn bdrv_co_ioctl_entry(void *opaque)
{
    BdrvIoctlCoData *data = opaque;
    data->ret = bdrv_co_do_ioctl(data->bs, data->req, data->buf);
}

/* needed for generic scsi interface */
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
    BdrvIoctlCoData data = {
        .bs = bs,
        .req = req,
        .buf = buf,
        .ret = -EINPROGRESS,
    };

    if (qemu_in_coroutine()) {
        /* Fast-path if already in coroutine context */
        bdrv_co_ioctl_entry(&data);
    } else {
        Coroutine *co = qemu_coroutine_create(bdrv_co_ioctl_entry, &data);

        qemu_coroutine_enter(co);
        while (data.ret == -EINPROGRESS) {
            aio_poll(bdrv_get_aio_context(bs), true);
        }
    }
    return data.ret;
}

static void coroutine_fn bdrv_co_aio_ioctl_entry(void *opaque)
{
    BlockAIOCBCoroutine *acb = opaque;
    acb->req.error = bdrv_co_do_ioctl(acb->common.bs,
                                      acb->req.req, acb->req.buf);
    bdrv_co_complete(acb);
}

BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
        unsigned long int req, void *buf,
        BlockCompletionFunc *cb, void *opaque)
{
    BlockAIOCBCoroutine *acb = qemu_aio_get(&bdrv_em_co_aiocb_info,
                                            bs, cb, opaque);
    Coroutine *co;

    acb->need_bh = true;
    acb->req.error = -EINPROGRESS;
    acb->req.req = req;
    acb->req.buf = buf;
    co = qemu_coroutine_create(bdrv_co_aio_ioctl_entry, acb);
    qemu_coroutine_enter(co);

    bdrv_co_maybe_schedule_bh(acb);
    return &acb->common;
}

void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
    return qemu_memalign(bdrv_opt_mem_align(bs), size);
+150 −84
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@
#include "qemu/uri.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "qapi-visit.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qjson.h"
#include "qapi/qmp/qint.h"
@@ -44,7 +47,8 @@ typedef struct BDRVNBDState {
    NbdClientSession client;

    /* For nbd_refresh_filename() */
    char *path, *host, *port, *export, *tlscredsid;
    SocketAddress *saddr;
    char *export, *tlscredsid;
} BDRVNBDState;

static int nbd_parse_uri(const char *filename, QDict *options)
@@ -90,9 +94,13 @@ static int nbd_parse_uri(const char *filename, QDict *options)
            ret = -EINVAL;
            goto out;
        }
        qdict_put(options, "path", qstring_from_str(qp->p[0].value));
        qdict_put(options, "server.type", qstring_from_str("unix"));
        qdict_put(options, "server.data.path",
                  qstring_from_str(qp->p[0].value));
    } else {
        QString *host;
        char *port_str;

        /* nbd[+tcp]://host[:port]/export */
        if (!uri->server) {
            ret = -EINVAL;
@@ -107,13 +115,13 @@ static int nbd_parse_uri(const char *filename, QDict *options)
            host = qstring_from_str(uri->server);
        }

        qdict_put(options, "host", host);
        if (uri->port) {
            char* port_str = g_strdup_printf("%d", uri->port);
            qdict_put(options, "port", qstring_from_str(port_str));
        qdict_put(options, "server.type", qstring_from_str("inet"));
        qdict_put(options, "server.data.host", host);

        port_str = g_strdup_printf("%d", uri->port ?: NBD_DEFAULT_PORT);
        qdict_put(options, "server.data.port", qstring_from_str(port_str));
        g_free(port_str);
    }
    }

out:
    if (qp) {
@@ -123,6 +131,26 @@ out:
    return ret;
}

static bool nbd_has_filename_options_conflict(QDict *options, Error **errp)
{
    const QDictEntry *e;

    for (e = qdict_first(options); e; e = qdict_next(options, e)) {
        if (!strcmp(e->key, "host") ||
            !strcmp(e->key, "port") ||
            !strcmp(e->key, "path") ||
            !strcmp(e->key, "export") ||
            strstart(e->key, "server.", NULL))
        {
            error_setg(errp, "Option '%s' cannot be used with a file name",
                       e->key);
            return true;
        }
    }

    return false;
}

static void nbd_parse_filename(const char *filename, QDict *options,
                               Error **errp)
{
@@ -131,12 +159,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
    const char *host_spec;
    const char *unixpath;

    if (qdict_haskey(options, "host")
        || qdict_haskey(options, "port")
        || qdict_haskey(options, "path"))
    {
        error_setg(errp, "host/port/path and a file name may not be specified "
                         "at the same time");
    if (nbd_has_filename_options_conflict(options, errp)) {
        return;
    }

@@ -173,7 +196,8 @@ static void nbd_parse_filename(const char *filename, QDict *options,

    /* are we a UNIX or TCP socket? */
    if (strstart(host_spec, "unix:", &unixpath)) {
        qdict_put(options, "path", qstring_from_str(unixpath));
        qdict_put(options, "server.type", qstring_from_str("unix"));
        qdict_put(options, "server.data.path", qstring_from_str(unixpath));
    } else {
        InetSocketAddress *addr = NULL;

@@ -182,8 +206,9 @@ static void nbd_parse_filename(const char *filename, QDict *options,
            goto out;
        }

        qdict_put(options, "host", qstring_from_str(addr->host));
        qdict_put(options, "port", qstring_from_str(addr->port));
        qdict_put(options, "server.type", qstring_from_str("inet"));
        qdict_put(options, "server.data.host", qstring_from_str(addr->host));
        qdict_put(options, "server.data.port", qstring_from_str(addr->port));
        qapi_free_InetSocketAddress(addr);
    }

@@ -191,47 +216,81 @@ out:
    g_free(file);
}

static SocketAddress *nbd_config(BDRVNBDState *s, QemuOpts *opts, Error **errp)
static bool nbd_process_legacy_socket_options(QDict *output_options,
                                              QemuOpts *legacy_opts,
                                              Error **errp)
{
    SocketAddress *saddr;
    const char *path = qemu_opt_get(legacy_opts, "path");
    const char *host = qemu_opt_get(legacy_opts, "host");
    const char *port = qemu_opt_get(legacy_opts, "port");
    const QDictEntry *e;

    s->path = g_strdup(qemu_opt_get(opts, "path"));
    s->host = g_strdup(qemu_opt_get(opts, "host"));
    if (!path && !host && !port) {
        return true;
    }

    if (!s->path == !s->host) {
        if (s->path) {
            error_setg(errp, "path and host may not be used at the same time.");
        } else {
            error_setg(errp, "one of path and host must be specified.");
    for (e = qdict_first(output_options); e; e = qdict_next(output_options, e))
    {
        if (strstart(e->key, "server.", NULL)) {
            error_setg(errp, "Cannot use 'server' and path/host/port at the "
                       "same time");
            return false;
        }
        return NULL;
    }

    saddr = g_new0(SocketAddress, 1);
    if (path && host) {
        error_setg(errp, "path and host may not be used at the same time");
        return false;
    } else if (path) {
        if (port) {
            error_setg(errp, "port may not be used without host");
            return false;
        }

    if (s->path) {
        UnixSocketAddress *q_unix;
        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
        q_unix = saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
        q_unix->path = g_strdup(s->path);
    } else {
        InetSocketAddress *inet;
        qdict_put(output_options, "server.type", qstring_from_str("unix"));
        qdict_put(output_options, "server.data.path", qstring_from_str(path));
    } else if (host) {
        qdict_put(output_options, "server.type", qstring_from_str("inet"));
        qdict_put(output_options, "server.data.host", qstring_from_str(host));
        qdict_put(output_options, "server.data.port",
                  qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT)));
    }

    return true;
}

static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options, Error **errp)
{
    SocketAddress *saddr = NULL;
    QDict *addr = NULL;
    QObject *crumpled_addr = NULL;
    Visitor *iv = NULL;
    Error *local_err = NULL;

        s->port = g_strdup(qemu_opt_get(opts, "port"));
    qdict_extract_subqdict(options, &addr, "server.");
    if (!qdict_size(addr)) {
        error_setg(errp, "NBD server address missing");
        goto done;
    }

        saddr->type = SOCKET_ADDRESS_KIND_INET;
        inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
        inet->host = g_strdup(s->host);
        inet->port = g_strdup(s->port);
        if (!inet->port) {
            inet->port = g_strdup_printf("%d", NBD_DEFAULT_PORT);
    crumpled_addr = qdict_crumple(addr, errp);
    if (!crumpled_addr) {
        goto done;
    }

    iv = qobject_input_visitor_new(crumpled_addr, true);
    visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        goto done;
    }

    s->client.is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;

    s->export = g_strdup(qemu_opt_get(opts, "export"));

done:
    QDECREF(addr);
    qobject_decref(crumpled_addr);
    visit_free(iv);
    return saddr;
}

@@ -332,7 +391,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
    QemuOpts *opts = NULL;
    Error *local_err = NULL;
    QIOChannelSocket *sioc = NULL;
    SocketAddress *saddr = NULL;
    QCryptoTLSCreds *tlscreds = NULL;
    const char *hostname = NULL;
    int ret = -EINVAL;
@@ -344,12 +402,19 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
        goto error;
    }

    /* Translate @host, @port, and @path to a SocketAddress */
    if (!nbd_process_legacy_socket_options(options, opts, errp)) {
        goto error;
    }

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

    s->export = g_strdup(qemu_opt_get(opts, "export"));

    s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
    if (s->tlscredsid) {
        tlscreds = nbd_get_tls_creds(s->tlscredsid, errp);
@@ -357,17 +422,17 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
            goto error;
        }

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

    /* establish TCP connection, return error if it fails
     * TODO: Configurable retry-until-timeout behaviour.
     */
    sioc = nbd_establish_connection(saddr, errp);
    sioc = nbd_establish_connection(s->saddr, errp);
    if (!sioc) {
        ret = -ECONNREFUSED;
        goto error;
@@ -384,13 +449,10 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
        object_unref(OBJECT(tlscreds));
    }
    if (ret < 0) {
        g_free(s->path);
        g_free(s->host);
        g_free(s->port);
        qapi_free_SocketAddress(s->saddr);
        g_free(s->export);
        g_free(s->tlscredsid);
    }
    qapi_free_SocketAddress(saddr);
    qemu_opts_del(opts);
    return ret;
}
@@ -412,9 +474,7 @@ static void nbd_close(BlockDriverState *bs)

    nbd_client_close(bs);

    g_free(s->path);
    g_free(s->host);
    g_free(s->port);
    qapi_free_SocketAddress(s->saddr);
    g_free(s->export);
    g_free(s->tlscredsid);
}
@@ -441,45 +501,51 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
{
    BDRVNBDState *s = bs->opaque;
    QDict *opts = qdict_new();
    QObject *saddr_qdict;
    Visitor *ov;
    const char *host = NULL, *port = NULL, *path = NULL;

    qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
    if (s->saddr->type == SOCKET_ADDRESS_KIND_INET) {
        const InetSocketAddress *inet = s->saddr->u.inet.data;
        if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) {
            host = inet->host;
            port = inet->port;
        }
    } else if (s->saddr->type == SOCKET_ADDRESS_KIND_UNIX) {
        path = s->saddr->u.q_unix.data->path;
    }

    if (s->path && s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd+unix:///%s?socket=%s", s->export, s->path);
    } else if (s->path && !s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd+unix://?socket=%s", s->path);
    } else if (!s->path && s->export && s->port) {
    qdict_put(opts, "driver", qstring_from_str("nbd"));

    if (path && s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd://%s:%s/%s", s->host, s->port, s->export);
    } else if (!s->path && s->export && !s->port) {
                 "nbd+unix:///%s?socket=%s", s->export, path);
    } else if (path && !s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd://%s/%s", s->host, s->export);
    } else if (!s->path && !s->export && s->port) {
                 "nbd+unix://?socket=%s", path);
    } else if (host && s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd://%s:%s", s->host, s->port);
    } else if (!s->path && !s->export && !s->port) {
                 "nbd://%s:%s/%s", host, port, s->export);
    } else if (host && !s->export) {
        snprintf(bs->exact_filename, sizeof(bs->exact_filename),
                 "nbd://%s", s->host);
                 "nbd://%s:%s", host, port);
    }

    if (s->path) {
        qdict_put_obj(opts, "path", QOBJECT(qstring_from_str(s->path)));
    } else if (s->port) {
        qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host)));
        qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(s->port)));
    } else {
        qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(s->host)));
    }
    ov = qobject_output_visitor_new(&saddr_qdict);
    visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
    visit_complete(ov, &saddr_qdict);
    assert(qobject_type(saddr_qdict) == QTYPE_QDICT);

    qdict_put_obj(opts, "server", saddr_qdict);

    if (s->export) {
        qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(s->export)));
        qdict_put(opts, "export", qstring_from_str(s->export));
    }
    if (s->tlscredsid) {
        qdict_put_obj(opts, "tls-creds",
                      QOBJECT(qstring_from_str(s->tlscredsid)));
        qdict_put(opts, "tls-creds", qstring_from_str(s->tlscredsid));
    }

    qdict_flatten(opts);
    bs->full_open_options = opts;
}

+13 −3
Original line number Diff line number Diff line
@@ -2069,13 +2069,23 @@ static bool hdev_is_sg(BlockDriverState *bs)

#if defined(__linux__)

    BDRVRawState *s = bs->opaque;
    struct stat st;
    struct sg_scsi_id scsiid;
    int sg_version;
    int ret;

    if (stat(bs->filename, &st) < 0 || !S_ISCHR(st.st_mode)) {
        return false;
    }

    if (stat(bs->filename, &st) >= 0 && S_ISCHR(st.st_mode) &&
        !bdrv_ioctl(bs, SG_GET_VERSION_NUM, &sg_version) &&
        !bdrv_ioctl(bs, SG_GET_SCSI_ID, &scsiid)) {
    ret = ioctl(s->fd, SG_GET_VERSION_NUM, &sg_version);
    if (ret < 0) {
        return false;
    }

    ret = ioctl(s->fd, SG_GET_SCSI_ID, &scsiid);
    if (ret >= 0) {
        DPRINTF("SG device found: type=%d, version=%d\n",
            scsiid.scsi_type, sg_version);
        return true;
+3 −6
Original line number Diff line number Diff line
@@ -176,12 +176,9 @@ static void raw_lock_medium(BlockDriverState *bs, bool locked)
    bdrv_lock_medium(bs->file->bs, locked);
}

static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
                                 unsigned long int req, void *buf,
                                 BlockCompletionFunc *cb,
                                 void *opaque)
static int raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
    return bdrv_aio_ioctl(bs->file->bs, req, buf, cb, opaque);
    return bdrv_co_ioctl(bs->file->bs, req, buf);
}

static int raw_has_zero_init(BlockDriverState *bs)
@@ -261,7 +258,7 @@ BlockDriver bdrv_raw = {
    .bdrv_media_changed   = &raw_media_changed,
    .bdrv_eject           = &raw_eject,
    .bdrv_lock_medium     = &raw_lock_medium,
    .bdrv_aio_ioctl       = &raw_aio_ioctl,
    .bdrv_co_ioctl        = &raw_co_ioctl,
    .create_opts          = &raw_create_opts,
    .bdrv_has_zero_init   = &raw_has_zero_init
};
Loading