int fd;
const char *tmpdir;
tmpdir = getenv("TMPDIR");
- if (!tmpdir)
- tmpdir = "/tmp";
+ if (!tmpdir) {
+ tmpdir = "/var/tmp";
+ }
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;
}
bdrv_refresh_limits(bs);
assert(bdrv_opt_mem_align(bs) != 0);
- assert(bs->request_alignment != 0);
+ assert((bs->request_alignment != 0) || bs->sg);
#ifndef _WIN32
if (bs->is_temporary) {
ret = -EINVAL;
goto fail;
}
- qdict_del(*options, "filename");
+
+ if (!drv->bdrv_needs_filename) {
+ qdict_del(*options, "filename");
+ } else {
+ filename = qdict_get_str(*options, "filename");
+ }
}
if (!drv->bdrv_file_open) {
* Opens a disk image whose options are given as BlockdevRef in another block
* device's options.
*
- * If force_raw is true, bdrv_file_open() will be used, thereby preventing any
- * image format auto-detection. If it is false and a filename is given,
- * bdrv_open() will be used for auto-detection.
- *
* If allow_none is true, no image will be opened if filename is false and no
* BlockdevRef is given. *pbs will remain unchanged and 0 will be returned.
*
*/
int bdrv_open_image(BlockDriverState **pbs, const char *filename,
QDict *options, const char *bdref_key, int flags,
- bool force_raw, bool allow_none, Error **errp)
+ bool allow_none, Error **errp)
{
QDict *image_options;
int ret;
goto done;
}
- if (filename && !force_raw) {
- /* If a filename is given and the block driver should be detected
- automatically (instead of using none), use bdrv_open() in order to do
- that auto-detection. */
- if (reference) {
- error_setg(errp, "Cannot reference an existing block device while "
- "giving a filename");
- ret = -EINVAL;
- goto done;
- }
-
- ret = bdrv_open(pbs, filename, NULL, image_options, flags, NULL, errp);
- } else {
- ret = bdrv_open(pbs, filename, reference, image_options,
- flags | BDRV_O_PROTOCOL, NULL, errp);
- }
+ ret = bdrv_open(pbs, filename, reference, image_options, flags, NULL, errp);
done:
qdict_del(options, bdref_key);
ret = bdrv_file_open(bs, filename, &options, flags & ~BDRV_O_PROTOCOL,
&local_err);
if (!ret) {
+ drv = bs->drv;
goto done;
} else if (bs->drv) {
goto close_and_fail;
assert(file == NULL);
ret = bdrv_open_image(&file, filename, options, "file",
- bdrv_open_flags(bs, flags | BDRV_O_UNMAP), true, true,
- &local_err);
+ bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
+ BDRV_O_PROTOCOL, true, &local_err);
if (ret < 0) {
- goto fail;
+ goto unlink_and_fail;
}
/* Find the right image format driver */
ret = -EINVAL;
goto close_and_fail;
}
- QDECREF(options);
if (!bdrv_key_required(bs)) {
bdrv_dev_change_media_cb(bs, true);
+ } else if (!runstate_check(RUN_STATE_PRELAUNCH)
+ && !runstate_check(RUN_STATE_INMIGRATE)
+ && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
+ error_setg(errp,
+ "Guest must be stopped for opening of encrypted image");
+ ret = -EBUSY;
+ goto close_and_fail;
}
+ QDECREF(options);
*pbs = bs;
return 0;
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
-
- /* keep the same entry in graph_bdrv_states
- * We do want to swap name but don't want to swap linked list entries
- */
- bs_dest->node_list = bs_src->node_list;
}
/*
{
BlockDriverState tmp;
+ /* The code needs to swap the node_name but simply swapping node_list won't
+ * work so first remove the nodes from the graph list, do the swap then
+ * insert them back if needed.
+ */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
+ }
+
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
+ /* insert the nodes back into the graph node list if needed */
+ if (bs_new->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_new, node_list);
+ }
+ if (bs_old->node_name[0] != '\0') {
+ QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs_old, node_list);
+ }
+
bdrv_rebind(bs_new);
bdrv_rebind(bs_old);
}
static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
int nb_sectors)
{
+ if (nb_sectors > INT_MAX / BDRV_SECTOR_SIZE) {
+ return -EIO;
+ }
+
return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
nb_sectors * BDRV_SECTOR_SIZE);
}
int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
{
- while (bs && bs->drv && !bs->drv->bdrv_debug_resume) {
+ while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
bs = bs->file;
}
return bdrv_co_flush(bs->file);
}
-void bdrv_invalidate_cache(BlockDriverState *bs)
+void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
{
- if (bs->drv && bs->drv->bdrv_invalidate_cache) {
- bs->drv->bdrv_invalidate_cache(bs);
+ Error *local_err = NULL;
+ int ret;
+
+ if (!bs->drv) {
+ return;
+ }
+
+ if (bs->drv->bdrv_invalidate_cache) {
+ bs->drv->bdrv_invalidate_cache(bs, &local_err);
+ } else if (bs->file) {
+ bdrv_invalidate_cache(bs->file, &local_err);
+ }
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ ret = refresh_total_sectors(bs, bs->total_sectors);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Could not refresh total sector count");
+ return;
}
}
-void bdrv_invalidate_cache_all(void)
+void bdrv_invalidate_cache_all(Error **errp)
{
BlockDriverState *bs;
+ Error *local_err = NULL;
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
- bdrv_invalidate_cache(bs);
+ bdrv_invalidate_cache(bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
}
return bs->drv->bdrv_amend_options(bs, options);
}
-/* Used to recurse on single child block filters.
- * Single child block filter will store their child in bs->file.
+/* This function will be called by the bdrv_recurse_is_first_non_filter method
+ * of block filter and by bdrv_is_first_non_filter.
+ * It is used to test if the given bs is the candidate or recurse more in the
+ * node graph.
*/
-bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
+bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
BlockDriverState *candidate)
{
- if (!bs->drv) {
- return false;
- }
-
- if (!bs->drv->authorizations[BS_IS_A_FILTER]) {
- if (bs == candidate) {
- return true;
- } else {
- return false;
- }
- }
-
- if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) {
+ /* return false if basic checks fails */
+ if (!bs || !bs->drv) {
return false;
}
- if (!bs->file) {
- return false;
+ /* the code reached a non block filter driver -> check if the bs is
+ * the same as the candidate. It's the recursion termination condition.
+ */
+ if (!bs->drv->is_filter) {
+ return bs == candidate;
}
+ /* Down this path the driver is a block filter driver */
- return bdrv_recurse_is_first_non_filter(bs->file, candidate);
-}
-
-bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
- BlockDriverState *candidate)
-{
- if (bs->drv && bs->drv->bdrv_recurse_is_first_non_filter) {
+ /* If the block filter recursion method is defined use it to recurse down
+ * the node graph.
+ */
+ if (bs->drv->bdrv_recurse_is_first_non_filter) {
return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate);
}
- return bdrv_generic_is_first_non_filter(bs, candidate);
+ /* the driver is a block filter but don't allow to recurse -> return false
+ */
+ return false;
}
/* This function checks if the candidate is the first non filter bs down it's
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
bool perm;
+ /* try to recurse in this top level bs */
perm = bdrv_recurse_is_first_non_filter(bs, candidate);
/* candidate is the first non filter */