| From 9f0ec0582867ea7c45ac5b23bfcbd20e699a4bd4 Mon Sep 17 00:00:00 2001 |
| From: Max Reitz <mreitz@redhat.com> |
| Date: Mon, 4 Nov 2013 22:32:14 +0100 |
| Subject: [PATCH 21/87] qcow2: Use Error parameter |
| |
| RH-Author: Max Reitz <mreitz@redhat.com> |
| Message-id: <1383604354-12743-24-git-send-email-mreitz@redhat.com> |
| Patchwork-id: 55323 |
| O-Subject: [RHEL-7.0 qemu-kvm PATCH 23/43] qcow2: Use Error parameter |
| Bugzilla: 1026524 |
| RH-Acked-by: Kevin Wolf <kwolf@redhat.com> |
| RH-Acked-by: Laszlo Ersek <lersek@redhat.com> |
| RH-Acked-by: Fam Zheng <famz@redhat.com> |
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| |
| BZ: 1026524 |
| |
| Employ usage of the new Error ** parameter in qcow2_open, qcow2_create |
| and associated functions. |
| |
| Signed-off-by: Max Reitz <mreitz@redhat.com> |
| (cherry picked from commit 3ef6c40ad0b350e18c78135ffbdbe209cb479c1f) |
| |
| Signed-off-by: Max Reitz <mreitz@redhat.com> |
| |
| Conflicts: |
| block/qcow2.c |
| |
| Conflicts because 8ad1898c has not been backported ("qcow2: Change |
| default for new images to compat=1.1"). |
| |
| block/qcow2.c | 134 ++++++++++++++++++++++++++++++++++++++-------------------- |
| 1 file changed, 88 insertions(+), 46 deletions(-) |
| |
| Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com> |
| |
| block/qcow2.c | 134 +++++++++++++++++++++++++++++++++++++------------------- |
| 1 files changed, 88 insertions(+), 46 deletions(-) |
| |
| diff --git a/block/qcow2.c b/block/qcow2.c |
| index 027d210..880d2cf 100644 |
| |
| |
| @@ -79,7 +79,8 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) |
| * return 0 upon success, non-0 otherwise |
| */ |
| static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| - uint64_t end_offset, void **p_feature_table) |
| + uint64_t end_offset, void **p_feature_table, |
| + Error **errp) |
| { |
| BDRVQcowState *s = bs->opaque; |
| QCowExtension ext; |
| @@ -100,10 +101,10 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| printf("attempting to read extended header in offset %lu\n", offset); |
| #endif |
| |
| - if (bdrv_pread(bs->file, offset, &ext, sizeof(ext)) != sizeof(ext)) { |
| - fprintf(stderr, "qcow2_read_extension: ERROR: " |
| - "pread fail from offset %" PRIu64 "\n", |
| - offset); |
| + ret = bdrv_pread(bs->file, offset, &ext, sizeof(ext)); |
| + if (ret < 0) { |
| + error_setg_errno(errp, -ret, "qcow2_read_extension: ERROR: " |
| + "pread fail from offset %" PRIu64, offset); |
| return 1; |
| } |
| be32_to_cpus(&ext.magic); |
| @@ -113,7 +114,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| printf("ext.magic = 0x%x\n", ext.magic); |
| #endif |
| if (ext.len > end_offset - offset) { |
| - error_report("Header extension too large"); |
| + error_setg(errp, "Header extension too large"); |
| return -EINVAL; |
| } |
| |
| @@ -123,14 +124,16 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| |
| case QCOW2_EXT_MAGIC_BACKING_FORMAT: |
| if (ext.len >= sizeof(bs->backing_format)) { |
| - fprintf(stderr, "ERROR: ext_backing_format: len=%u too large" |
| - " (>=%zu)\n", |
| - ext.len, sizeof(bs->backing_format)); |
| + error_setg(errp, "ERROR: ext_backing_format: len=%u too large" |
| + " (>=%zu)", ext.len, sizeof(bs->backing_format)); |
| return 2; |
| } |
| - if (bdrv_pread(bs->file, offset , bs->backing_format, |
| - ext.len) != ext.len) |
| + ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len); |
| + if (ret < 0) { |
| + error_setg_errno(errp, -ret, "ERROR: ext_backing_format: " |
| + "Could not read format name"); |
| return 3; |
| + } |
| bs->backing_format[ext.len] = '\0'; |
| #ifdef DEBUG_EXT |
| printf("Qcow2: Got format extension %s\n", bs->backing_format); |
| @@ -142,6 +145,8 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature)); |
| ret = bdrv_pread(bs->file, offset , feature_table, ext.len); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "ERROR: ext_feature_table: " |
| + "Could not read table"); |
| return ret; |
| } |
| |
| @@ -161,6 +166,8 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, |
| |
| ret = bdrv_pread(bs->file, offset , uext->data, uext->len); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "ERROR: unknown extension: " |
| + "Could not read data"); |
| return ret; |
| } |
| } |
| @@ -184,8 +191,8 @@ static void cleanup_unknown_header_ext(BlockDriverState *bs) |
| } |
| } |
| |
| -static void GCC_FMT_ATTR(2, 3) report_unsupported(BlockDriverState *bs, |
| - const char *fmt, ...) |
| +static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs, |
| + Error **errp, const char *fmt, ...) |
| { |
| char msg[64]; |
| va_list ap; |
| @@ -194,17 +201,17 @@ static void GCC_FMT_ATTR(2, 3) report_unsupported(BlockDriverState *bs, |
| vsnprintf(msg, sizeof(msg), fmt, ap); |
| va_end(ap); |
| |
| - qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, |
| - bs->device_name, "qcow2", msg); |
| + error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bs->device_name, "qcow2", |
| + msg); |
| } |
| |
| static void report_unsupported_feature(BlockDriverState *bs, |
| - Qcow2Feature *table, uint64_t mask) |
| + Error **errp, Qcow2Feature *table, uint64_t mask) |
| { |
| while (table && table->name[0] != '\0') { |
| if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) { |
| if (mask & (1 << table->bit)) { |
| - report_unsupported(bs, "%.46s",table->name); |
| + report_unsupported(bs, errp, "%.46s", table->name); |
| mask &= ~(1 << table->bit); |
| } |
| } |
| @@ -212,7 +219,8 @@ static void report_unsupported_feature(BlockDriverState *bs, |
| } |
| |
| if (mask) { |
| - report_unsupported(bs, "Unknown incompatible feature: %" PRIx64, mask); |
| + report_unsupported(bs, errp, "Unknown incompatible feature: %" PRIx64, |
| + mask); |
| } |
| } |
| |
| @@ -363,6 +371,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| ret = bdrv_pread(bs->file, 0, &header, sizeof(header)); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not read qcow2 header"); |
| goto fail; |
| } |
| be32_to_cpus(&header.magic); |
| @@ -380,11 +389,12 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| be32_to_cpus(&header.nb_snapshots); |
| |
| if (header.magic != QCOW_MAGIC) { |
| + error_setg(errp, "Image is not in qcow2 format"); |
| ret = -EMEDIUMTYPE; |
| goto fail; |
| } |
| if (header.version < 2 || header.version > 3) { |
| - report_unsupported(bs, "QCOW version %d", header.version); |
| + report_unsupported(bs, errp, "QCOW version %d", header.version); |
| ret = -ENOTSUP; |
| goto fail; |
| } |
| @@ -412,6 +422,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields, |
| s->unknown_header_fields_size); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not read unknown qcow2 header " |
| + "fields"); |
| goto fail; |
| } |
| } |
| @@ -430,8 +442,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| if (s->incompatible_features & ~QCOW2_INCOMPAT_MASK) { |
| void *feature_table = NULL; |
| qcow2_read_extensions(bs, header.header_length, ext_end, |
| - &feature_table); |
| - report_unsupported_feature(bs, feature_table, |
| + &feature_table, NULL); |
| + report_unsupported_feature(bs, errp, feature_table, |
| s->incompatible_features & |
| ~QCOW2_INCOMPAT_MASK); |
| ret = -ENOTSUP; |
| @@ -442,8 +454,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| /* Corrupt images may not be written to unless they are being repaired |
| */ |
| if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) { |
| - error_report("qcow2: Image is corrupt; cannot be opened " |
| - "read/write."); |
| + error_setg(errp, "qcow2: Image is corrupt; cannot be opened " |
| + "read/write"); |
| ret = -EACCES; |
| goto fail; |
| } |
| @@ -451,7 +463,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| /* Check support for various header values */ |
| if (header.refcount_order != 4) { |
| - report_unsupported(bs, "%d bit reference counts", |
| + report_unsupported(bs, errp, "%d bit reference counts", |
| 1 << header.refcount_order); |
| ret = -ENOTSUP; |
| goto fail; |
| @@ -459,10 +471,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| if (header.cluster_bits < MIN_CLUSTER_BITS || |
| header.cluster_bits > MAX_CLUSTER_BITS) { |
| + error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits); |
| ret = -EINVAL; |
| goto fail; |
| } |
| if (header.crypt_method > QCOW_CRYPT_AES) { |
| + error_setg(errp, "Unsupported encryption method: %i", |
| + header.crypt_method); |
| ret = -EINVAL; |
| goto fail; |
| } |
| @@ -491,6 +506,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| l1_vm_state_index = size_to_l1(s, header.size); |
| if (l1_vm_state_index > INT_MAX) { |
| + error_setg(errp, "Image is too big"); |
| ret = -EFBIG; |
| goto fail; |
| } |
| @@ -499,6 +515,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| /* the L1 table must contain at least enough entries to put |
| header.size bytes */ |
| if (s->l1_size < s->l1_vm_state_index) { |
| + error_setg(errp, "L1 table is too small"); |
| ret = -EINVAL; |
| goto fail; |
| } |
| @@ -509,6 +526,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, |
| s->l1_size * sizeof(uint64_t)); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not read L1 table"); |
| goto fail; |
| } |
| for(i = 0;i < s->l1_size; i++) { |
| @@ -529,6 +547,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| ret = qcow2_refcount_init(bs); |
| if (ret != 0) { |
| + error_setg_errno(errp, -ret, "Could not initialize refcount handling"); |
| goto fail; |
| } |
| |
| @@ -536,7 +555,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| QTAILQ_INIT(&s->discards); |
| |
| /* read qcow2 extensions */ |
| - if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) { |
| + if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL, |
| + &local_err)) { |
| + error_propagate(errp, local_err); |
| ret = -EINVAL; |
| goto fail; |
| } |
| @@ -550,6 +571,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| ret = bdrv_pread(bs->file, header.backing_file_offset, |
| bs->backing_file, len); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not read backing file name"); |
| goto fail; |
| } |
| bs->backing_file[len] = '\0'; |
| @@ -557,6 +579,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| ret = qcow2_read_snapshots(bs); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not read snapshots"); |
| goto fail; |
| } |
| |
| @@ -565,6 +588,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| s->autoclear_features = 0; |
| ret = qcow2_update_header(bs); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not update qcow2 header"); |
| goto fail; |
| } |
| } |
| @@ -579,6 +603,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| |
| ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not repair dirty image"); |
| goto fail; |
| } |
| } |
| @@ -587,8 +612,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| opts = qemu_opts_create_nofail(&qcow2_runtime_opts); |
| qemu_opts_absorb_qdict(opts, options, &local_err); |
| if (error_is_set(&local_err)) { |
| - qerror_report_err(local_err); |
| - error_free(local_err); |
| + error_propagate(errp, local_err); |
| ret = -EINVAL; |
| goto fail; |
| } |
| @@ -609,8 +633,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, |
| qemu_opts_del(opts); |
| |
| if (s->use_lazy_refcounts && s->qcow_version < 3) { |
| - qerror_report(ERROR_CLASS_GENERIC_ERROR, "Lazy refcounts require " |
| - "a qcow2 image with at least qemu 1.1 compatibility level"); |
| + error_setg(errp, "Lazy refcounts require a qcow2 image with at least " |
| + "qemu 1.1 compatibility level"); |
| ret = -EINVAL; |
| goto fail; |
| } |
| @@ -1333,7 +1357,8 @@ static int preallocate(BlockDriverState *bs) |
| static int qcow2_create2(const char *filename, int64_t total_size, |
| const char *backing_file, const char *backing_format, |
| int flags, size_t cluster_size, int prealloc, |
| - QEMUOptionParameter *options, int version) |
| + QEMUOptionParameter *options, int version, |
| + Error **errp) |
| { |
| /* Calculate cluster_bits */ |
| int cluster_bits; |
| @@ -1341,9 +1366,8 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS || |
| (1 << cluster_bits) != cluster_size) |
| { |
| - error_report( |
| - "Cluster size must be a power of two between %d and %dk", |
| - 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); |
| + error_setg(errp, "Cluster size must be a power of two between %d and " |
| + "%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); |
| return -EINVAL; |
| } |
| |
| @@ -1362,15 +1386,18 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| BlockDriverState* bs; |
| QCowHeader header; |
| uint8_t* refcount_table; |
| + Error *local_err = NULL; |
| int ret; |
| |
| - ret = bdrv_create_file(filename, options, NULL); |
| + ret = bdrv_create_file(filename, options, &local_err); |
| if (ret < 0) { |
| + error_propagate(errp, local_err); |
| return ret; |
| } |
| |
| - ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, NULL); |
| + ret = bdrv_file_open(&bs, filename, NULL, BDRV_O_RDWR, &local_err); |
| if (ret < 0) { |
| + error_propagate(errp, local_err); |
| return ret; |
| } |
| |
| @@ -1400,6 +1427,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| |
| ret = bdrv_pwrite(bs, 0, &header, sizeof(header)); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not write qcow2 header"); |
| goto out; |
| } |
| |
| @@ -1409,6 +1437,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| g_free(refcount_table); |
| |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not write refcount table"); |
| goto out; |
| } |
| |
| @@ -1422,13 +1451,16 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| BlockDriver* drv = bdrv_find_format("qcow2"); |
| assert(drv != NULL); |
| ret = bdrv_open(bs, filename, NULL, |
| - BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, NULL); |
| + BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, drv, &local_err); |
| if (ret < 0) { |
| + error_propagate(errp, local_err); |
| goto out; |
| } |
| |
| ret = qcow2_alloc_clusters(bs, 2 * cluster_size); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 " |
| + "header and refcount table"); |
| goto out; |
| |
| } else if (ret != 0) { |
| @@ -1439,6 +1471,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| /* Okay, now that we have a valid image, let's give it the right size */ |
| ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not resize image"); |
| goto out; |
| } |
| |
| @@ -1446,6 +1479,8 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| if (backing_file) { |
| ret = bdrv_change_backing_file(bs, backing_file, backing_format); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not assign backing file '%s' " |
| + "with format '%s'", backing_file, backing_format); |
| goto out; |
| } |
| } |
| @@ -1457,6 +1492,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, |
| ret = preallocate(bs); |
| qemu_co_mutex_unlock(&s->lock); |
| if (ret < 0) { |
| + error_setg_errno(errp, -ret, "Could not preallocate metadata"); |
| goto out; |
| } |
| } |
| @@ -1477,6 +1513,8 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, |
| size_t cluster_size = DEFAULT_CLUSTER_SIZE; |
| int prealloc = 0; |
| int version = 2; |
| + Error *local_err = NULL; |
| + int ret; |
| |
| /* Read out options */ |
| while (options && options->name) { |
| @@ -1498,8 +1536,8 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, |
| } else if (!strcmp(options->value.s, "metadata")) { |
| prealloc = 1; |
| } else { |
| - fprintf(stderr, "Invalid preallocation mode: '%s'\n", |
| - options->value.s); |
| + error_setg(errp, "Invalid preallocation mode: '%s'", |
| + options->value.s); |
| return -EINVAL; |
| } |
| } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) { |
| @@ -1508,8 +1546,8 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, |
| } else if (!strcmp(options->value.s, "1.1")) { |
| version = 3; |
| } else { |
| - fprintf(stderr, "Invalid compatibility level: '%s'\n", |
| - options->value.s); |
| + error_setg(errp, "Invalid compatibility level: '%s'", |
| + options->value.s); |
| return -EINVAL; |
| } |
| } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) { |
| @@ -1519,19 +1557,23 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, |
| } |
| |
| if (backing_file && prealloc) { |
| - fprintf(stderr, "Backing file and preallocation cannot be used at " |
| - "the same time\n"); |
| + error_setg(errp, "Backing file and preallocation cannot be used at " |
| + "the same time"); |
| return -EINVAL; |
| } |
| |
| if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) { |
| - fprintf(stderr, "Lazy refcounts only supported with compatibility " |
| - "level 1.1 and above (use compat=1.1 or greater)\n"); |
| + error_setg(errp, "Lazy refcounts only supported with compatibility " |
| + "level 1.1 and above (use compat=1.1 or greater)"); |
| return -EINVAL; |
| } |
| |
| - return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags, |
| - cluster_size, prealloc, options, version); |
| + ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags, |
| + cluster_size, prealloc, options, version, &local_err); |
| + if (error_is_set(&local_err)) { |
| + error_propagate(errp, local_err); |
| + } |
| + return ret; |
| } |
| |
| static int qcow2_make_empty(BlockDriverState *bs) |
| -- |
| 1.7.1 |
| |