Commit 79b2a13a authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/ericb/tags/pull-nbd-2017-10-14' into staging



nbd patches for 2017-10-14

- Marc-André Lureau - NBD: use g_new() family of functions
- Vladimir Sementsov-Ogievskiy - first half of 00/13 nbd minimal structured read

# gpg: Signature made Sun 15 Oct 2017 01:38:47 BST
# gpg:                using RSA key 0xA7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>"
# gpg:                 aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>"
# gpg:                 aka "[jpeg image of size 6874]"
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2  F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-nbd-2017-10-14:
  nbd: header constants indenting
  nbd/server: simplify reply transmission
  nbd/server: refactor nbd_co_send_simple_reply parameters
  nbd/server: do not use NBDReply structure
  nbd/server: structurize simple reply header sending
  nbd: rename some simple-request related objects to be _simple_
  block/nbd-client: refactor nbd_co_receive_reply
  block/nbd-client: assert qiov len once in nbd_co_request
  NBD: use g_new() family of functions

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 48ae1f60 92652b12
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -156,7 +156,6 @@ static int nbd_co_send_request(BlockDriverState *bs,
        qio_channel_set_cork(s->ioc, true);
        rc = nbd_send_request(s->ioc, request);
        if (rc >= 0 && !s->quit) {
            assert(request->len == iov_size(qiov->iov, qiov->niov));
            if (qio_channel_writev_all(s->ioc, qiov->iov, qiov->niov,
                                       NULL) < 0) {
                rc = -EIO;
@@ -181,11 +180,11 @@ err:
}

static int nbd_co_receive_reply(NBDClientSession *s,
                                NBDRequest *request,
                                uint64_t handle,
                                QEMUIOVector *qiov)
{
    int ret;
    int i = HANDLE_TO_INDEX(s, request->handle);
    int i = HANDLE_TO_INDEX(s, handle);

    /* Wait until we're woken up by nbd_read_reply_entry.  */
    s->requests[i].receiving = true;
@@ -194,10 +193,9 @@ static int nbd_co_receive_reply(NBDClientSession *s,
    if (!s->ioc || s->quit) {
        ret = -EIO;
    } else {
        assert(s->reply.handle == request->handle);
        assert(s->reply.handle == handle);
        ret = -s->reply.error;
        if (qiov && s->reply.error == 0) {
            assert(request->len == iov_size(qiov->iov, qiov->niov));
            if (qio_channel_readv_all(s->ioc, qiov->iov, qiov->niov,
                                      NULL) < 0) {
                ret = -EIO;
@@ -231,15 +229,19 @@ static int nbd_co_request(BlockDriverState *bs,
    NBDClientSession *client = nbd_get_client_session(bs);
    int ret;

    assert(!qiov || request->type == NBD_CMD_WRITE ||
           request->type == NBD_CMD_READ);
    if (qiov) {
        assert(request->type == NBD_CMD_WRITE || request->type == NBD_CMD_READ);
        assert(request->len == iov_size(qiov->iov, qiov->niov));
    } else {
        assert(request->type != NBD_CMD_WRITE && request->type != NBD_CMD_READ);
    }
    ret = nbd_co_send_request(bs, request,
                              request->type == NBD_CMD_WRITE ? qiov : NULL);
    if (ret < 0) {
        return ret;
    }

    return nbd_co_receive_reply(client, request,
    return nbd_co_receive_reply(client, request->handle,
                                request->type == NBD_CMD_READ ? qiov : NULL);
}

+14 −7
Original line number Diff line number Diff line
@@ -63,13 +63,20 @@ struct NBDReply {
};
typedef struct NBDReply NBDReply;

typedef struct NBDSimpleReply {
    uint32_t magic;  /* NBD_SIMPLE_REPLY_MAGIC */
    uint32_t error;
    uint64_t handle;
} QEMU_PACKED NBDSimpleReply;

/* Transmission (export) flags: sent from server to client during handshake,
   but describe what will happen during transmission */
#define NBD_FLAG_HAS_FLAGS         (1 << 0) /* Flags are there */
#define NBD_FLAG_READ_ONLY         (1 << 1) /* Device is read-only */
#define NBD_FLAG_SEND_FLUSH        (1 << 2) /* Send FLUSH */
#define NBD_FLAG_SEND_FUA          (1 << 3) /* Send FUA (Force Unit Access) */
#define NBD_FLAG_ROTATIONAL     (1 << 4)        /* Use elevator algorithm - rotational media */
#define NBD_FLAG_ROTATIONAL        (1 << 4) /* Use elevator algorithm -
                                               rotational media */
#define NBD_FLAG_SEND_TRIM         (1 << 5) /* Send TRIM (discard) */
#define NBD_FLAG_SEND_WRITE_ZEROES (1 << 6) /* Send WRITE_ZEROES */

+2 −2
Original line number Diff line number Diff line
@@ -931,7 +931,7 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
    }

    /* Reply
       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
       [ 0 ..  3]    magic   (NBD_SIMPLE_REPLY_MAGIC)
       [ 4 ..  7]    error   (0 == no error)
       [ 7 .. 15]    handle
     */
@@ -949,7 +949,7 @@ int nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
    }
    trace_nbd_receive_reply(magic, reply->error, reply->handle);

    if (magic != NBD_REPLY_MAGIC) {
    if (magic != NBD_SIMPLE_REPLY_MAGIC) {
        error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic);
        return -EINVAL;
    }
+17 −17
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@
#define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124)

#define NBD_REQUEST_MAGIC           0x25609513
#define NBD_REPLY_MAGIC         0x67446698
#define NBD_SIMPLE_REPLY_MAGIC      0x67446698
#define NBD_OPTS_MAGIC              0x49484156454F5054LL
#define NBD_CLIENT_MAGIC            0x0000420281861253LL
#define NBD_REP_MAGIC               0x0003e889045565a9LL
+43 −58
Original line number Diff line number Diff line
@@ -902,26 +902,6 @@ static int nbd_receive_request(QIOChannel *ioc, NBDRequest *request,
    return 0;
}

static int nbd_send_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
{
    uint8_t buf[NBD_REPLY_SIZE];

    reply->error = system_errno_to_nbd_errno(reply->error);

    trace_nbd_send_reply(reply->error, reply->handle);

    /* Reply
       [ 0 ..  3]    magic   (NBD_REPLY_MAGIC)
       [ 4 ..  7]    error   (0 == no error)
       [ 7 .. 15]    handle
     */
    stl_be_p(buf, NBD_REPLY_MAGIC);
    stl_be_p(buf + 4, reply->error);
    stq_be_p(buf + 8, reply->handle);

    return nbd_write(ioc, buf, sizeof(buf), errp);
}

#define MAX_NBD_REQUESTS 16

void nbd_client_get(NBDClient *client)
@@ -1047,7 +1027,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
{
    AioContext *ctx;
    BlockBackend *blk;
    NBDExport *exp = g_malloc0(sizeof(NBDExport));
    NBDExport *exp = g_new0(NBDExport, 1);
    uint64_t perm;
    int ret;

@@ -1208,38 +1188,51 @@ void nbd_export_close_all(void)
    }
}

static int nbd_co_send_reply(NBDRequestData *req, NBDReply *reply, int len,
                             Error **errp)
static int coroutine_fn nbd_co_send_iov(NBDClient *client, struct iovec *iov,
                                        unsigned niov, Error **errp)
{
    NBDClient *client = req->client;
    int ret;

    g_assert(qemu_in_coroutine());

    trace_nbd_co_send_reply(reply->handle, reply->error, len);

    qemu_co_mutex_lock(&client->send_lock);
    client->send_coroutine = qemu_coroutine_self();

    if (!len) {
        ret = nbd_send_reply(client->ioc, reply, errp);
    } else {
        qio_channel_set_cork(client->ioc, true);
        ret = nbd_send_reply(client->ioc, reply, errp);
        if (ret == 0) {
            ret = nbd_write(client->ioc, req->data, len, errp);
            if (ret < 0) {
                ret = -EIO;
            }
        }
        qio_channel_set_cork(client->ioc, false);
    }
    ret = qio_channel_writev_all(client->ioc, iov, niov, errp) < 0 ? -EIO : 0;

    client->send_coroutine = NULL;
    qemu_co_mutex_unlock(&client->send_lock);

    return ret;
}

static inline void set_be_simple_reply(NBDSimpleReply *reply, uint64_t error,
                                       uint64_t handle)
{
    stl_be_p(&reply->magic, NBD_SIMPLE_REPLY_MAGIC);
    stl_be_p(&reply->error, error);
    stq_be_p(&reply->handle, handle);
}

static int nbd_co_send_simple_reply(NBDClient *client,
                                    uint64_t handle,
                                    uint32_t error,
                                    void *data,
                                    size_t len,
                                    Error **errp)
{
    NBDSimpleReply reply;
    int nbd_err = system_errno_to_nbd_errno(error);
    struct iovec iov[] = {
        {.iov_base = &reply, .iov_len = sizeof(reply)},
        {.iov_base = data, .iov_len = len}
    };

    trace_nbd_co_send_simple_reply(handle, nbd_err, len);
    set_be_simple_reply(&reply, nbd_err, handle);

    return nbd_co_send_iov(client, iov, len ? 2 : 1, errp);
}

/* nbd_co_receive_request
 * Collect a client request. Return 0 if request looks valid, -EIO to drop
 * connection right away, and any other negative value to report an error to
@@ -1331,7 +1324,6 @@ static coroutine_fn void nbd_trip(void *opaque)
    NBDExport *exp = client->exp;
    NBDRequestData *req;
    NBDRequest request = { 0 };    /* GCC thinks it can be used uninitialized */
    NBDReply reply;
    int ret;
    int flags;
    int reply_data_len = 0;
@@ -1351,11 +1343,7 @@ static coroutine_fn void nbd_trip(void *opaque)
        goto disconnect;
    }

    reply.handle = request.handle;
    reply.error = 0;

    if (ret < 0) {
        reply.error = -ret;
        goto reply;
    }

@@ -1374,7 +1362,6 @@ static coroutine_fn void nbd_trip(void *opaque)
            ret = blk_co_flush(exp->blk);
            if (ret < 0) {
                error_setg_errno(&local_err, -ret, "flush failed");
                reply.error = -ret;
                break;
            }
        }
@@ -1383,7 +1370,6 @@ static coroutine_fn void nbd_trip(void *opaque)
                        req->data, request.len);
        if (ret < 0) {
            error_setg_errno(&local_err, -ret, "reading from file failed");
            reply.error = -ret;
            break;
        }

@@ -1392,7 +1378,7 @@ static coroutine_fn void nbd_trip(void *opaque)
        break;
    case NBD_CMD_WRITE:
        if (exp->nbdflags & NBD_FLAG_READ_ONLY) {
            reply.error = EROFS;
            ret = -EROFS;
            break;
        }

@@ -1404,14 +1390,13 @@ static coroutine_fn void nbd_trip(void *opaque)
                         req->data, request.len, flags);
        if (ret < 0) {
            error_setg_errno(&local_err, -ret, "writing to file failed");
            reply.error = -ret;
        }

        break;
    case NBD_CMD_WRITE_ZEROES:
        if (exp->nbdflags & NBD_FLAG_READ_ONLY) {
            error_setg(&local_err, "Server is read-only, return error");
            reply.error = EROFS;
            ret = -EROFS;
            break;
        }

@@ -1426,7 +1411,6 @@ static coroutine_fn void nbd_trip(void *opaque)
                                request.len, flags);
        if (ret < 0) {
            error_setg_errno(&local_err, -ret, "writing to file failed");
            reply.error = -ret;
        }

        break;
@@ -1438,7 +1422,6 @@ static coroutine_fn void nbd_trip(void *opaque)
        ret = blk_co_flush(exp->blk);
        if (ret < 0) {
            error_setg_errno(&local_err, -ret, "flush failed");
            reply.error = -ret;
        }

        break;
@@ -1447,25 +1430,27 @@ static coroutine_fn void nbd_trip(void *opaque)
                              request.len);
        if (ret < 0) {
            error_setg_errno(&local_err, -ret, "discard failed");
            reply.error = -ret;
        }

        break;
    default:
        error_setg(&local_err, "invalid request type (%" PRIu32 ") received",
                   request.type);
        reply.error = EINVAL;
        ret = -EINVAL;
    }

reply:
    if (local_err) {
        /* If we are here local_err is not fatal error, already stored in
         * reply.error */
        /* If we get here, local_err was not a fatal error, and should be sent
         * to the client. */
        error_report_err(local_err);
        local_err = NULL;
    }

    if (nbd_co_send_reply(req, &reply, reply_data_len, &local_err) < 0) {
    if (nbd_co_send_simple_reply(req->client, request.handle,
                                 ret < 0 ? -ret : 0,
                                 req->data, reply_data_len, &local_err) < 0)
    {
        error_prepend(&local_err, "Failed to send reply: ");
        goto disconnect;
    }
@@ -1539,7 +1524,7 @@ void nbd_client_new(NBDExport *exp,
    NBDClient *client;
    Coroutine *co;

    client = g_malloc0(sizeof(NBDClient));
    client = g_new0(NBDClient, 1);
    client->refcount = 1;
    client->exp = exp;
    client->tlscreds = tlscreds;
Loading