summaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
Diffstat (limited to 'block.c')
-rw-r--r--block.c219
1 files changed, 141 insertions, 78 deletions
diff --git a/block.c b/block.c
index c05875fe39..0668c4be17 100644
--- a/block.c
+++ b/block.c
@@ -518,22 +518,16 @@ BlockDriver *bdrv_find_protocol(const char *filename)
return NULL;
}
-static int find_image_format(const char *filename, BlockDriver **pdrv)
+static int find_image_format(BlockDriverState *bs, const char *filename,
+ BlockDriver **pdrv)
{
- int ret, score, score_max;
+ int score, score_max;
BlockDriver *drv1, *drv;
uint8_t buf[2048];
- BlockDriverState *bs;
-
- ret = bdrv_file_open(&bs, filename, 0);
- if (ret < 0) {
- *pdrv = NULL;
- return ret;
- }
+ int ret = 0;
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
if (bs->sg || !bdrv_is_inserted(bs)) {
- bdrv_delete(bs);
drv = bdrv_find_format("raw");
if (!drv) {
ret = -ENOENT;
@@ -543,7 +537,6 @@ static int find_image_format(const char *filename, BlockDriver **pdrv)
}
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
- bdrv_delete(bs);
if (ret < 0) {
*pdrv = NULL;
return ret;
@@ -634,10 +627,31 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
bs->copy_on_read--;
}
+static int bdrv_open_flags(BlockDriverState *bs, int flags)
+{
+ int open_flags = flags | BDRV_O_CACHE_WB;
+
+ /*
+ * Clear flags that are internal to the block layer before opening the
+ * image.
+ */
+ open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
+
+ /*
+ * Snapshots should be writable.
+ */
+ if (bs->is_temporary) {
+ open_flags |= BDRV_O_RDWR;
+ }
+
+ return open_flags;
+}
+
/*
* Common part for opening disk images and files
*/
-static int bdrv_open_common(BlockDriverState *bs, const char *filename,
+static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
+ const char *filename,
int flags, BlockDriver *drv)
{
int ret, open_flags;
@@ -665,31 +679,22 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs->opaque = g_malloc0(drv->instance_size);
bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
- open_flags = flags | BDRV_O_CACHE_WB;
-
- /*
- * Clear flags that are internal to the block layer before opening the
- * image.
- */
- open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
-
- /*
- * Snapshots should be writable.
- */
- if (bs->is_temporary) {
- open_flags |= BDRV_O_RDWR;
- }
+ open_flags = bdrv_open_flags(bs, flags);
bs->read_only = !(open_flags & BDRV_O_RDWR);
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
- ret = drv->bdrv_file_open(bs, filename, open_flags);
- } else {
- ret = bdrv_file_open(&bs->file, filename, open_flags);
- if (ret >= 0) {
- ret = drv->bdrv_open(bs, open_flags);
+ if (file != NULL) {
+ bdrv_swap(file, bs);
+ ret = 0;
+ } else {
+ ret = drv->bdrv_file_open(bs, filename, open_flags);
}
+ } else {
+ assert(file != NULL);
+ bs->file = file;
+ ret = drv->bdrv_open(bs, open_flags);
}
if (ret < 0) {
@@ -709,10 +714,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
return 0;
free_and_fail:
- if (bs->file) {
- bdrv_delete(bs->file);
- bs->file = NULL;
- }
+ bs->file = NULL;
g_free(bs->opaque);
bs->opaque = NULL;
bs->drv = NULL;
@@ -734,7 +736,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
}
bs = bdrv_new("");
- ret = bdrv_open_common(bs, filename, flags, drv);
+ ret = bdrv_open_common(bs, NULL, filename, flags, drv);
if (ret < 0) {
bdrv_delete(bs);
return ret;
@@ -789,6 +791,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
int ret;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char tmp_filename[PATH_MAX + 1];
+ BlockDriverState *file = NULL;
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
@@ -848,25 +851,36 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
bs->is_temporary = 1;
}
+ /* Open image file without format layer */
+ if (flags & BDRV_O_RDWR) {
+ flags |= BDRV_O_ALLOW_RDWR;
+ }
+
+ ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags));
+ if (ret < 0) {
+ return ret;
+ }
+
/* Find the right image format driver */
if (!drv) {
- ret = find_image_format(filename, &drv);
+ ret = find_image_format(file, filename, &drv);
}
if (!drv) {
goto unlink_and_fail;
}
- if (flags & BDRV_O_RDWR) {
- flags |= BDRV_O_ALLOW_RDWR;
- }
-
/* Open the image */
- ret = bdrv_open_common(bs, filename, flags, drv);
+ ret = bdrv_open_common(bs, file, filename, flags, drv);
if (ret < 0) {
goto unlink_and_fail;
}
+ if (bs->file != file) {
+ bdrv_delete(file);
+ file = NULL;
+ }
+
/* If there is a backing file, use it */
if ((flags & BDRV_O_NO_BACKING) == 0) {
ret = bdrv_open_backing_file(bs);
@@ -888,6 +902,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
return 0;
unlink_and_fail:
+ if (file != NULL) {
+ bdrv_delete(file);
+ }
if (bs->is_temporary) {
unlink(filename);
}
@@ -3028,7 +3045,46 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
}
drv->bdrv_debug_event(bs, event);
+}
+
+int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
+ const char *tag)
+{
+ while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
+ bs = bs->file;
+ }
+
+ if (bs && bs->drv && bs->drv->bdrv_debug_breakpoint) {
+ return bs->drv->bdrv_debug_breakpoint(bs, event, tag);
+ }
+ return -ENOTSUP;
+}
+
+int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
+{
+ while (bs && bs->drv && !bs->drv->bdrv_debug_resume) {
+ bs = bs->file;
+ }
+
+ if (bs && bs->drv && bs->drv->bdrv_debug_resume) {
+ return bs->drv->bdrv_debug_resume(bs, tag);
+ }
+
+ return -ENOTSUP;
+}
+
+bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
+{
+ while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
+ bs = bs->file;
+ }
+
+ if (bs && bs->drv && bs->drv->bdrv_debug_is_suspended) {
+ return bs->drv->bdrv_debug_is_suspended(bs, tag);
+ }
+
+ return false;
}
/**************************************************************/
@@ -3778,12 +3834,20 @@ typedef struct BlockDriverAIOCBCoroutine {
BlockDriverAIOCB common;
BlockRequest req;
bool is_write;
+ bool *done;
QEMUBH* bh;
} BlockDriverAIOCBCoroutine;
static void bdrv_aio_co_cancel_em(BlockDriverAIOCB *blockacb)
{
- qemu_aio_flush();
+ BlockDriverAIOCBCoroutine *acb =
+ container_of(blockacb, BlockDriverAIOCBCoroutine, common);
+ bool done = false;
+
+ acb->done = &done;
+ while (!done) {
+ qemu_aio_wait();
+ }
}
static const AIOCBInfo bdrv_em_co_aiocb_info = {
@@ -3796,6 +3860,11 @@ static void bdrv_co_em_bh(void *opaque)
BlockDriverAIOCBCoroutine *acb = opaque;
acb->common.cb(acb->common.opaque, acb->req.error);
+
+ if (acb->done) {
+ *acb->done = true;
+ }
+
qemu_bh_delete(acb->bh);
qemu_aio_release(acb);
}
@@ -3834,6 +3903,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
acb->req.nb_sectors = nb_sectors;
acb->req.qiov = qiov;
acb->is_write = is_write;
+ acb->done = NULL;
co = qemu_coroutine_create(bdrv_co_do_rw);
qemu_coroutine_enter(co, acb);
@@ -3860,6 +3930,8 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockDriverAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
+ acb->done = NULL;
+
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
qemu_coroutine_enter(co, acb);
@@ -3888,6 +3960,7 @@ BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
+ acb->done = NULL;
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
qemu_coroutine_enter(co, acb);
@@ -4408,9 +4481,9 @@ bdrv_acct_done(BlockDriverState *bs, BlockAcctCookie *cookie)
bs->total_time_ns[cookie->type] += get_clock() - cookie->start_time_ns;
}
-int bdrv_img_create(const char *filename, const char *fmt,
- const char *base_filename, const char *base_fmt,
- char *options, uint64_t img_size, int flags)
+void bdrv_img_create(const char *filename, const char *fmt,
+ const char *base_filename, const char *base_fmt,
+ char *options, uint64_t img_size, int flags, Error **errp)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt, *backing_file, *size;
@@ -4422,16 +4495,14 @@ int bdrv_img_create(const char *filename, const char *fmt,
/* Find driver and parse its options */
drv = bdrv_find_format(fmt);
if (!drv) {
- error_report("Unknown file format '%s'", fmt);
- ret = -EINVAL;
- goto out;
+ error_setg(errp, "Unknown file format '%s'", fmt);
+ return;
}
proto_drv = bdrv_find_protocol(filename);
if (!proto_drv) {
- error_report("Unknown protocol '%s'", filename);
- ret = -EINVAL;
- goto out;
+ error_setg(errp, "Unknown protocol '%s'", filename);
+ return;
}
create_options = append_option_parameters(create_options,
@@ -4448,8 +4519,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
if (options) {
param = parse_option_parameters(options, create_options, param);
if (param == NULL) {
- error_report("Invalid options for file format '%s'.", fmt);
- ret = -EINVAL;
+ error_setg(errp, "Invalid options for file format '%s'.", fmt);
goto out;
}
}
@@ -4457,18 +4527,16 @@ int bdrv_img_create(const char *filename, const char *fmt,
if (base_filename) {
if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
base_filename)) {
- error_report("Backing file not supported for file format '%s'",
- fmt);
- ret = -EINVAL;
+ error_setg(errp, "Backing file not supported for file format '%s'",
+ fmt);
goto out;
}
}
if (base_fmt) {
if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
- error_report("Backing file format not supported for file "
- "format '%s'", fmt);
- ret = -EINVAL;
+ error_setg(errp, "Backing file format not supported for file "
+ "format '%s'", fmt);
goto out;
}
}
@@ -4476,9 +4544,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
if (backing_file && backing_file->value.s) {
if (!strcmp(filename, backing_file->value.s)) {
- error_report("Error: Trying to create an image with the "
- "same filename as the backing file");
- ret = -EINVAL;
+ error_setg(errp, "Error: Trying to create an image with the "
+ "same filename as the backing file");
goto out;
}
}
@@ -4487,9 +4554,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
if (backing_fmt && backing_fmt->value.s) {
backing_drv = bdrv_find_format(backing_fmt->value.s);
if (!backing_drv) {
- error_report("Unknown backing file format '%s'",
- backing_fmt->value.s);
- ret = -EINVAL;
+ error_setg(errp, "Unknown backing file format '%s'",
+ backing_fmt->value.s);
goto out;
}
}
@@ -4511,7 +4577,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv);
if (ret < 0) {
- error_report("Could not open '%s'", backing_file->value.s);
+ error_setg_errno(errp, -ret, "Could not open '%s'",
+ backing_file->value.s);
goto out;
}
bdrv_get_geometry(bs, &size);
@@ -4520,8 +4587,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
snprintf(buf, sizeof(buf), "%" PRId64, size);
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
} else {
- error_report("Image creation needs a size parameter");
- ret = -EINVAL;
+ error_setg(errp, "Image creation needs a size parameter");
goto out;
}
}
@@ -4531,17 +4597,16 @@ int bdrv_img_create(const char *filename, const char *fmt,
puts("");
ret = bdrv_create(drv, filename, param);
-
if (ret < 0) {
if (ret == -ENOTSUP) {
- error_report("Formatting or formatting option not supported for "
- "file format '%s'", fmt);
+ error_setg(errp,"Formatting or formatting option not supported for "
+ "file format '%s'", fmt);
} else if (ret == -EFBIG) {
- error_report("The image size is too large for file format '%s'",
- fmt);
+ error_setg(errp, "The image size is too large for file format '%s'",
+ fmt);
} else {
- error_report("%s: error while creating %s: %s", filename, fmt,
- strerror(-ret));
+ error_setg(errp, "%s: error while creating %s: %s", filename, fmt,
+ strerror(-ret));
}
}
@@ -4552,6 +4617,4 @@ out:
if (bs) {
bdrv_delete(bs);
}
-
- return ret;
}