X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=block.c;h=382ea71f4b8c28550d4a798377fd1e6c4bae04ae;hb=8d07d6c46597a885eb38d99cc6fff399ce69cd21;hp=ba0d8760dbf6805bd65e3de003a70957aa72f9e2;hpb=34b5d2c68eb4082c288e70fb99c61af8f7b96fde;p=qemu.git diff --git a/block.c b/block.c index ba0d8760d..382ea71f4 100644 --- a/block.c +++ b/block.c @@ -394,18 +394,26 @@ typedef struct CreateCo { char *filename; QEMUOptionParameter *options; int ret; + Error *err; } CreateCo; static void coroutine_fn bdrv_create_co_entry(void *opaque) { + Error *local_err = NULL; + int ret; + CreateCo *cco = opaque; assert(cco->drv); - cco->ret = cco->drv->bdrv_create(cco->filename, cco->options, NULL); + ret = cco->drv->bdrv_create(cco->filename, cco->options, &local_err); + if (error_is_set(&local_err)) { + error_propagate(&cco->err, local_err); + } + cco->ret = ret; } int bdrv_create(BlockDriver *drv, const char* filename, - QEMUOptionParameter *options) + QEMUOptionParameter *options, Error **errp) { int ret; @@ -415,9 +423,11 @@ int bdrv_create(BlockDriver *drv, const char* filename, .filename = g_strdup(filename), .options = options, .ret = NOT_DONE, + .err = NULL, }; if (!drv->bdrv_create) { + error_setg(errp, "Driver '%s' does not support image creation", drv->format_name); ret = -ENOTSUP; goto out; } @@ -434,22 +444,37 @@ int bdrv_create(BlockDriver *drv, const char* filename, } ret = cco.ret; + if (ret < 0) { + if (error_is_set(&cco.err)) { + error_propagate(errp, cco.err); + } else { + error_setg_errno(errp, -ret, "Could not create image"); + } + } out: g_free(cco.filename); return ret; } -int bdrv_create_file(const char* filename, QEMUOptionParameter *options) +int bdrv_create_file(const char* filename, QEMUOptionParameter *options, + Error **errp) { BlockDriver *drv; + Error *local_err = NULL; + int ret; drv = bdrv_find_protocol(filename, true); if (drv == NULL) { + error_setg(errp, "Could not find protocol for file '%s'", filename); return -ENOENT; } - return bdrv_create(drv, filename, options); + ret = bdrv_create(drv, filename, options, &local_err); + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + } + return ret; } /* @@ -615,7 +640,7 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) if (length < 0) { return length; } - hint = length >> BDRV_SECTOR_BITS; + hint = DIV_ROUND_UP(length, BDRV_SECTOR_SIZE); } bs->total_sectors = hint; @@ -744,13 +769,22 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, bs->read_only = !(open_flags & BDRV_O_RDWR); if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { - error_setg(errp, "Driver '%s' is not whitelisted", drv->format_name); + error_setg(errp, + !bs->read_only && bdrv_is_whitelisted(drv, true) + ? "Driver '%s' can only be used for read-only devices" + : "Driver '%s' is not whitelisted", + drv->format_name); return -ENOTSUP; } assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */ - if (!bs->read_only && (flags & BDRV_O_COPY_ON_READ)) { - bdrv_enable_copy_on_read(bs); + if (flags & BDRV_O_COPY_ON_READ) { + if (!bs->read_only) { + bdrv_enable_copy_on_read(bs); + } else { + error_setg(errp, "Can't use copy-on-read on read-only device"); + return -EINVAL; + } } if (filename != NULL) { @@ -767,7 +801,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, /* Open the image, either directly or using a protocol */ if (drv->bdrv_file_open) { assert(file == NULL); - assert(drv->bdrv_parse_filename || filename != NULL); + assert(!drv->bdrv_needs_filename || filename != NULL); ret = drv->bdrv_file_open(bs, options, open_flags, &local_err); } else { if (file == NULL) { @@ -783,8 +817,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, if (ret < 0) { if (error_is_set(&local_err)) { error_propagate(errp, local_err); - } else if (filename) { - error_setg_errno(errp, -ret, "Could not open '%s'", filename); + } else if (bs->filename[0]) { + error_setg_errno(errp, -ret, "Could not open '%s'", bs->filename); } else { error_setg_errno(errp, -ret, "Could not open image"); } @@ -799,8 +833,8 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file, #ifndef _WIN32 if (bs->is_temporary) { - assert(filename != NULL); - unlink(filename); + assert(bs->filename[0] != '\0'); + unlink(bs->filename); } #endif return 0; @@ -856,7 +890,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, /* Find the right block driver */ drvname = qdict_get_try_str(options, "driver"); if (drvname) { - drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); + drv = bdrv_find_format(drvname); if (!drv) { error_setg(errp, "Unknown driver '%s'", drvname); } @@ -886,7 +920,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, goto fail; } qdict_del(options, "filename"); - } else if (!drv->bdrv_parse_filename && !filename) { + } else if (drv->bdrv_needs_filename && !filename) { error_setg(errp, "The '%s' block driver requires a file name", drv->format_name); ret = -EINVAL; @@ -953,18 +987,20 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { QDECREF(options); return 0; + } else { + bdrv_get_full_backing_filename(bs, backing_filename, + sizeof(backing_filename)); } bs->backing_hd = bdrv_new(""); - bdrv_get_full_backing_filename(bs, backing_filename, - sizeof(backing_filename)); if (bs->backing_format[0] != '\0') { back_drv = bdrv_find_format(bs->backing_format); } /* backing files always opened read-only */ - back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT); + back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | + BDRV_O_COPY_ON_READ); ret = bdrv_open(bs->backing_hd, *backing_filename ? backing_filename : NULL, options, @@ -973,31 +1009,16 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) bdrv_unref(bs->backing_hd); bs->backing_hd = NULL; bs->open_flags |= BDRV_O_NO_BACKING; - error_propagate(errp, local_err); + error_setg(errp, "Could not open backing file: %s", + error_get_pretty(local_err)); + error_free(local_err); return ret; } + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->backing_hd->file->filename); return 0; } -static void extract_subqdict(QDict *src, QDict **dst, const char *start) -{ - const QDictEntry *entry, *next; - const char *p; - - *dst = qdict_new(); - entry = qdict_first(src); - - while (entry != NULL) { - next = qdict_next(src, entry); - if (strstart(entry->key, start, &p)) { - qobject_incref(entry->value); - qdict_put_obj(*dst, p, entry->value); - qdict_del(src, entry->key); - } - entry = next; - } -} - /* * Opens a disk image (raw, qcow2, vmdk, ...) * @@ -1065,8 +1086,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, snprintf(backing_filename, sizeof(backing_filename), "%s", filename); } else if (!realpath(filename, backing_filename)) { - error_setg_errno(errp, errno, "Could not resolve path '%s'", filename); ret = -errno; + error_setg_errno(errp, errno, "Could not resolve path '%s'", filename); goto fail; } @@ -1082,11 +1103,14 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, drv->format_name); } - ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options); + ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err); free_option_parameters(create_options); if (ret < 0) { error_setg_errno(errp, -ret, "Could not create temporary overlay " - "'%s'", tmp_filename); + "'%s': %s", tmp_filename, + error_get_pretty(local_err)); + error_free(local_err); + local_err = NULL; goto fail; } @@ -1100,7 +1124,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, flags |= BDRV_O_ALLOW_RDWR; } - extract_subqdict(options, &file_options, "file."); + qdict_extract_subqdict(options, &file_options, "file."); ret = bdrv_file_open(&file, filename, file_options, bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err); @@ -1111,8 +1135,13 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, /* Find the right image format driver */ drvname = qdict_get_try_str(options, "driver"); if (drvname) { - drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR)); + drv = bdrv_find_format(drvname); qdict_del(options, "driver"); + if (!drv) { + error_setg(errp, "Invalid driver: '%s'", drvname); + ret = -EINVAL; + goto unlink_and_fail; + } } if (!drv) { @@ -1138,7 +1167,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options, if ((flags & BDRV_O_NO_BACKING) == 0) { QDict *backing_options; - extract_subqdict(options, &backing_options, "backing."); + qdict_extract_subqdict(options, &backing_options, "backing."); ret = bdrv_open_backing_file(bs, backing_options, &local_err); if (ret < 0) { goto close_and_fail; @@ -2641,7 +2670,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs, goto out; } - total_sectors = len >> BDRV_SECTOR_BITS; + total_sectors = DIV_ROUND_UP(len, BDRV_SECTOR_SIZE); max_nb_sectors = MAX(0, total_sectors - sector_num); if (max_nb_sectors > 0) { ret = drv->bdrv_co_readv(bs, sector_num, @@ -2847,9 +2876,10 @@ int64_t bdrv_getlength(BlockDriverState *bs) if (!drv) return -ENOMEDIUM; - if (bdrv_dev_has_removable_media(bs)) { - if (drv->bdrv_getlength) { - return drv->bdrv_getlength(bs); + if (drv->has_variable_length) { + int ret = refresh_total_sectors(bs, bs->total_sectors); + if (ret < 0) { + return ret; } } return bs->total_sectors * BDRV_SECTOR_SIZE; @@ -3131,13 +3161,20 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs, ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum); if (ret < 0) { + *pnum = 0; return ret; } + if (ret & BDRV_BLOCK_RAW) { + assert(ret & BDRV_BLOCK_OFFSET_VALID); + return bdrv_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS, + *pnum, pnum); + } + if (!(ret & BDRV_BLOCK_DATA)) { if (bdrv_has_zero_init(bs)) { ret |= BDRV_BLOCK_ZERO; - } else { + } else if (bs->backing_hd) { BlockDriverState *bs2 = bs->backing_hd; int64_t length2 = bdrv_getlength(bs2); if (length2 >= 0 && sector_num >= (length2 >> BDRV_SECTOR_BITS)) { @@ -3309,6 +3346,15 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return drv->bdrv_get_info(bs, bdi); } +ImageInfoSpecific *bdrv_get_specific_info(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + if (drv && drv->bdrv_get_specific_info) { + return drv->bdrv_get_specific_info(bs); + } + return NULL; +} + int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf, int64_t pos, int size) { @@ -4461,6 +4507,7 @@ void bdrv_img_create(const char *filename, const char *fmt, BlockDriverState *bs = NULL; BlockDriver *drv, *proto_drv; BlockDriver *backing_drv = NULL; + Error *local_err = NULL; int ret = 0; /* Find driver and parse its options */ @@ -4547,10 +4594,13 @@ void bdrv_img_create(const char *filename, const char *fmt, bs = bdrv_new(""); ret = bdrv_open(bs, backing_file->value.s, NULL, back_flags, - backing_drv, NULL); + backing_drv, &local_err); if (ret < 0) { - error_setg_errno(errp, -ret, "Could not open '%s'", - backing_file->value.s); + error_setg_errno(errp, -ret, "Could not open '%s': %s", + backing_file->value.s, + error_get_pretty(local_err)); + error_free(local_err); + local_err = NULL; goto out; } bdrv_get_geometry(bs, &size); @@ -4569,22 +4619,19 @@ void bdrv_img_create(const char *filename, const char *fmt, print_option_parameters(param); puts(""); } - ret = bdrv_create(drv, filename, param); - if (ret < 0) { - if (ret == -ENOTSUP) { - error_setg(errp,"Formatting or formatting option not supported for " - "file format '%s'", fmt); - } else if (ret == -EFBIG) { - const char *cluster_size_hint = ""; - if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) { - cluster_size_hint = " (try using a larger cluster size)"; - } - error_setg(errp, "The image size is too large for file format '%s'%s", - fmt, cluster_size_hint); - } else { - error_setg(errp, "%s: error while creating %s: %s", filename, fmt, - strerror(-ret)); + ret = bdrv_create(drv, filename, param, &local_err); + if (ret == -EFBIG) { + /* This is generally a better message than whatever the driver would + * deliver (especially because of the cluster_size_hint), since that + * is most probably not much different from "image too large". */ + const char *cluster_size_hint = ""; + if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) { + cluster_size_hint = " (try using a larger cluster size)"; } + error_setg(errp, "The image size is too large for file format '%s'" + "%s", fmt, cluster_size_hint); + error_free(local_err); + local_err = NULL; } out: @@ -4594,6 +4641,9 @@ out: if (bs) { bdrv_unref(bs); } + if (error_is_set(&local_err)) { + error_propagate(errp, local_err); + } } AioContext *bdrv_get_aio_context(BlockDriverState *bs) @@ -4615,3 +4665,22 @@ int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options) } return bs->drv->bdrv_amend_options(bs, options); } + +ExtSnapshotPerm bdrv_check_ext_snapshot(BlockDriverState *bs) +{ + if (bs->drv->bdrv_check_ext_snapshot) { + return bs->drv->bdrv_check_ext_snapshot(bs); + } + + if (bs->file && bs->file->drv && bs->file->drv->bdrv_check_ext_snapshot) { + return bs->file->drv->bdrv_check_ext_snapshot(bs); + } + + /* external snapshots are allowed by default */ + return EXT_SNAPSHOT_ALLOWED; +} + +ExtSnapshotPerm bdrv_check_ext_snapshot_forbidden(BlockDriverState *bs) +{ + return EXT_SNAPSHOT_FORBIDDEN; +}