Block patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTehNaAAoJEH8JsnLIjy/Ws+QP/0C7GTkY+CAgSSoQmIKr96lf k0iRIypxMw68S6NEXtiqFn1yLVv41+puamrznmOSBqxZwwWLpu+J28M8i3M3lr2Q /bs7l22+HfakfJ6AJkYXaLPqAlRdCnM3HOLWpDuVFLeaLlHV14w4oWCIAs/lA6Tg n4S4nKpWUzm97NnNvQjf953kSFZ/xfH72PcICE5vyaQBnrDMMUnRyffdnVBEGMjd hhx/demJNXt+01XxC4VrnvpibGvMthEbQoRwemFi2snD6YXhk9XcT+jiD2VMrgCr fC316vdAFAiVNvI+JjCRE/1gaMRI+m0tNpymzGWnbnEc8P86KUaitASRc150NDSO UgpDg7oneMXC66OdZXG0XqojiAQ8sqHrvMpV+YiirJUbwIcD5ITDKt9omuIjOWjj ENXHOk2U87xoFfqBRRbsuO+U2QtfPDFA4jRjh5ppUy/0xuW/YL3SBCSdUHR8jalM H8mYcC9zKsL7D71Nh6spU4btNK2xjZT+vPoiurHNyiBSVniHagsKPGtzQCqhJEa+ y9xCBCyqZvHBvQ2w1pE4DBOIvt3L0kKd7pRxRch9letCA6Fo/ktb7rvkDkcPVh50 I0kphrnWqGLgC+8oMvh/gjwtzvWkTCfc8jhvzAcBGaInQr+spSaduCAnrGTpfBh1 vfvc1o3NUVhvqipMgdzq =LnQj -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block patches # gpg: Signature made Mon 19 May 2014 15:21:14 BST using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-upstream: (22 commits) block: optimize zero writes with bdrv_write_zeroes blockdev: add a function to parse enum ids from strings util: add qemu_iovec_is_zero qcow1: Stricter backing file length check qcow1: Validate image size (CVE-2014-0223) qcow1: Validate L2 table size (CVE-2014-0222) qcow1: Check maximum cluster size qcow1: Make padding in the header explicit curl: Add usage documentation curl: Add sslverify option curl: Remove broken parsing of options from url curl: Fix build when curl_multi_socket_action isn't available qemu-iotests: Fix blkdebug in VM drive in 030 qemu-iotests: Fix core dump suppression in test 039 iotests: Add test for the JSON protocol block: Allow JSON filenames check-qdict: Add test for qdict_join() qdict: Add qdict_join() block: add test for vhdx image created by Disk2VHD block: vhdx - account for identical header sections ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						ca8c0fab95
					
				
							
								
								
									
										60
									
								
								block.c
								
								
								
								
							
							
						
						
									
										60
									
								
								block.c
								
								
								
								
							| 
						 | 
				
			
			@ -1274,6 +1274,33 @@ out:
 | 
			
		|||
    g_free(tmp_filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QDict *parse_json_filename(const char *filename, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    QObject *options_obj;
 | 
			
		||||
    QDict *options;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    ret = strstart(filename, "json:", &filename);
 | 
			
		||||
    assert(ret);
 | 
			
		||||
 | 
			
		||||
    options_obj = qobject_from_json(filename);
 | 
			
		||||
    if (!options_obj) {
 | 
			
		||||
        error_setg(errp, "Could not parse the JSON options");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (qobject_type(options_obj) != QTYPE_QDICT) {
 | 
			
		||||
        qobject_decref(options_obj);
 | 
			
		||||
        error_setg(errp, "Invalid JSON object given");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    options = qobject_to_qdict(options_obj);
 | 
			
		||||
    qdict_flatten(options);
 | 
			
		||||
 | 
			
		||||
    return options;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Opens a disk image (raw, qcow2, vmdk, ...)
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1337,6 +1364,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
 | 
			
		|||
        options = qdict_new();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (filename && g_str_has_prefix(filename, "json:")) {
 | 
			
		||||
        QDict *json_options = parse_json_filename(filename, &local_err);
 | 
			
		||||
        if (local_err) {
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Options given in the filename have lower priority than options
 | 
			
		||||
         * specified directly */
 | 
			
		||||
        qdict_join(options, json_options, false);
 | 
			
		||||
        QDECREF(json_options);
 | 
			
		||||
        filename = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bs->options = options;
 | 
			
		||||
    options = qdict_clone_shallow(options);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3248,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
 | 
			
		|||
 | 
			
		||||
    ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
 | 
			
		||||
 | 
			
		||||
    if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
 | 
			
		||||
        !(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
 | 
			
		||||
        qemu_iovec_is_zero(qiov)) {
 | 
			
		||||
        flags |= BDRV_REQ_ZERO_WRITE;
 | 
			
		||||
        if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
 | 
			
		||||
            flags |= BDRV_REQ_MAY_UNMAP;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret < 0) {
 | 
			
		||||
        /* Do nothing, write notifier decided to fail this request */
 | 
			
		||||
    } else if (flags & BDRV_REQ_ZERO_WRITE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3864,7 +3914,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
 | 
			
		|||
 | 
			
		||||
    if (!bs->drv->bdrv_co_get_block_status) {
 | 
			
		||||
        *pnum = nb_sectors;
 | 
			
		||||
        ret = BDRV_BLOCK_DATA;
 | 
			
		||||
        ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
 | 
			
		||||
        if (bs->drv->protocol_name) {
 | 
			
		||||
            ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -3883,6 +3933,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
 | 
			
		|||
                                     *pnum, pnum);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
 | 
			
		||||
        ret |= BDRV_BLOCK_ALLOCATED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
 | 
			
		||||
        if (bdrv_unallocated_blocks_are_zero(bs)) {
 | 
			
		||||
            ret |= BDRV_BLOCK_ZERO;
 | 
			
		||||
| 
						 | 
				
			
			@ -3959,9 +4013,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
 | 
			
		|||
    if (ret < 0) {
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    return
 | 
			
		||||
        (ret & BDRV_BLOCK_DATA) ||
 | 
			
		||||
        ((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
 | 
			
		||||
    return (ret & BDRV_BLOCK_ALLOCATED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										79
									
								
								block/curl.c
								
								
								
								
							
							
						
						
									
										79
									
								
								block/curl.c
								
								
								
								
							| 
						 | 
				
			
			@ -23,6 +23,7 @@
 | 
			
		|||
 */
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "block/block_int.h"
 | 
			
		||||
#include "qapi/qmp/qbool.h"
 | 
			
		||||
#include <curl/curl.h>
 | 
			
		||||
 | 
			
		||||
// #define DEBUG
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +38,21 @@
 | 
			
		|||
#if LIBCURL_VERSION_NUM >= 0x071000
 | 
			
		||||
/* The multi interface timer callback was introduced in 7.16.0 */
 | 
			
		||||
#define NEED_CURL_TIMER_CALLBACK
 | 
			
		||||
#define HAVE_SOCKET_ACTION
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_SOCKET_ACTION
 | 
			
		||||
/* If curl_multi_socket_action isn't available, define it statically here in
 | 
			
		||||
 * terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
 | 
			
		||||
 * less efficient but still safe. */
 | 
			
		||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
 | 
			
		||||
                                            curl_socket_t sockfd,
 | 
			
		||||
                                            int ev_bitmask,
 | 
			
		||||
                                            int *running_handles)
 | 
			
		||||
{
 | 
			
		||||
    return curl_multi_socket(multi_handle, sockfd, running_handles);
 | 
			
		||||
}
 | 
			
		||||
#define curl_multi_socket_action __curl_multi_socket_action
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
 | 
			
		||||
| 
						 | 
				
			
			@ -46,12 +62,16 @@
 | 
			
		|||
#define CURL_NUM_STATES 8
 | 
			
		||||
#define CURL_NUM_ACB    8
 | 
			
		||||
#define SECTOR_SIZE     512
 | 
			
		||||
#define READ_AHEAD_SIZE (256 * 1024)
 | 
			
		||||
#define READ_AHEAD_DEFAULT (256 * 1024)
 | 
			
		||||
 | 
			
		||||
#define FIND_RET_NONE   0
 | 
			
		||||
#define FIND_RET_OK     1
 | 
			
		||||
#define FIND_RET_WAIT   2
 | 
			
		||||
 | 
			
		||||
#define CURL_BLOCK_OPT_URL       "url"
 | 
			
		||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
 | 
			
		||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
 | 
			
		||||
 | 
			
		||||
struct BDRVCURLState;
 | 
			
		||||
 | 
			
		||||
typedef struct CURLAIOCB {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
 | 
			
		|||
    CURLState states[CURL_NUM_STATES];
 | 
			
		||||
    char *url;
 | 
			
		||||
    size_t readahead_size;
 | 
			
		||||
    bool sslverify;
 | 
			
		||||
    bool accept_range;
 | 
			
		||||
} BDRVCURLState;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
 | 
			
		|||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
 | 
			
		||||
        curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
 | 
			
		||||
                         (long) s->sslverify);
 | 
			
		||||
        curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
 | 
			
		||||
        curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
 | 
			
		||||
                         (void *)curl_read_cb);
 | 
			
		||||
| 
						 | 
				
			
			@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
 | 
			
		|||
static void curl_parse_filename(const char *filename, QDict *options,
 | 
			
		||||
                                Error **errp)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    #define RA_OPTSTR ":readahead="
 | 
			
		||||
    char *file;
 | 
			
		||||
    char *ra;
 | 
			
		||||
    const char *ra_val;
 | 
			
		||||
    int parse_state = 0;
 | 
			
		||||
 | 
			
		||||
    file = g_strdup(filename);
 | 
			
		||||
 | 
			
		||||
    /* Parse a trailing ":readahead=#:" param, if present. */
 | 
			
		||||
    ra = file + strlen(file) - 1;
 | 
			
		||||
    while (ra >= file) {
 | 
			
		||||
        if (parse_state == 0) {
 | 
			
		||||
            if (*ra == ':') {
 | 
			
		||||
                parse_state++;
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (parse_state == 1) {
 | 
			
		||||
            if (*ra > '9' || *ra < '0') {
 | 
			
		||||
                char *opt_start = ra - strlen(RA_OPTSTR) + 1;
 | 
			
		||||
                if (opt_start > file &&
 | 
			
		||||
                    strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
 | 
			
		||||
                    ra_val = ra + 1;
 | 
			
		||||
                    ra -= strlen(RA_OPTSTR) - 1;
 | 
			
		||||
                    *ra = '\0';
 | 
			
		||||
                    qdict_put(options, "readahead", qstring_from_str(ra_val));
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ra--;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qdict_put(options, "url", qstring_from_str(file));
 | 
			
		||||
 | 
			
		||||
    g_free(file);
 | 
			
		||||
    qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static QemuOptsList runtime_opts = {
 | 
			
		||||
| 
						 | 
				
			
			@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
 | 
			
		|||
    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
 | 
			
		||||
    .desc = {
 | 
			
		||||
        {
 | 
			
		||||
            .name = "url",
 | 
			
		||||
            .name = CURL_BLOCK_OPT_URL,
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
            .help = "URL to open",
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = "readahead",
 | 
			
		||||
            .name = CURL_BLOCK_OPT_READAHEAD,
 | 
			
		||||
            .type = QEMU_OPT_SIZE,
 | 
			
		||||
            .help = "Readahead size",
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            .name = CURL_BLOCK_OPT_SSLVERIFY,
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "Verify SSL certificate"
 | 
			
		||||
        },
 | 
			
		||||
        { /* end of list */ }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
 | 
			
		|||
        goto out_noclean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
 | 
			
		||||
    s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
 | 
			
		||||
                                          READ_AHEAD_DEFAULT);
 | 
			
		||||
    if ((s->readahead_size & 0x1ff) != 0) {
 | 
			
		||||
        error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
 | 
			
		||||
                   s->readahead_size);
 | 
			
		||||
        goto out_noclean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    file = qemu_opt_get(opts, "url");
 | 
			
		||||
    s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
 | 
			
		||||
 | 
			
		||||
    file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
 | 
			
		||||
    if (file == NULL) {
 | 
			
		||||
        error_setg(errp, "curl block driver requires an 'url' option");
 | 
			
		||||
        goto out_noclean;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    info->backing_file_depth = bdrv_get_backing_file_depth(bs);
 | 
			
		||||
    info->detect_zeroes = bs->detect_zeroes;
 | 
			
		||||
 | 
			
		||||
    if (bs->io_limits_enabled) {
 | 
			
		||||
        ThrottleConfig cfg;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										44
									
								
								block/qcow.c
								
								
								
								
							
							
						
						
									
										44
									
								
								block/qcow.c
								
								
								
								
							| 
						 | 
				
			
			@ -48,9 +48,10 @@ typedef struct QCowHeader {
 | 
			
		|||
    uint64_t size; /* in bytes */
 | 
			
		||||
    uint8_t cluster_bits;
 | 
			
		||||
    uint8_t l2_bits;
 | 
			
		||||
    uint16_t padding;
 | 
			
		||||
    uint32_t crypt_method;
 | 
			
		||||
    uint64_t l1_table_offset;
 | 
			
		||||
} QCowHeader;
 | 
			
		||||
} QEMU_PACKED QCowHeader;
 | 
			
		||||
 | 
			
		||||
#define L2_CACHE_SIZE 16
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
 | 
			
		|||
    int cluster_sectors;
 | 
			
		||||
    int l2_bits;
 | 
			
		||||
    int l2_size;
 | 
			
		||||
    int l1_size;
 | 
			
		||||
    unsigned int l1_size;
 | 
			
		||||
    uint64_t cluster_offset_mask;
 | 
			
		||||
    uint64_t l1_table_offset;
 | 
			
		||||
    uint64_t *l1_table;
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
			
		|||
                     Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    BDRVQcowState *s = bs->opaque;
 | 
			
		||||
    int len, i, shift, ret;
 | 
			
		||||
    unsigned int len, i, shift;
 | 
			
		||||
    int ret;
 | 
			
		||||
    QCowHeader header;
 | 
			
		||||
 | 
			
		||||
    ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
 | 
			
		||||
| 
						 | 
				
			
			@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
			
		|||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (header.size <= 1 || header.cluster_bits < 9) {
 | 
			
		||||
        error_setg(errp, "invalid value in qcow header");
 | 
			
		||||
    if (header.size <= 1) {
 | 
			
		||||
        error_setg(errp, "Image size is too small (must be at least 2 bytes)");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
    if (header.cluster_bits < 9 || header.cluster_bits > 16) {
 | 
			
		||||
        error_setg(errp, "Cluster size must be between 512 and 64k");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* l2_bits specifies number of entries; storing a uint64_t in each entry,
 | 
			
		||||
     * so bytes = num_entries << 3. */
 | 
			
		||||
    if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
 | 
			
		||||
        error_setg(errp, "L2 table size must be between 512 and 64k");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (header.crypt_method > QCOW_CRYPT_AES) {
 | 
			
		||||
        error_setg(errp, "invalid encryption method in qcow header");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
			
		|||
 | 
			
		||||
    /* read the level 1 table */
 | 
			
		||||
    shift = s->cluster_bits + s->l2_bits;
 | 
			
		||||
    s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
 | 
			
		||||
    if (header.size > UINT64_MAX - (1LL << shift)) {
 | 
			
		||||
        error_setg(errp, "Image too large");
 | 
			
		||||
        ret = -EINVAL;
 | 
			
		||||
        goto fail;
 | 
			
		||||
    } else {
 | 
			
		||||
        uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
 | 
			
		||||
        if (l1_size > INT_MAX / sizeof(uint64_t)) {
 | 
			
		||||
            error_setg(errp, "Image too large");
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        s->l1_size = l1_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s->l1_table_offset = header.l1_table_offset;
 | 
			
		||||
    s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
 | 
			
		|||
    if (header.backing_file_offset != 0) {
 | 
			
		||||
        len = header.backing_file_size;
 | 
			
		||||
        if (len > 1023) {
 | 
			
		||||
            len = 1023;
 | 
			
		||||
            error_setg(errp, "Backing file name too long");
 | 
			
		||||
            ret = -EINVAL;
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
        ret = bdrv_pread(bs->file, header.backing_file_offset,
 | 
			
		||||
                   bs->backing_file, len);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
 | 
			
		|||
        } else if (h2_seq > h1_seq) {
 | 
			
		||||
            s->curr_header = 1;
 | 
			
		||||
        } else {
 | 
			
		||||
            goto fail;
 | 
			
		||||
            /* The Microsoft Disk2VHD tool will create 2 identical
 | 
			
		||||
             * headers, with identical sequence numbers.  If the headers are
 | 
			
		||||
             * identical, don't consider the file corrupt */
 | 
			
		||||
            if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
 | 
			
		||||
                s->curr_header = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                goto fail;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								blockdev.c
								
								
								
								
							
							
						
						
									
										43
									
								
								blockdev.c
								
								
								
								
							| 
						 | 
				
			
			@ -288,6 +288,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
 | 
			
		||||
                                    int max, int def, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    if (!buf) {
 | 
			
		||||
        return def;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < max; i++) {
 | 
			
		||||
        if (!strcmp(buf, lookup[i])) {
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error_setg(errp, "invalid parameter value: %s", buf);
 | 
			
		||||
    return def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    if (throttle_conflicting(cfg)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -324,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		|||
    QemuOpts *opts;
 | 
			
		||||
    const char *id;
 | 
			
		||||
    bool has_driver_specific_opts;
 | 
			
		||||
    BlockdevDetectZeroesOptions detect_zeroes;
 | 
			
		||||
    BlockDriver *drv = NULL;
 | 
			
		||||
 | 
			
		||||
    /* Check common options by copying from bs_opts to opts, all other options
 | 
			
		||||
| 
						 | 
				
			
			@ -452,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    detect_zeroes =
 | 
			
		||||
        parse_enum_option(BlockdevDetectZeroesOptions_lookup,
 | 
			
		||||
                          qemu_opt_get(opts, "detect-zeroes"),
 | 
			
		||||
                          BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
 | 
			
		||||
                          BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
 | 
			
		||||
                          &error);
 | 
			
		||||
    if (error) {
 | 
			
		||||
        error_propagate(errp, error);
 | 
			
		||||
        goto early_err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
 | 
			
		||||
        !(bdrv_flags & BDRV_O_UNMAP)) {
 | 
			
		||||
        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
 | 
			
		||||
                         "without setting discard operation to unmap");
 | 
			
		||||
        goto early_err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* init */
 | 
			
		||||
    dinfo = g_malloc0(sizeof(*dinfo));
 | 
			
		||||
    dinfo->id = g_strdup(qemu_opts_id(opts));
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
 | 
			
		|||
    }
 | 
			
		||||
    dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
 | 
			
		||||
    dinfo->bdrv->read_only = ro;
 | 
			
		||||
    dinfo->bdrv->detect_zeroes = detect_zeroes;
 | 
			
		||||
    dinfo->refcount = 1;
 | 
			
		||||
    if (serial != NULL) {
 | 
			
		||||
        dinfo->serial = g_strdup(serial);
 | 
			
		||||
| 
						 | 
				
			
			@ -2455,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
 | 
			
		|||
            .name = "copy-on-read",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
            .help = "copy read data from backing file into image file",
 | 
			
		||||
        },{
 | 
			
		||||
            .name = "detect-zeroes",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
            .help = "try to optimize zero writes (off, on, unmap)",
 | 
			
		||||
        },
 | 
			
		||||
        { /* end of list */ }
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								hmp.c
								
								
								
								
							
							
						
						
									
										5
									
								
								hmp.c
								
								
								
								
							| 
						 | 
				
			
			@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
 | 
			
		|||
                           info->value->inserted->backing_file_depth);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
 | 
			
		||||
            monitor_printf(mon, "    Detect zeroes:    %s\n",
 | 
			
		||||
                           BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (info->value->inserted->bps
 | 
			
		||||
            || info->value->inserted->bps_rd
 | 
			
		||||
            || info->value->inserted->bps_wr
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,6 +120,8 @@ typedef enum {
 | 
			
		|||
/* BDRV_BLOCK_DATA: data is read from bs->file or another file
 | 
			
		||||
 * BDRV_BLOCK_ZERO: sectors read as zero
 | 
			
		||||
 * BDRV_BLOCK_OFFSET_VALID: sector stored in bs->file as raw data
 | 
			
		||||
 * BDRV_BLOCK_ALLOCATED: the content of the block is determined by this
 | 
			
		||||
 *                       layer (as opposed to the backing file)
 | 
			
		||||
 * BDRV_BLOCK_RAW: used internally to indicate that the request
 | 
			
		||||
 *                 was answered by the raw driver and that one
 | 
			
		||||
 *                 should look in bs->file directly.
 | 
			
		||||
| 
						 | 
				
			
			@ -141,10 +143,11 @@ typedef enum {
 | 
			
		|||
 *  f    t        f       not allocated or unknown offset, read as zero
 | 
			
		||||
 *  f    f        f       not allocated or unknown offset, read from backing_hd
 | 
			
		||||
 */
 | 
			
		||||
#define BDRV_BLOCK_DATA         1
 | 
			
		||||
#define BDRV_BLOCK_ZERO         2
 | 
			
		||||
#define BDRV_BLOCK_OFFSET_VALID 4
 | 
			
		||||
#define BDRV_BLOCK_RAW          8
 | 
			
		||||
#define BDRV_BLOCK_DATA         0x01
 | 
			
		||||
#define BDRV_BLOCK_ZERO         0x02
 | 
			
		||||
#define BDRV_BLOCK_OFFSET_VALID 0x04
 | 
			
		||||
#define BDRV_BLOCK_RAW          0x08
 | 
			
		||||
#define BDRV_BLOCK_ALLOCATED    0x10
 | 
			
		||||
#define BDRV_BLOCK_OFFSET_MASK  BDRV_SECTOR_MASK
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -364,6 +364,7 @@ struct BlockDriverState {
 | 
			
		|||
    BlockJob *job;
 | 
			
		||||
 | 
			
		||||
    QDict *options;
 | 
			
		||||
    BlockdevDetectZeroesOptions detect_zeroes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int get_tmp_filename(char *filename, int size);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@
 | 
			
		|||
#include "qapi/qmp/qobject.h"
 | 
			
		||||
#include "qapi/qmp/qlist.h"
 | 
			
		||||
#include "qemu/queue.h"
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define QDICT_BUCKET_MAX 512
 | 
			
		||||
| 
						 | 
				
			
			@ -70,4 +71,6 @@ void qdict_flatten(QDict *qdict);
 | 
			
		|||
void qdict_extract_subqdict(QDict *src, QDict **dst, const char *start);
 | 
			
		||||
void qdict_array_split(QDict *src, QList **dst);
 | 
			
		||||
 | 
			
		||||
void qdict_join(QDict *dest, QDict *src, bool overwrite);
 | 
			
		||||
 | 
			
		||||
#endif /* QDICT_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -318,6 +318,7 @@ void qemu_iovec_concat(QEMUIOVector *dst,
 | 
			
		|||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
 | 
			
		||||
                           struct iovec *src_iov, unsigned int src_cnt,
 | 
			
		||||
                           size_t soffset, size_t sbytes);
 | 
			
		||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov);
 | 
			
		||||
void qemu_iovec_destroy(QEMUIOVector *qiov);
 | 
			
		||||
void qemu_iovec_reset(QEMUIOVector *qiov);
 | 
			
		||||
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -942,6 +942,8 @@
 | 
			
		|||
# @encryption_key_missing: true if the backing device is encrypted but an
 | 
			
		||||
#                          valid encryption key is missing
 | 
			
		||||
#
 | 
			
		||||
# @detect_zeroes: detect and optimize zero writes (Since 2.1)
 | 
			
		||||
#
 | 
			
		||||
# @bps: total throughput limit in bytes per second is specified
 | 
			
		||||
#
 | 
			
		||||
# @bps_rd: read throughput limit in bytes per second is specified
 | 
			
		||||
| 
						 | 
				
			
			@ -977,6 +979,7 @@
 | 
			
		|||
  'data': { 'file': 'str', '*node-name': 'str', 'ro': 'bool', 'drv': 'str',
 | 
			
		||||
            '*backing_file': 'str', 'backing_file_depth': 'int',
 | 
			
		||||
            'encrypted': 'bool', 'encryption_key_missing': 'bool',
 | 
			
		||||
            'detect_zeroes': 'BlockdevDetectZeroesOptions',
 | 
			
		||||
            'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
 | 
			
		||||
            'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
 | 
			
		||||
            'image': 'ImageInfo',
 | 
			
		||||
| 
						 | 
				
			
			@ -4254,6 +4257,22 @@
 | 
			
		|||
{ 'enum': 'BlockdevDiscardOptions',
 | 
			
		||||
  'data': [ 'ignore', 'unmap' ] }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @BlockdevDetectZeroesOptions
 | 
			
		||||
#
 | 
			
		||||
# Describes the operation mode for the automatic conversion of plain
 | 
			
		||||
# zero writes by the OS to driver specific optimized zero write commands.
 | 
			
		||||
#
 | 
			
		||||
# @off:      Disabled (default)
 | 
			
		||||
# @on:       Enabled
 | 
			
		||||
# @unmap:    Enabled and even try to unmap blocks if possible. This requires
 | 
			
		||||
#            also that @BlockdevDiscardOptions is set to unmap for this device.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.1
 | 
			
		||||
##
 | 
			
		||||
{ 'enum': 'BlockdevDetectZeroesOptions',
 | 
			
		||||
  'data': [ 'off', 'on', 'unmap' ] }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @BlockdevAioOptions
 | 
			
		||||
#
 | 
			
		||||
| 
						 | 
				
			
			@ -4306,20 +4325,22 @@
 | 
			
		|||
# Options that are available for all block devices, independent of the block
 | 
			
		||||
# driver.
 | 
			
		||||
#
 | 
			
		||||
# @driver:      block driver name
 | 
			
		||||
# @id:          #optional id by which the new block device can be referred to.
 | 
			
		||||
#               This is a required option on the top level of blockdev-add, and
 | 
			
		||||
#               currently not allowed on any other level.
 | 
			
		||||
# @node-name:   #optional the name of a block driver state node (Since 2.0)
 | 
			
		||||
# @discard:     #optional discard-related options (default: ignore)
 | 
			
		||||
# @cache:       #optional cache-related options
 | 
			
		||||
# @aio:         #optional AIO backend (default: threads)
 | 
			
		||||
# @rerror:      #optional how to handle read errors on the device
 | 
			
		||||
#               (default: report)
 | 
			
		||||
# @werror:      #optional how to handle write errors on the device
 | 
			
		||||
#               (default: enospc)
 | 
			
		||||
# @read-only:   #optional whether the block device should be read-only
 | 
			
		||||
#               (default: false)
 | 
			
		||||
# @driver:        block driver name
 | 
			
		||||
# @id:            #optional id by which the new block device can be referred to.
 | 
			
		||||
#                 This is a required option on the top level of blockdev-add, and
 | 
			
		||||
#                 currently not allowed on any other level.
 | 
			
		||||
# @node-name:     #optional the name of a block driver state node (Since 2.0)
 | 
			
		||||
# @discard:       #optional discard-related options (default: ignore)
 | 
			
		||||
# @cache:         #optional cache-related options
 | 
			
		||||
# @aio:           #optional AIO backend (default: threads)
 | 
			
		||||
# @rerror:        #optional how to handle read errors on the device
 | 
			
		||||
#                 (default: report)
 | 
			
		||||
# @werror:        #optional how to handle write errors on the device
 | 
			
		||||
#                 (default: enospc)
 | 
			
		||||
# @read-only:     #optional whether the block device should be read-only
 | 
			
		||||
#                 (default: false)
 | 
			
		||||
# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
 | 
			
		||||
#                 (default: off)
 | 
			
		||||
#
 | 
			
		||||
# Since: 1.7
 | 
			
		||||
##
 | 
			
		||||
| 
						 | 
				
			
			@ -4332,7 +4353,8 @@
 | 
			
		|||
            '*aio': 'BlockdevAioOptions',
 | 
			
		||||
            '*rerror': 'BlockdevOnError',
 | 
			
		||||
            '*werror': 'BlockdevOnError',
 | 
			
		||||
            '*read-only': 'bool' } }
 | 
			
		||||
            '*read-only': 'bool',
 | 
			
		||||
            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @BlockdevOptionsFile
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,11 +70,8 @@ static void add_format_to_seq(void *opaque, const char *fmt_name)
 | 
			
		|||
{
 | 
			
		||||
    GSequence *seq = opaque;
 | 
			
		||||
 | 
			
		||||
    if (!g_sequence_lookup(seq, (gpointer)fmt_name,
 | 
			
		||||
                           compare_data, NULL)) {
 | 
			
		||||
        g_sequence_insert_sorted(seq, (gpointer)fmt_name,
 | 
			
		||||
                                 compare_data, NULL);
 | 
			
		||||
    }
 | 
			
		||||
    g_sequence_insert_sorted(seq, (gpointer)fmt_name,
 | 
			
		||||
                             compare_data, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -414,6 +414,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
 | 
			
		|||
    "       [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
 | 
			
		||||
    "       [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
 | 
			
		||||
    "       [,readonly=on|off][,copy-on-read=on|off]\n"
 | 
			
		||||
    "       [,detect-zeroes=on|off|unmap]\n"
 | 
			
		||||
    "       [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
 | 
			
		||||
    "       [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
 | 
			
		||||
    "       [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -475,6 +476,11 @@ Open drive @option{file} as read-only. Guest write attempts will fail.
 | 
			
		|||
@item copy-on-read=@var{copy-on-read}
 | 
			
		||||
@var{copy-on-read} is "on" or "off" and enables whether to copy read backing
 | 
			
		||||
file sectors into the image file.
 | 
			
		||||
@item detect-zeroes=@var{detect-zeroes}
 | 
			
		||||
@var{detect-zeroes} is "off", "on" or "unmap" and enables the automatic
 | 
			
		||||
conversion of plain zero writes by the OS to driver specific optimized
 | 
			
		||||
zero write commands. You may even choose "unmap" if @var{discard} is set
 | 
			
		||||
to "unmap" to allow a zero write to be converted to an UNMAP operation.
 | 
			
		||||
@end table
 | 
			
		||||
 | 
			
		||||
By default, the @option{cache=writeback} mode is used. It will report data
 | 
			
		||||
| 
						 | 
				
			
			@ -2191,6 +2197,74 @@ qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img
 | 
			
		|||
@end example
 | 
			
		||||
 | 
			
		||||
See also @url{http://www.gluster.org}.
 | 
			
		||||
 | 
			
		||||
@item HTTP/HTTPS/FTP/FTPS/TFTP
 | 
			
		||||
QEMU supports read-only access to files accessed over http(s), ftp(s) and tftp.
 | 
			
		||||
 | 
			
		||||
Syntax using a single filename:
 | 
			
		||||
@example
 | 
			
		||||
<protocol>://[<username>[:<password>]@@]<host>/<path>
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
where:
 | 
			
		||||
@table @option
 | 
			
		||||
@item protocol
 | 
			
		||||
'http', 'https', 'ftp', 'ftps', or 'tftp'.
 | 
			
		||||
 | 
			
		||||
@item username
 | 
			
		||||
Optional username for authentication to the remote server.
 | 
			
		||||
 | 
			
		||||
@item password
 | 
			
		||||
Optional password for authentication to the remote server.
 | 
			
		||||
 | 
			
		||||
@item host
 | 
			
		||||
Address of the remote server.
 | 
			
		||||
 | 
			
		||||
@item path
 | 
			
		||||
Path on the remote server, including any query string.
 | 
			
		||||
@end table
 | 
			
		||||
 | 
			
		||||
The following options are also supported:
 | 
			
		||||
@table @option
 | 
			
		||||
@item url
 | 
			
		||||
The full URL when passing options to the driver explicitly.
 | 
			
		||||
 | 
			
		||||
@item readahead
 | 
			
		||||
The amount of data to read ahead with each range request to the remote server.
 | 
			
		||||
This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it
 | 
			
		||||
does not have a suffix, it will be assumed to be in bytes. The value must be a
 | 
			
		||||
multiple of 512 bytes. It defaults to 256k.
 | 
			
		||||
 | 
			
		||||
@item sslverify
 | 
			
		||||
Whether to verify the remote server's certificate when connecting over SSL. It
 | 
			
		||||
can have the value 'on' or 'off'. It defaults to 'on'.
 | 
			
		||||
@end table
 | 
			
		||||
 | 
			
		||||
Note that when passing options to qemu explicitly, @option{driver} is the value
 | 
			
		||||
of <protocol>.
 | 
			
		||||
 | 
			
		||||
Example: boot from a remote Fedora 20 live ISO image
 | 
			
		||||
@example
 | 
			
		||||
qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
 | 
			
		||||
 | 
			
		||||
qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
Example: boot from a remote Fedora 20 cloud image using a local overlay for
 | 
			
		||||
writes, copy-on-read, and a readahead of 64k
 | 
			
		||||
@example
 | 
			
		||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2
 | 
			
		||||
 | 
			
		||||
qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on
 | 
			
		||||
@end example
 | 
			
		||||
 | 
			
		||||
Example: boot from an image stored on a VMware vSphere server with a self-signed
 | 
			
		||||
certificate using a local overlay for writes and a readahead of 64k
 | 
			
		||||
@example
 | 
			
		||||
qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k"@}' /tmp/test.qcow2
 | 
			
		||||
 | 
			
		||||
qemu-system-x86_64 -drive file=/tmp/test.qcow2
 | 
			
		||||
@end example
 | 
			
		||||
ETEXI
 | 
			
		||||
 | 
			
		||||
STEXI
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2032,6 +2032,8 @@ Each json-object contain the following:
 | 
			
		|||
         - "iops_rd_max":  read I/O operations max (json-int)
 | 
			
		||||
         - "iops_wr_max":  write I/O operations max (json-int)
 | 
			
		||||
         - "iops_size": I/O size when limiting by iops (json-int)
 | 
			
		||||
         - "detect_zeroes": detect and optimize zero writing (json-string)
 | 
			
		||||
             - Possible values: "off", "on", "unmap"
 | 
			
		||||
         - "image": the detail of the image, it is a json-object containing
 | 
			
		||||
            the following:
 | 
			
		||||
             - "filename": image file name (json-string)
 | 
			
		||||
| 
						 | 
				
			
			@ -2108,6 +2110,7 @@ Example:
 | 
			
		|||
               "iops_rd_max": 0,
 | 
			
		||||
               "iops_wr_max": 0,
 | 
			
		||||
               "iops_size": 0,
 | 
			
		||||
               "detect_zeroes": "on",
 | 
			
		||||
               "image":{
 | 
			
		||||
                  "filename":"disks/test.qcow2",
 | 
			
		||||
                  "format":"qcow2",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -665,3 +665,35 @@ void qdict_array_split(QDict *src, QList **dst)
 | 
			
		|||
        qlist_append_obj(*dst, subqobj ?: QOBJECT(subqdict));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * qdict_join(): Absorb the src QDict into the dest QDict, that is, move all
 | 
			
		||||
 * elements from src to dest.
 | 
			
		||||
 *
 | 
			
		||||
 * If an element from src has a key already present in dest, it will not be
 | 
			
		||||
 * moved unless overwrite is true.
 | 
			
		||||
 *
 | 
			
		||||
 * If overwrite is true, the conflicting values in dest will be discarded and
 | 
			
		||||
 * replaced by the corresponding values from src.
 | 
			
		||||
 *
 | 
			
		||||
 * Therefore, with overwrite being true, the src QDict will always be empty when
 | 
			
		||||
 * this function returns. If overwrite is false, the src QDict will be empty
 | 
			
		||||
 * iff there were no conflicts.
 | 
			
		||||
 */
 | 
			
		||||
void qdict_join(QDict *dest, QDict *src, bool overwrite)
 | 
			
		||||
{
 | 
			
		||||
    const QDictEntry *entry, *next;
 | 
			
		||||
 | 
			
		||||
    entry = qdict_first(src);
 | 
			
		||||
    while (entry) {
 | 
			
		||||
        next = qdict_next(src, entry);
 | 
			
		||||
 | 
			
		||||
        if (overwrite || !qdict_haskey(dest, entry->key)) {
 | 
			
		||||
            qobject_incref(entry->value);
 | 
			
		||||
            qdict_put_obj(dest, entry->key, entry->value);
 | 
			
		||||
            qdict_del(src, entry->key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        entry = next;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
 | 
			
		|||
    QDECREF(test_dict);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qdict_join_test(void)
 | 
			
		||||
{
 | 
			
		||||
    QDict *dict1, *dict2;
 | 
			
		||||
    bool overwrite = false;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    dict1 = qdict_new();
 | 
			
		||||
    dict2 = qdict_new();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Test everything once without overwrite and once with */
 | 
			
		||||
    do
 | 
			
		||||
    {
 | 
			
		||||
        /* Test empty dicts */
 | 
			
		||||
        qdict_join(dict1, dict2, overwrite);
 | 
			
		||||
 | 
			
		||||
        g_assert(qdict_size(dict1) == 0);
 | 
			
		||||
        g_assert(qdict_size(dict2) == 0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /* First iteration: Test movement */
 | 
			
		||||
        /* Second iteration: Test empty source and non-empty destination */
 | 
			
		||||
        qdict_put(dict2, "foo", qint_from_int(42));
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < 2; i++) {
 | 
			
		||||
            qdict_join(dict1, dict2, overwrite);
 | 
			
		||||
 | 
			
		||||
            g_assert(qdict_size(dict1) == 1);
 | 
			
		||||
            g_assert(qdict_size(dict2) == 0);
 | 
			
		||||
 | 
			
		||||
            g_assert(qdict_get_int(dict1, "foo") == 42);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /* Test non-empty source and destination without conflict */
 | 
			
		||||
        qdict_put(dict2, "bar", qint_from_int(23));
 | 
			
		||||
 | 
			
		||||
        qdict_join(dict1, dict2, overwrite);
 | 
			
		||||
 | 
			
		||||
        g_assert(qdict_size(dict1) == 2);
 | 
			
		||||
        g_assert(qdict_size(dict2) == 0);
 | 
			
		||||
 | 
			
		||||
        g_assert(qdict_get_int(dict1, "foo") == 42);
 | 
			
		||||
        g_assert(qdict_get_int(dict1, "bar") == 23);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /* Test conflict */
 | 
			
		||||
        qdict_put(dict2, "foo", qint_from_int(84));
 | 
			
		||||
 | 
			
		||||
        qdict_join(dict1, dict2, overwrite);
 | 
			
		||||
 | 
			
		||||
        g_assert(qdict_size(dict1) == 2);
 | 
			
		||||
        g_assert(qdict_size(dict2) == !overwrite);
 | 
			
		||||
 | 
			
		||||
        g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
 | 
			
		||||
        g_assert(qdict_get_int(dict1, "bar") == 23);
 | 
			
		||||
 | 
			
		||||
        if (!overwrite) {
 | 
			
		||||
            g_assert(qdict_get_int(dict2, "foo") == 84);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /* Check the references */
 | 
			
		||||
        g_assert(qdict_get(dict1, "foo")->refcnt == 1);
 | 
			
		||||
        g_assert(qdict_get(dict1, "bar")->refcnt == 1);
 | 
			
		||||
 | 
			
		||||
        if (!overwrite) {
 | 
			
		||||
            g_assert(qdict_get(dict2, "foo")->refcnt == 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /* Clean up */
 | 
			
		||||
        qdict_del(dict1, "foo");
 | 
			
		||||
        qdict_del(dict1, "bar");
 | 
			
		||||
 | 
			
		||||
        if (!overwrite) {
 | 
			
		||||
            qdict_del(dict2, "foo");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while (overwrite ^= true);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    QDECREF(dict1);
 | 
			
		||||
    QDECREF(dict2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Errors test-cases
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -584,6 +670,7 @@ int main(int argc, char **argv)
 | 
			
		|||
    g_test_add_func("/public/iterapi", qdict_iterapi_test);
 | 
			
		||||
    g_test_add_func("/public/flatten", qdict_flatten_test);
 | 
			
		||||
    g_test_add_func("/public/array_split", qdict_array_split_test);
 | 
			
		||||
    g_test_add_func("/public/join", qdict_join_test);
 | 
			
		||||
 | 
			
		||||
    g_test_add_func("/errors/put_exists", qdict_put_exists_test);
 | 
			
		||||
    g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
 | 
			
		|||
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
 | 
			
		||||
        qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
 | 
			
		||||
        qemu_io('-c', 'write -P 0x1 0 512', backing_img)
 | 
			
		||||
        self.vm = iotests.VM().add_drive(test_img)
 | 
			
		||||
        self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
 | 
			
		||||
        self.vm.launch()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,11 @@ _supported_os Linux
 | 
			
		|||
_default_cache_mode "writethrough"
 | 
			
		||||
_supported_cache_modes "writethrough"
 | 
			
		||||
 | 
			
		||||
_no_dump_exec()
 | 
			
		||||
{
 | 
			
		||||
    (ulimit -c 0; exec "$@")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size=128M
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
| 
						 | 
				
			
			@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
 | 
			
		|||
IMGOPTS="compat=1.1,lazy_refcounts=on"
 | 
			
		||||
_make_test_img $size
 | 
			
		||||
 | 
			
		||||
old_ulimit=$(ulimit -c)
 | 
			
		||||
ulimit -c 0 # do not produce a core dump on abort(3)
 | 
			
		||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
 | 
			
		||||
ulimit -c "$old_ulimit"
 | 
			
		||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
# The dirty bit must be set
 | 
			
		||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
 | 
			
		||||
| 
						 | 
				
			
			@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
 | 
			
		|||
IMGOPTS="compat=1.1,lazy_refcounts=on"
 | 
			
		||||
_make_test_img $size
 | 
			
		||||
 | 
			
		||||
old_ulimit=$(ulimit -c)
 | 
			
		||||
ulimit -c 0 # do not produce a core dump on abort(3)
 | 
			
		||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
 | 
			
		||||
ulimit -c "$old_ulimit"
 | 
			
		||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
# The dirty bit must be set
 | 
			
		||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
 | 
			
		||||
| 
						 | 
				
			
			@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
 | 
			
		|||
IMGOPTS="compat=1.1,lazy_refcounts=off"
 | 
			
		||||
_make_test_img $size
 | 
			
		||||
 | 
			
		||||
old_ulimit=$(ulimit -c)
 | 
			
		||||
ulimit -c 0 # do not produce a core dump on abort(3)
 | 
			
		||||
$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
 | 
			
		||||
ulimit -c "$old_ulimit"
 | 
			
		||||
_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
# The dirty bit must not be set since lazy_refcounts=off
 | 
			
		||||
./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ No errors were found on the image.
 | 
			
		|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 | 
			
		||||
wrote 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
./039: Aborted                 ( ulimit -c 0; exec "$@" )
 | 
			
		||||
incompatible_features     0x1
 | 
			
		||||
ERROR cluster 5 refcount=0 reference=1
 | 
			
		||||
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
 | 
			
		|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 | 
			
		||||
wrote 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
./039: Aborted                 ( ulimit -c 0; exec "$@" )
 | 
			
		||||
incompatible_features     0x1
 | 
			
		||||
Repairing cluster 5 refcount=0 reference=1
 | 
			
		||||
wrote 512/512 bytes at offset 0
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +54,7 @@ incompatible_features     0x0
 | 
			
		|||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 | 
			
		||||
wrote 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
./039: Aborted                 ( ulimit -c 0; exec "$@" )
 | 
			
		||||
incompatible_features     0x0
 | 
			
		||||
No errors were found on the image.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 | 
			
		|||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
 | 
			
		||||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ QMP_VERSION
 | 
			
		|||
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
 | 
			
		||||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ Testing:
 | 
			
		|||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": "OK\r\n"}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
| 
						 | 
				
			
			@ -64,14 +64,14 @@ Testing:
 | 
			
		|||
QMP_VERSION
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "RESET"}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 | 
			
		||||
{"return": {}}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 | 
			
		||||
{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
 | 
			
		|||
$QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
 | 
			
		||||
                                                      | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
_cleanup_test_img
 | 
			
		||||
_use_sample_img test-disk2vhd.vhdx.bz2
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "=== Verify image created by Disk2VHD can be opened ==="
 | 
			
		||||
$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
 | 
			
		||||
 | 
			
		||||
# success, all done
 | 
			
		||||
echo "*** done"
 | 
			
		||||
rm -f $seq.full
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,4 +18,11 @@ No errors were found on the image.
 | 
			
		|||
=== Verify open image read-only succeeds after log replay ===
 | 
			
		||||
read 18874368/18874368 bytes at offset 0
 | 
			
		||||
18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
 | 
			
		||||
=== Verify image created by Disk2VHD can be opened ===
 | 
			
		||||
image: TEST_DIR/test-disk2vhd.vhdx
 | 
			
		||||
file format: vhdx
 | 
			
		||||
virtual size: 256M (268435456 bytes)
 | 
			
		||||
disk size: 260M
 | 
			
		||||
cluster_size: 2097152
 | 
			
		||||
*** done
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,130 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# Test case for support of JSON filenames
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2014 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# creator
 | 
			
		||||
owner=mreitz@redhat.com
 | 
			
		||||
 | 
			
		||||
seq="$(basename $0)"
 | 
			
		||||
echo "QA output created by $seq"
 | 
			
		||||
 | 
			
		||||
here="$PWD"
 | 
			
		||||
tmp=/tmp/$$
 | 
			
		||||
status=1	# failure is the default!
 | 
			
		||||
 | 
			
		||||
_cleanup()
 | 
			
		||||
{
 | 
			
		||||
	_cleanup_test_img
 | 
			
		||||
}
 | 
			
		||||
trap "_cleanup; exit \$status" 0 1 2 3 15
 | 
			
		||||
 | 
			
		||||
# get standard environment, filters and checks
 | 
			
		||||
. ./common.rc
 | 
			
		||||
. ./common.filter
 | 
			
		||||
 | 
			
		||||
_supported_fmt qcow2
 | 
			
		||||
_supported_proto file
 | 
			
		||||
_supported_os Linux
 | 
			
		||||
 | 
			
		||||
# Using an image filename containing quotation marks will render the JSON data
 | 
			
		||||
# below invalid. In that case, we have little choice but simply not to run this
 | 
			
		||||
# test.
 | 
			
		||||
case $TEST_IMG in
 | 
			
		||||
    *'"'*)
 | 
			
		||||
        _notrun "image filename may not contain quotation marks"
 | 
			
		||||
        ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
IMG_SIZE=64M
 | 
			
		||||
 | 
			
		||||
# Taken from test 072
 | 
			
		||||
echo
 | 
			
		||||
echo "=== Testing nested image formats ==="
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
 | 
			
		||||
 | 
			
		||||
$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
 | 
			
		||||
         -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
 | 
			
		||||
 | 
			
		||||
$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
 | 
			
		||||
         -c 'read -P 66 1024 512' "json:{
 | 
			
		||||
    \"driver\": \"$IMGFMT\",
 | 
			
		||||
    \"file\": {
 | 
			
		||||
        \"driver\": \"$IMGFMT\",
 | 
			
		||||
        \"file\": {
 | 
			
		||||
            \"filename\": \"$TEST_IMG\"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
# This should fail (see test 072)
 | 
			
		||||
$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Taken from test 071
 | 
			
		||||
echo
 | 
			
		||||
echo "=== Testing blkdebug ==="
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
_make_test_img $IMG_SIZE
 | 
			
		||||
 | 
			
		||||
$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
 | 
			
		||||
# the same (which they should).
 | 
			
		||||
$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
 | 
			
		||||
    \"driver\": \"$IMGFMT\",
 | 
			
		||||
    \"file\": {
 | 
			
		||||
        \"driver\": \"blkdebug\",
 | 
			
		||||
        \"inject-error\": [{
 | 
			
		||||
            \"event\": \"l2_load\"
 | 
			
		||||
        }],
 | 
			
		||||
        \"image.filename\": \"$TEST_IMG\"
 | 
			
		||||
    }
 | 
			
		||||
}" | _filter_qemu_io
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "=== Testing qemu-img info output ==="
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
$QEMU_IMG info "json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" \
 | 
			
		||||
    | _filter_testdir | _filter_imgfmt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "=== Testing option merging ==="
 | 
			
		||||
echo
 | 
			
		||||
 | 
			
		||||
# Both options given directly and those given in the filename should be used
 | 
			
		||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
 | 
			
		||||
         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
 | 
			
		||||
 | 
			
		||||
# Options given directly should be prioritized over those given in the filename
 | 
			
		||||
$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
 | 
			
		||||
         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# success, all done
 | 
			
		||||
echo "*** done"
 | 
			
		||||
rm -f $seq.full
 | 
			
		||||
status=0
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
QA output created by 089
 | 
			
		||||
 | 
			
		||||
=== Testing nested image formats ===
 | 
			
		||||
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 
 | 
			
		||||
wrote 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
wrote 512/512 bytes at offset 512
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
wrote 512/512 bytes at offset 1024
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
read 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
read 512/512 bytes at offset 512
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
read 512/512 bytes at offset 1024
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
Pattern verification failed at offset 0, 512 bytes
 | 
			
		||||
read 512/512 bytes at offset 0
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
 | 
			
		||||
=== Testing blkdebug ===
 | 
			
		||||
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 | 
			
		||||
wrote 512/512 bytes at offset 229376
 | 
			
		||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 | 
			
		||||
read failed: Input/output error
 | 
			
		||||
 | 
			
		||||
=== Testing qemu-img info output ===
 | 
			
		||||
 | 
			
		||||
image: TEST_DIR/t.IMGFMT
 | 
			
		||||
file format: IMGFMT
 | 
			
		||||
virtual size: 64M (67108864 bytes)
 | 
			
		||||
disk size: 324K
 | 
			
		||||
cluster_size: 65536
 | 
			
		||||
Format specific information:
 | 
			
		||||
    compat: 1.1
 | 
			
		||||
    lazy refcounts: false
 | 
			
		||||
 | 
			
		||||
=== Testing option merging ===
 | 
			
		||||
 | 
			
		||||
format name: IMGFMT
 | 
			
		||||
cluster size: 64 KiB
 | 
			
		||||
vm state offset: 512 MiB
 | 
			
		||||
Format specific information:
 | 
			
		||||
    compat: 1.1
 | 
			
		||||
    lazy refcounts: false
 | 
			
		||||
format name: IMGFMT
 | 
			
		||||
cluster size: 64 KiB
 | 
			
		||||
vm state offset: 512 MiB
 | 
			
		||||
Format specific information:
 | 
			
		||||
    compat: 1.1
 | 
			
		||||
    lazy refcounts: false
 | 
			
		||||
*** done
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
#
 | 
			
		||||
# qcow1 format input validation tests
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2014 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This program is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# creator
 | 
			
		||||
owner=kwolf@redhat.com
 | 
			
		||||
 | 
			
		||||
seq=`basename $0`
 | 
			
		||||
echo "QA output created by $seq"
 | 
			
		||||
 | 
			
		||||
here=`pwd`
 | 
			
		||||
tmp=/tmp/$$
 | 
			
		||||
status=1	# failure is the default!
 | 
			
		||||
 | 
			
		||||
_cleanup()
 | 
			
		||||
{
 | 
			
		||||
    rm -f $TEST_IMG.snap
 | 
			
		||||
    _cleanup_test_img
 | 
			
		||||
}
 | 
			
		||||
trap "_cleanup; exit \$status" 0 1 2 3 15
 | 
			
		||||
 | 
			
		||||
# get standard environment, filters and checks
 | 
			
		||||
. ./common.rc
 | 
			
		||||
. ./common.filter
 | 
			
		||||
 | 
			
		||||
_supported_fmt qcow
 | 
			
		||||
_supported_proto generic
 | 
			
		||||
_supported_os Linux
 | 
			
		||||
 | 
			
		||||
offset_backing_file_offset=8
 | 
			
		||||
offset_backing_file_size=16
 | 
			
		||||
offset_size=24
 | 
			
		||||
offset_cluster_bits=32
 | 
			
		||||
offset_l2_bits=33
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== Invalid cluster size =="
 | 
			
		||||
_make_test_img 64M
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== Invalid L2 table size =="
 | 
			
		||||
_make_test_img 64M
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== Invalid size =="
 | 
			
		||||
_make_test_img 64M
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
 | 
			
		||||
{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo "== Invalid backing file length =="
 | 
			
		||||
_make_test_img 64M
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
 | 
			
		||||
{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
 | 
			
		||||
 | 
			
		||||
# success, all done
 | 
			
		||||
echo "*** done"
 | 
			
		||||
rm -f $seq.full
 | 
			
		||||
status=0
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
QA output created by 092
 | 
			
		||||
 | 
			
		||||
== Invalid cluster size ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
 | 
			
		||||
== Invalid L2 table size ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
 | 
			
		||||
== Invalid size ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Image too large
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
 | 
			
		||||
== Invalid backing file length ==
 | 
			
		||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
 | 
			
		||||
no file open, try 'help open'
 | 
			
		||||
*** done
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +150,7 @@ _filter_win32()
 | 
			
		|||
_filter_qemu_io()
 | 
			
		||||
{
 | 
			
		||||
    _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
 | 
			
		||||
        -e "s/: line [0-9][0-9]*:  *[0-9][0-9]*\( Aborted\)/:\1/" \
 | 
			
		||||
        -e "s/qemu-io> //g"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,5 +95,7 @@
 | 
			
		|||
086 rw auto quick
 | 
			
		||||
087 rw auto
 | 
			
		||||
088 rw auto
 | 
			
		||||
089 rw auto quick
 | 
			
		||||
090 rw auto quick
 | 
			
		||||
091 rw auto
 | 
			
		||||
092 rw auto quick
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										21
									
								
								util/iov.c
								
								
								
								
							
							
						
						
									
										21
									
								
								util/iov.c
								
								
								
								
							| 
						 | 
				
			
			@ -335,6 +335,27 @@ void qemu_iovec_concat(QEMUIOVector *dst,
 | 
			
		|||
    qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check if the contents of the iovecs are all zero
 | 
			
		||||
 */
 | 
			
		||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    int i;
 | 
			
		||||
    for (i = 0; i < qiov->niov; i++) {
 | 
			
		||||
        size_t offs = QEMU_ALIGN_DOWN(qiov->iov[i].iov_len, 4 * sizeof(long));
 | 
			
		||||
        uint8_t *ptr = qiov->iov[i].iov_base;
 | 
			
		||||
        if (offs && !buffer_is_zero(qiov->iov[i].iov_base, offs)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        for (; offs < qiov->iov[i].iov_len; offs++) {
 | 
			
		||||
            if (ptr[offs]) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qemu_iovec_destroy(QEMUIOVector *qiov)
 | 
			
		||||
{
 | 
			
		||||
    assert(qiov->nalloc != -1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue