#include "qapi/qmp/qerror.h"
#include "qemu/ratelimit.h"
#include "qemu/bitmap.h"
-#include "qemu/error-report.h"
#define SLICE_TIME 100000000ULL /* ns */
#define MAX_IN_FLIGHT 16
to_replace = s->to_replace;
}
- /* This was checked in mirror_start_job(), but meanwhile one of the
- * nodes could have been newly attached to a BlockBackend. */
- if (bdrv_has_blk(to_replace) && bdrv_has_blk(s->target)) {
- error_report("block job: Can't create node with two BlockBackends");
- data->ret = -EINVAL;
- goto out;
- }
-
if (bdrv_get_flags(s->target) != bdrv_get_flags(to_replace)) {
bdrv_reopen(s->target, bdrv_get_flags(to_replace), NULL);
}
+
+ /* The mirror job has no requests in flight any more, but we need to
+ * drain potential other users of the BDS before changing the graph. */
+ bdrv_drained_begin(s->target);
bdrv_replace_in_backing_chain(to_replace, s->target);
+ bdrv_drained_end(s->target);
+
/* We just changed the BDS the job BB refers to */
blk_remove_bs(job->blk);
blk_insert_bs(job->blk, src);
}
-
-out:
if (s->to_replace) {
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
error_free(s->replace_blocker);
bool is_none_mode, BlockDriverState *base)
{
MirrorBlockJob *s;
- BlockDriverState *replaced_bs;
if (granularity == 0) {
granularity = bdrv_get_default_bitmap_granularity(target);
buf_size = DEFAULT_MIRROR_BUF_SIZE;
}
- /* We can't support this case as long as the block layer can't handle
- * multiple BlockBackends per BlockDriverState. */
- if (replaces) {
- replaced_bs = bdrv_lookup_bs(replaces, replaces, errp);
- if (replaced_bs == NULL) {
- return;
- }
- } else {
- replaced_bs = bs;
- }
- if (bdrv_has_blk(replaced_bs) && bdrv_has_blk(target)) {
- error_setg(errp, "Can't create node with two BlockBackends");
- return;
- }
-
s = block_job_create(driver, bs, speed, cb, opaque, errp);
if (!s) {
return;
test_image_not_found = None
test_small_buffer2 = None
-class TestBlockdevAttached(iotests.QMPTestCase):
- image_len = 1 * 1024 * 1024 # MB
-
- def setUp(self):
- iotests.create_image(backing_img, self.image_len)
- qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
- qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
- self.vm = iotests.VM().add_drive(test_img)
- self.vm.launch()
-
- def tearDown(self):
- self.vm.shutdown()
- os.remove(test_img)
- os.remove(target_img)
-
- def test_blockdev_attached(self):
- self.assert_no_active_block_jobs()
- args = {'options':
- {'driver': iotests.imgfmt,
- 'id': 'drive1',
- 'file': { 'filename': target_img, 'driver': 'file' } } }
- result = self.vm.qmp("blockdev-add", **args)
- self.assert_qmp(result, 'return', {})
- result = self.vm.qmp('blockdev-mirror', device='drive0', sync='full',
- target='drive1')
- self.assert_qmp(result, 'error/class', 'GenericError')
-
class TestSingleDriveZeroLength(TestSingleDrive):
image_len = 0
test_small_buffer2 = None