Commit 41691986 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 Fri 04 Sep 2015 20:45:33 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream:
  quorum: validate vote threshold against num_children even if read-pattern is fifo
  qcow2: reorder fields in Qcow2CachedTable to reduce padding
  docs: document how to configure the qcow2 L2/refcount caches
  qcow2: add option to clean unused cache entries after some time
  qcow2: mark the memory as no longer needed after qcow2_cache_empty()
  iotests: Warn if python subprocess is killed
  iotests: Do not suppress segfaults in bash tests
  iotests: Respect -nodefaults in tests 41 and 55
  iotests: More options for VM.add_drive()
  qemu-img: Fix crash in amend invocation
  block/raw-posix: Use raw_normalize_devicepath()
  qemu-iotests: s390x: fix test 130
  qemu-iotests: s390x: fix test 049, reject negative sizes in QemuOpts
  qemu-iotests: s390x: fix test 041 and 055
  qemu-iotests: disable default qemu devices for cross-platform compatibility
  qemu-iotests: qemu machine type support

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 298fae38 c804b579
Loading
Loading
Loading
Loading
+62 −1
Original line number Diff line number Diff line
@@ -22,16 +22,24 @@
 * THE SOFTWARE.
 */

/* Needed for CONFIG_MADVISE */
#include "config-host.h"

#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
#include <sys/mman.h>
#endif

#include "block/block_int.h"
#include "qemu-common.h"
#include "qemu/osdep.h"
#include "qcow2.h"
#include "trace.h"

typedef struct Qcow2CachedTable {
    int64_t  offset;
    bool     dirty;
    uint64_t lru_counter;
    int      ref;
    bool     dirty;
} Qcow2CachedTable;

struct Qcow2Cache {
@@ -41,6 +49,7 @@ struct Qcow2Cache {
    bool                    depends_on_flush;
    void                   *table_array;
    uint64_t                lru_counter;
    uint64_t                cache_clean_lru_counter;
};

static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
@@ -60,6 +69,56 @@ static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
    return idx;
}

static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
                                      int i, int num_tables)
{
#if QEMU_MADV_DONTNEED != QEMU_MADV_INVALID
    BDRVQcowState *s = bs->opaque;
    void *t = qcow2_cache_get_table_addr(bs, c, i);
    int align = getpagesize();
    size_t mem_size = (size_t) s->cluster_size * num_tables;
    size_t offset = QEMU_ALIGN_UP((uintptr_t) t, align) - (uintptr_t) t;
    size_t length = QEMU_ALIGN_DOWN(mem_size - offset, align);
    if (length > 0) {
        qemu_madvise((uint8_t *) t + offset, length, QEMU_MADV_DONTNEED);
    }
#endif
}

static inline bool can_clean_entry(Qcow2Cache *c, int i)
{
    Qcow2CachedTable *t = &c->entries[i];
    return t->ref == 0 && !t->dirty && t->offset != 0 &&
        t->lru_counter <= c->cache_clean_lru_counter;
}

void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
{
    int i = 0;
    while (i < c->size) {
        int to_clean = 0;

        /* Skip the entries that we don't need to clean */
        while (i < c->size && !can_clean_entry(c, i)) {
            i++;
        }

        /* And count how many we can clean in a row */
        while (i < c->size && can_clean_entry(c, i)) {
            c->entries[i].offset = 0;
            c->entries[i].lru_counter = 0;
            i++;
            to_clean++;
        }

        if (to_clean > 0) {
            qcow2_cache_table_release(bs, c, i - to_clean, to_clean);
        }
    }

    c->cache_clean_lru_counter = c->lru_counter;
}

Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
{
    BDRVQcowState *s = bs->opaque;
@@ -237,6 +296,8 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
        c->entries[i].lru_counter = 0;
    }

    qcow2_cache_table_release(bs, c, 0, c->size);

    c->lru_counter = 0;

    return 0;
+64 −0
Original line number Diff line number Diff line
@@ -467,6 +467,11 @@ static QemuOptsList qcow2_runtime_opts = {
            .type = QEMU_OPT_SIZE,
            .help = "Maximum refcount block cache size",
        },
        {
            .name = QCOW2_OPT_CACHE_CLEAN_INTERVAL,
            .type = QEMU_OPT_NUMBER,
            .help = "Clean unused cache entries after this time (in seconds)",
        },
        { /* end of list */ }
    },
};
@@ -482,6 +487,49 @@ static const char *overlap_bool_option_names[QCOW2_OL_MAX_BITNR] = {
    [QCOW2_OL_INACTIVE_L2_BITNR]    = QCOW2_OPT_OVERLAP_INACTIVE_L2,
};

static void cache_clean_timer_cb(void *opaque)
{
    BlockDriverState *bs = opaque;
    BDRVQcowState *s = bs->opaque;
    qcow2_cache_clean_unused(bs, s->l2_table_cache);
    qcow2_cache_clean_unused(bs, s->refcount_block_cache);
    timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
              (int64_t) s->cache_clean_interval * 1000);
}

static void cache_clean_timer_init(BlockDriverState *bs, AioContext *context)
{
    BDRVQcowState *s = bs->opaque;
    if (s->cache_clean_interval > 0) {
        s->cache_clean_timer = aio_timer_new(context, QEMU_CLOCK_VIRTUAL,
                                             SCALE_MS, cache_clean_timer_cb,
                                             bs);
        timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
                  (int64_t) s->cache_clean_interval * 1000);
    }
}

static void cache_clean_timer_del(BlockDriverState *bs)
{
    BDRVQcowState *s = bs->opaque;
    if (s->cache_clean_timer) {
        timer_del(s->cache_clean_timer);
        timer_free(s->cache_clean_timer);
        s->cache_clean_timer = NULL;
    }
}

static void qcow2_detach_aio_context(BlockDriverState *bs)
{
    cache_clean_timer_del(bs);
}

static void qcow2_attach_aio_context(BlockDriverState *bs,
                                     AioContext *new_context)
{
    cache_clean_timer_init(bs, new_context);
}

static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
                             uint64_t *l2_cache_size,
                             uint64_t *refcount_cache_size, Error **errp)
@@ -555,6 +603,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
    const char *opt_overlap_check, *opt_overlap_check_template;
    int overlap_check_template = 0;
    uint64_t l2_cache_size, refcount_cache_size;
    uint64_t cache_clean_interval;

    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
    if (ret < 0) {
@@ -848,6 +897,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
        goto fail;
    }

    cache_clean_interval =
        qemu_opt_get_number(opts, QCOW2_OPT_CACHE_CLEAN_INTERVAL, 0);
    if (cache_clean_interval > UINT_MAX) {
        error_setg(errp, "Cache clean interval too big");
        ret = -EINVAL;
        goto fail;
    }
    s->cache_clean_interval = cache_clean_interval;
    cache_clean_timer_init(bs, bdrv_get_aio_context(bs));

    s->cluster_cache = g_malloc(s->cluster_size);
    /* one more sector for decompressed data alignment */
    s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
@@ -1013,6 +1072,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
    qemu_vfree(s->l1_table);
    /* else pre-write overlap checks in cache_destroy may crash */
    s->l1_table = NULL;
    cache_clean_timer_del(bs);
    if (s->l2_table_cache) {
        qcow2_cache_destroy(bs, s->l2_table_cache);
    }
@@ -1471,6 +1531,7 @@ static void qcow2_close(BlockDriverState *bs)
        }
    }

    cache_clean_timer_del(bs);
    qcow2_cache_destroy(bs, s->l2_table_cache);
    qcow2_cache_destroy(bs, s->refcount_block_cache);

@@ -2977,6 +3038,9 @@ BlockDriver bdrv_qcow2 = {
    .create_opts         = &qcow2_create_opts,
    .bdrv_check          = qcow2_check,
    .bdrv_amend_options  = qcow2_amend_options,

    .bdrv_detach_aio_context  = qcow2_detach_aio_context,
    .bdrv_attach_aio_context  = qcow2_attach_aio_context,
};

static void bdrv_qcow2_init(void)
+4 −0
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@
#define QCOW2_OPT_CACHE_SIZE "cache-size"
#define QCOW2_OPT_L2_CACHE_SIZE "l2-cache-size"
#define QCOW2_OPT_REFCOUNT_CACHE_SIZE "refcount-cache-size"
#define QCOW2_OPT_CACHE_CLEAN_INTERVAL "cache-clean-interval"

typedef struct QCowHeader {
    uint32_t magic;
@@ -239,6 +240,8 @@ typedef struct BDRVQcowState {

    Qcow2Cache* l2_table_cache;
    Qcow2Cache* refcount_block_cache;
    QEMUTimer *cache_clean_timer;
    unsigned cache_clean_interval;

    uint8_t *cluster_cache;
    uint8_t *cluster_data;
@@ -581,6 +584,7 @@ int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
    Qcow2Cache *dependency);
void qcow2_cache_depends_on_flush(Qcow2Cache *c);

void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);

int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
+6 −6
Original line number Diff line number Diff line
@@ -889,20 +889,20 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
    }

    s->threshold = qemu_opt_get_number(opts, QUORUM_OPT_VOTE_THRESHOLD, 0);
    ret = parse_read_pattern(qemu_opt_get(opts, QUORUM_OPT_READ_PATTERN));
    /* and validate it against s->num_children */
    ret = quorum_valid_threshold(s->threshold, s->num_children, &local_err);
    if (ret < 0) {
        error_setg(&local_err, "Please set read-pattern as fifo or quorum");
        goto exit;
    }
    s->read_pattern = ret;

    if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
        /* and validate it against s->num_children */
        ret = quorum_valid_threshold(s->threshold, s->num_children, &local_err);
    ret = parse_read_pattern(qemu_opt_get(opts, QUORUM_OPT_READ_PATTERN));
    if (ret < 0) {
        error_setg(&local_err, "Please set read-pattern as fifo or quorum");
        goto exit;
    }
    s->read_pattern = ret;

    if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
        /* is the driver in blkverify mode */
        if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
            s->num_children == 2 && s->threshold == 2) {
+17 −5
Original line number Diff line number Diff line
@@ -670,13 +670,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,

    /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
    if (raw_s->fd == -1) {
        const char *normalized_filename = state->bs->filename;
        ret = raw_normalize_devicepath(&normalized_filename);
        if (ret < 0) {
            error_setg_errno(errp, -ret, "Could not normalize device path");
        } else {
            assert(!(raw_s->open_flags & O_CREAT));
        raw_s->fd = qemu_open(state->bs->filename, raw_s->open_flags);
            raw_s->fd = qemu_open(normalized_filename, raw_s->open_flags);
            if (raw_s->fd == -1) {
                error_setg_errno(errp, errno, "Could not reopen file");
                ret = -1;
            }
        }
    }

    /* Fail already reopen_prepare() if we can't get a working O_DIRECT
     * alignment with the new fd. */
@@ -2314,6 +2320,12 @@ static int hdev_create(const char *filename, QemuOpts *opts,

    (void)has_prefix;

    ret = raw_normalize_devicepath(&filename);
    if (ret < 0) {
        error_setg_errno(errp, -ret, "Could not normalize device path");
        return ret;
    }

    /* Read out options */
    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
                          BDRV_SECTOR_SIZE);
Loading