Skip to content

Commit

Permalink
block: Error parameter for open functions
Browse files Browse the repository at this point in the history
Add an Error ** parameter to bdrv_open, bdrv_file_open and associated
functions to allow more specific error messages.

Signed-off-by: Max Reitz <[email protected]>
  • Loading branch information
XanClic authored and kevmw committed Sep 12, 2013
1 parent d5124c0 commit 34b5d2c
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 85 deletions.
100 changes: 64 additions & 36 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
}

static int find_image_format(BlockDriverState *bs, const char *filename,
BlockDriver **pdrv)
BlockDriver **pdrv, Error **errp)
{
int score, score_max;
BlockDriver *drv1, *drv;
Expand All @@ -563,6 +563,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
if (bs->sg || !bdrv_is_inserted(bs) || bdrv_getlength(bs) == 0) {
drv = bdrv_find_format("raw");
if (!drv) {
error_setg(errp, "Could not find raw image format");
ret = -ENOENT;
}
*pdrv = drv;
Expand All @@ -571,6 +572,8 @@ static int find_image_format(BlockDriverState *bs, const char *filename,

ret = bdrv_pread(bs, 0, buf, sizeof(buf));
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read image for determining its "
"format");
*pdrv = NULL;
return ret;
}
Expand All @@ -587,6 +590,8 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
}
}
if (!drv) {
error_setg(errp, "Could not determine image format: No compatible "
"driver found");
ret = -ENOENT;
}
*pdrv = drv;
Expand Down Expand Up @@ -706,10 +711,11 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
* Removes all processed options from *options.
*/
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
QDict *options, int flags, BlockDriver *drv)
QDict *options, int flags, BlockDriver *drv, Error **errp)
{
int ret, open_flags;
const char *filename;
Error *local_err = NULL;

assert(drv != NULL);
assert(bs->file == NULL);
Expand Down Expand Up @@ -738,6 +744,7 @@ 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);
return -ENOTSUP;
}

Expand All @@ -761,25 +768,32 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
if (drv->bdrv_file_open) {
assert(file == NULL);
assert(drv->bdrv_parse_filename || filename != NULL);
ret = drv->bdrv_file_open(bs, options, open_flags, NULL);
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
} else {
if (file == NULL) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't use '%s' as a "
"block driver for the protocol level",
drv->format_name);
error_setg(errp, "Can't use '%s' as a block driver for the "
"protocol level", drv->format_name);
ret = -EINVAL;
goto free_and_fail;
}
bs->file = file;
ret = drv->bdrv_open(bs, options, open_flags, NULL);
ret = drv->bdrv_open(bs, options, open_flags, &local_err);
}

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 {
error_setg_errno(errp, -ret, "Could not open image");
}
goto free_and_fail;
}

ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count");
goto free_and_fail;
}

Expand Down Expand Up @@ -808,12 +822,13 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
* dictionary, it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_file_open(BlockDriverState **pbs, const char *filename,
QDict *options, int flags)
QDict *options, int flags, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv;
const char *drvname;
bool allow_protocol_prefix = false;
Error *local_err = NULL;
int ret;

/* NULL means an empty set of options */
Expand All @@ -832,8 +847,8 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
qdict_put(options, "filename", qstring_from_str(filename));
allow_protocol_prefix = true;
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Can't specify 'file' and "
"'filename' options at the same time");
error_setg(errp, "Can't specify 'file' and 'filename' options at the "
"same time");
ret = -EINVAL;
goto fail;
}
Expand All @@ -842,53 +857,53 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
drv = bdrv_find_whitelisted_format(drvname, !(flags & BDRV_O_RDWR));
if (!drv) {
error_setg(errp, "Unknown driver '%s'", drvname);
}
qdict_del(options, "driver");
} else if (filename) {
drv = bdrv_find_protocol(filename, allow_protocol_prefix);
if (!drv) {
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Unknown protocol");
error_setg(errp, "Unknown protocol");
}
} else {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"Must specify either driver or file");
error_setg(errp, "Must specify either driver or file");
drv = NULL;
}

if (!drv) {
/* errp has been set already */
ret = -ENOENT;
goto fail;
}

/* Parse the filename and open it */
if (drv->bdrv_parse_filename && filename) {
Error *local_err = NULL;
drv->bdrv_parse_filename(filename, 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;
}
qdict_del(options, "filename");
} else if (!drv->bdrv_parse_filename && !filename) {
qerror_report(ERROR_CLASS_GENERIC_ERROR,
"The '%s' block driver requires a file name",
drv->format_name);
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
goto fail;
}

ret = bdrv_open_common(bs, NULL, options, flags, drv);
ret = bdrv_open_common(bs, NULL, options, flags, drv, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
goto fail;
}

/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block protocol '%s' doesn't "
"support the option '%s'",
drv->format_name, entry->key);
error_setg(errp, "Block protocol '%s' doesn't support the option '%s'",
drv->format_name, entry->key);
ret = -EINVAL;
goto fail;
}
Expand All @@ -915,11 +930,12 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
* function (even on failure), so if the caller intends to reuse the dictionary,
* it needs to use QINCREF() before calling bdrv_file_open.
*/
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
{
char backing_filename[PATH_MAX];
int back_flags, ret;
BlockDriver *back_drv = NULL;
Error *local_err = NULL;

if (bs->backing_hd != NULL) {
QDECREF(options);
Expand Down Expand Up @@ -952,11 +968,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options)

ret = bdrv_open(bs->backing_hd,
*backing_filename ? backing_filename : NULL, options,
back_flags, back_drv);
back_flags, back_drv, &local_err);
if (ret < 0) {
bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
bs->open_flags |= BDRV_O_NO_BACKING;
error_propagate(errp, local_err);
return ret;
}
return 0;
Expand Down Expand Up @@ -990,14 +1007,15 @@ static void extract_subqdict(QDict *src, QDict **dst, const char *start)
* dictionary, it needs to use QINCREF() before calling bdrv_open.
*/
int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
int flags, BlockDriver *drv)
int flags, BlockDriver *drv, Error **errp)
{
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char tmp_filename[PATH_MAX + 1];
BlockDriverState *file = NULL;
QDict *file_options = NULL;
const char *drvname;
Error *local_err = NULL;

/* NULL means an empty set of options */
if (options == NULL) {
Expand All @@ -1016,7 +1034,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
char backing_filename[PATH_MAX];

if (qdict_size(options) != 0) {
error_report("Can't use snapshot=on with driver-specific options");
error_setg(errp, "Can't use snapshot=on with driver-specific options");
ret = -EINVAL;
goto fail;
}
Expand All @@ -1027,7 +1045,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,

/* if there is a backing file, use it */
bs1 = bdrv_new("");
ret = bdrv_open(bs1, filename, NULL, 0, drv);
ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
if (ret < 0) {
bdrv_unref(bs1);
goto fail;
Expand All @@ -1038,6 +1056,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,

ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not get temporary filename");
goto fail;
}

Expand All @@ -1046,6 +1065,7 @@ 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;
goto fail;
}
Expand All @@ -1065,6 +1085,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options);
free_option_parameters(create_options);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not create temporary overlay "
"'%s'", tmp_filename);
goto fail;
}

Expand All @@ -1081,7 +1103,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
extract_subqdict(options, &file_options, "file.");

ret = bdrv_file_open(&file, filename, file_options,
bdrv_open_flags(bs, flags | BDRV_O_UNMAP));
bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err);
if (ret < 0) {
goto fail;
}
Expand All @@ -1094,15 +1116,15 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
}

if (!drv) {
ret = find_image_format(file, filename, &drv);
ret = find_image_format(file, filename, &drv, &local_err);
}

if (!drv) {
goto unlink_and_fail;
}

/* Open the image */
ret = bdrv_open_common(bs, file, options, flags, drv);
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
if (ret < 0) {
goto unlink_and_fail;
}
Expand All @@ -1117,7 +1139,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDict *backing_options;

extract_subqdict(options, &backing_options, "backing.");
ret = bdrv_open_backing_file(bs, backing_options);
ret = bdrv_open_backing_file(bs, backing_options, &local_err);
if (ret < 0) {
goto close_and_fail;
}
Expand All @@ -1126,9 +1148,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
/* Check if any unknown options were used */
if (qdict_size(options) != 0) {
const QDictEntry *entry = qdict_first(options);
qerror_report(ERROR_CLASS_GENERIC_ERROR, "Block format '%s' used by "
"device '%s' doesn't support the option '%s'",
drv->format_name, bs->device_name, entry->key);
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
"support the option '%s'", drv->format_name, bs->device_name,
entry->key);

ret = -EINVAL;
goto close_and_fail;
Expand All @@ -1152,11 +1174,17 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
QDECREF(bs->options);
QDECREF(options);
bs->options = NULL;
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
return ret;

close_and_fail:
bdrv_close(bs);
QDECREF(options);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
}
return ret;
}

Expand Down Expand Up @@ -4519,7 +4547,7 @@ 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);
backing_drv, NULL);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not open '%s'",
backing_file->value.s);
Expand Down
4 changes: 3 additions & 1 deletion block/blkdebug.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,10 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}

ret = bdrv_file_open(&bs->file, filename, NULL, flags);
ret = bdrv_file_open(&bs->file, filename, NULL, flags, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
goto fail;
}

Expand Down
8 changes: 6 additions & 2 deletions block/blkverify.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}

ret = bdrv_file_open(&bs->file, raw, NULL, flags);
ret = bdrv_file_open(&bs->file, raw, NULL, flags, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
goto fail;
}

Expand All @@ -154,8 +156,10 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
}

s->test_file = bdrv_new("");
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL);
ret = bdrv_open(s->test_file, filename, NULL, flags, NULL, &local_err);
if (ret < 0) {
qerror_report_err(local_err);
error_free(local_err);
bdrv_unref(s->test_file);
s->test_file = NULL;
goto fail;
Expand Down
Loading

0 comments on commit 34b5d2c

Please sign in to comment.