Commit a6f2cb03 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging



# gpg: Signature made Thu Apr  9 10:55:11 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/block-pull-request:
  block/iscsi: handle zero events from iscsi_which_events
  aio: strengthen memory barriers for bottom half scheduling
  virtio-blk: correctly dirty guest memory
  qcow2: Fix header update with overridden backing file

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents cf811fff 05b685fb
Loading
Loading
Loading
Loading
+12 −16
Original line number Diff line number Diff line
@@ -72,12 +72,13 @@ int aio_bh_poll(AioContext *ctx)
        /* Make sure that fetching bh happens before accessing its members */
        smp_read_barrier_depends();
        next = bh->next;
        if (!bh->deleted && bh->scheduled) {
            bh->scheduled = 0;
            /* Paired with write barrier in bh schedule to ensure reading for
             * idle & callbacks coming after bh's scheduling.
        /* The atomic_xchg is paired with the one in qemu_bh_schedule.  The
         * implicit memory barrier ensures that the callback sees all writes
         * done by the scheduling thread.  It also ensures that the scheduling
         * thread sees the zero before bh->cb has run, and thus will call
         * aio_notify again if necessary.
         */
            smp_rmb();
        if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
            if (!bh->idle)
                ret = 1;
            bh->idle = 0;
@@ -108,34 +109,29 @@ int aio_bh_poll(AioContext *ctx)

void qemu_bh_schedule_idle(QEMUBH *bh)
{
    if (bh->scheduled)
        return;
    bh->idle = 1;
    /* Make sure that idle & any writes needed by the callback are done
     * before the locations are read in the aio_bh_poll.
     */
    smp_wmb();
    bh->scheduled = 1;
    atomic_mb_set(&bh->scheduled, 1);
}

void qemu_bh_schedule(QEMUBH *bh)
{
    AioContext *ctx;

    if (bh->scheduled)
        return;
    ctx = bh->ctx;
    bh->idle = 0;
    /* Make sure that:
    /* The memory barrier implicit in atomic_xchg makes sure that:
     * 1. idle & any writes needed by the callback are done before the
     *    locations are read in the aio_bh_poll.
     * 2. ctx is loaded before scheduled is set and the callback has a chance
     *    to execute.
     */
    smp_mb();
    bh->scheduled = 1;
    if (atomic_xchg(&bh->scheduled, 1) == 0) {
        aio_notify(ctx);
    }
}


/* This func is async.
+27 −6
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ typedef struct IscsiLun {
    uint64_t num_blocks;
    int events;
    QEMUTimer *nop_timer;
    QEMUTimer *event_timer;
    uint8_t lbpme;
    uint8_t lbprz;
    uint8_t has_write_same;
@@ -95,6 +96,7 @@ typedef struct IscsiAIOCB {
#endif
} IscsiAIOCB;

#define EVENT_INTERVAL 250
#define NOP_INTERVAL 5000
#define MAX_NOP_FAILURES 3
#define ISCSI_CMD_RETRIES ARRAY_SIZE(iscsi_retry_times)
@@ -256,21 +258,30 @@ static void
iscsi_set_events(IscsiLun *iscsilun)
{
    struct iscsi_context *iscsi = iscsilun->iscsi;
    int ev;
    int ev = iscsi_which_events(iscsi);

    /* We always register a read handler.  */
    ev = POLLIN;
    ev |= iscsi_which_events(iscsi);
    if (ev != iscsilun->events) {
        aio_set_fd_handler(iscsilun->aio_context,
                           iscsi_get_fd(iscsi),
                           iscsi_process_read,
                           (ev & POLLIN) ? iscsi_process_read : NULL,
                           (ev & POLLOUT) ? iscsi_process_write : NULL,
                           iscsilun);
        iscsilun->events = ev;
    }

    /* newer versions of libiscsi may return zero events. In this
     * case start a timer to ensure we are able to return to service
     * once this situation changes. */
    if (!ev) {
        timer_mod(iscsilun->event_timer,
                  qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + EVENT_INTERVAL);
    }
}

    iscsilun->events = ev;
static void iscsi_timed_set_events(void *opaque)
{
    IscsiLun *iscsilun = opaque;
    iscsi_set_events(iscsilun);
}

static void
@@ -1214,6 +1225,11 @@ static void iscsi_detach_aio_context(BlockDriverState *bs)
        timer_free(iscsilun->nop_timer);
        iscsilun->nop_timer = NULL;
    }
    if (iscsilun->event_timer) {
        timer_del(iscsilun->event_timer);
        timer_free(iscsilun->event_timer);
        iscsilun->event_timer = NULL;
    }
}

static void iscsi_attach_aio_context(BlockDriverState *bs,
@@ -1230,6 +1246,11 @@ static void iscsi_attach_aio_context(BlockDriverState *bs,
                                        iscsi_nop_timed_event, iscsilun);
    timer_mod(iscsilun->nop_timer,
              qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);

    /* Prepare a timer for a delayed call to iscsi_set_events */
    iscsilun->event_timer = aio_timer_new(iscsilun->aio_context,
                                          QEMU_CLOCK_REALTIME, SCALE_MS,
                                          iscsi_timed_set_events, iscsilun);
}

static bool iscsi_is_write_protected(IscsiLun *iscsilun)
+22 −7
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
                return 3;
            }
            bs->backing_format[ext.len] = '\0';
            s->image_backing_format = g_strdup(bs->backing_format);
#ifdef DEBUG_EXT
            printf("Qcow2: Got format extension %s\n", bs->backing_format);
#endif
@@ -884,6 +885,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
            goto fail;
        }
        bs->backing_file[len] = '\0';
        s->image_backing_file = g_strdup(bs->backing_file);
    }

    /* Internal snapshots */
@@ -1457,6 +1459,9 @@ static void qcow2_close(BlockDriverState *bs)
    g_free(s->unknown_header_fields);
    cleanup_unknown_header_ext(bs);

    g_free(s->image_backing_file);
    g_free(s->image_backing_format);

    g_free(s->cluster_cache);
    qemu_vfree(s->cluster_data);
    qcow2_refcount_close(bs);
@@ -1622,9 +1627,10 @@ int qcow2_update_header(BlockDriverState *bs)
    }

    /* Backing file format header extension */
    if (*bs->backing_format) {
    if (s->image_backing_format) {
        ret = header_ext_add(buf, QCOW2_EXT_MAGIC_BACKING_FORMAT,
                             bs->backing_format, strlen(bs->backing_format),
                             s->image_backing_format,
                             strlen(s->image_backing_format),
                             buflen);
        if (ret < 0) {
            goto fail;
@@ -1682,8 +1688,8 @@ int qcow2_update_header(BlockDriverState *bs)
    buflen -= ret;

    /* Backing file name */
    if (*bs->backing_file) {
        size_t backing_file_len = strlen(bs->backing_file);
    if (s->image_backing_file) {
        size_t backing_file_len = strlen(s->image_backing_file);

        if (buflen < backing_file_len) {
            ret = -ENOSPC;
@@ -1691,7 +1697,7 @@ int qcow2_update_header(BlockDriverState *bs)
        }

        /* Using strncpy is ok here, since buf is not NUL-terminated. */
        strncpy(buf, bs->backing_file, buflen);
        strncpy(buf, s->image_backing_file, buflen);

        header->backing_file_offset = cpu_to_be64(buf - ((char*) header));
        header->backing_file_size   = cpu_to_be32(backing_file_len);
@@ -1712,9 +1718,17 @@ fail:
static int qcow2_change_backing_file(BlockDriverState *bs,
    const char *backing_file, const char *backing_fmt)
{
    BDRVQcowState *s = bs->opaque;

    pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
    pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");

    g_free(s->image_backing_file);
    g_free(s->image_backing_format);

    s->image_backing_file = backing_file ? g_strdup(bs->backing_file) : NULL;
    s->image_backing_format = backing_fmt ? g_strdup(bs->backing_format) : NULL;

    return qcow2_update_header(bs);
}

@@ -2751,8 +2765,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
    }

    if (backing_file || backing_format) {
        ret = qcow2_change_backing_file(bs, backing_file ?: bs->backing_file,
                                        backing_format ?: bs->backing_format);
        ret = qcow2_change_backing_file(bs,
                    backing_file ?: s->image_backing_file,
                    backing_format ?: s->image_backing_format);
        if (ret < 0) {
            return ret;
        }
+6 −0
Original line number Diff line number Diff line
@@ -283,6 +283,12 @@ typedef struct BDRVQcowState {
    QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
    QTAILQ_HEAD (, Qcow2DiscardRegion) discards;
    bool cache_discards;

    /* Backing file path and format as stored in the image (this is not the
     * effective path/format, which may be the result of a runtime option
     * override) */
    char *image_backing_file;
    char *image_backing_format;
} BDRVQcowState;

struct QCowAIOCB;
+1 −2
Original line number Diff line number Diff line
@@ -77,8 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
    VirtIOBlockDataPlane *s = req->dev->dataplane;
    stb_p(&req->in->status, status);

    vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem,
               req->qiov.size + sizeof(*req->in));
    vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len);

    /* Suppress notification to guest by BH and its scheduled
     * flag because requests are completed as a batch after io
Loading