def convert_image(source, dest, out_format, bps_limit=None):
"""Convert image to other format."""
- start_time = timeutils.utcnow()
- # Always set -t none. First it is needed for cgroup io/limiting
- # and it is needed to ensure that all data hit the device before
- # it gets unmapped remotely from the host
+
cmd = ('qemu-img', 'convert',
- '-t', 'none',
'-O', out_format, source, dest)
+
+ # Check whether O_DIRECT is supported and set '-t none' if it is
+ # This is needed to ensure that all data hit the device before
+ # it gets unmapped remotely from the host for some backends
+ # Reference Bug: #1363016
+
+ # NOTE(jdg): In the case of file devices qemu does the
+ # flush properly and more efficiently than would be done
+ # setting O_DIRECT, so check for that and skip the
+ # setting for non BLK devs
+ if (utils.is_blk_device(dest) and
+ volume_utils.check_for_odirect_support(source,
+ dest,
+ 'oflag=direct')):
+ cmd = ('qemu-img', 'convert',
+ '-t', 'none',
+ '-O', out_format, source, dest)
+
+ start_time = timeutils.utcnow()
cgcmd = volume_utils.setup_blkio_cgroup(source, dest, bps_limit)
if cgcmd:
cmd = tuple(cgcmd) + cmd
mox = self._mox
mox.StubOutWithMock(utils, 'execute')
+ mox.StubOutWithMock(utils, 'is_blk_device')
TEST_OUT_FORMAT = 'vmdk'
TEST_SOURCE = 'img/qemu.img'
TEST_DEST = '/img/vmware.vmdk'
+ utils.is_blk_device(TEST_DEST).AndReturn(True)
+ utils.execute('dd', 'count=0', 'if=img/qemu.img',
+ 'of=/img/vmware.vmdk', 'oflag=direct',
+ run_as_root=True)
utils.execute(
'qemu-img', 'convert', '-t', 'none', '-O', TEST_OUT_FORMAT,
TEST_SOURCE, TEST_DEST, run_as_root=True)
mox.StubOutWithMock(utils, 'execute')
mox.StubOutWithMock(image_utils, 'fetch')
mox.StubOutWithMock(volume_utils, 'setup_blkio_cgroup')
+ mox.StubOutWithMock(utils, 'is_blk_device')
TEST_INFO = ("image: qemu.qcow2\n"
"file format: raw\n"
"virtual size: 0 (0 bytes)\n"
"disk size: 0")
+ utils.is_blk_device(self.TEST_DEV_PATH).AndReturn(True)
CONF.set_override('volume_copy_bps_limit', bps_limit)
image_utils.create_temporary_file().AndReturn(self.TEST_DEV_PATH)
prefix = ('cgexec', '-g', 'blkio:test')
else:
prefix = ()
+
+ utils.execute('dd', 'count=0', 'if=/dev/ether/fake_dev',
+ 'of=/dev/ether/fake_dev', 'oflag=direct',
+ run_as_root=True)
+
cmd = prefix + ('qemu-img', 'convert', '-t', 'none', '-O', 'raw',
self.TEST_DEV_PATH, self.TEST_DEV_PATH)
self.TEST_IMAGE_ID, self.TEST_DEV_PATH,
mox.IgnoreArg())
- self._mox.VerifyAll()
-
def test_fetch_to_raw_on_error_parsing_failed(self):
SRC_INFO_NO_FORMAT = ("image: qemu.qcow2\n"
"virtual_size: 50M (52428800 bytes)\n"
context, self._image_service,
self.TEST_IMAGE_ID, self.TEST_DEV_PATH,
mox.IgnoreArg())
- self._mox.VerifyAll()
def test_fetch_to_raw_on_error_backing_file(self):
SRC_INFO_BACKING_FILE = ("image: qemu.qcow2\n"
context, self._image_service,
self.TEST_IMAGE_ID, self.TEST_DEV_PATH,
mox.IgnoreArg())
- self._mox.VerifyAll()
@mock.patch('os.stat')
def test_fetch_to_raw_on_error_not_convert_to_raw(self, mock_stat):
prefix = ('cgexec', '-g', 'blkio:test')
else:
prefix = ()
- cmd = prefix + ('qemu-img', 'convert', '-t', 'none', '-O', 'qcow2',
+
+ cmd = prefix + ('qemu-img', 'convert', '-O', 'qcow2',
mox.IgnoreArg(), mox.IgnoreArg())
m = self._mox
volume_utils.setup_blkio_cgroup(mox.IgnoreArg(), mox.IgnoreArg(),
bps_limit).AndReturn(prefix)
+
utils.execute(*cmd, run_as_root=True)
utils.execute(
'env', 'LC_ALL=C', 'qemu-img', 'info',
@mock.patch('os.stat')
def test_upload_volume_with_bps_limit(self, mock_stat):
+ bps_limit = 1048576
+ image_meta = {'id': 1, 'disk_format': 'qcow2'}
+ TEST_RET = "image: qemu.qcow2\n"\
+ "file_format: qcow2 \n"\
+ "virtual_size: 50M (52428800 bytes)\n"\
+ "cluster_size: 65536\n"\
+ "disk_size: 196K (200704 bytes)"
+
+ CONF.set_override('volume_copy_bps_limit', bps_limit)
+ prefix = ('cgexec', '-g', 'blkio:test')
+
+ cmd = prefix + ('qemu-img', 'convert', '-O', 'qcow2',
+ mox.IgnoreArg(), mox.IgnoreArg())
+
+ m = self._mox
+ m.StubOutWithMock(utils, 'execute')
+ m.StubOutWithMock(volume_utils, 'setup_blkio_cgroup')
+ m.StubOutWithMock(volume_utils, 'check_for_odirect_support')
- self.test_upload_volume(bps_limit=1048576)
+ volume_utils.setup_blkio_cgroup(mox.IgnoreArg(), mox.IgnoreArg(),
+ bps_limit).AndReturn(prefix)
+ utils.execute(*cmd, run_as_root=True)
+ utils.execute(
+ 'env', 'LC_ALL=C', 'qemu-img', 'info',
+ mox.IgnoreArg(), run_as_root=True).AndReturn(
+ (TEST_RET, 'ignored'))
+
+ m.ReplayAll()
+ image_utils.upload_volume(context, FakeImageService(),
+ image_meta, '/dev/loop1')
+ m.VerifyAll()
def test_upload_volume_with_raw_image(self):
image_meta = {'id': 1, 'disk_format': 'raw'}
m = self._mox
m.StubOutWithMock(utils, 'execute')
+ m.StubOutWithMock(volume_utils, 'check_for_odirect_support')
- utils.execute('qemu-img', 'convert', '-t', 'none', '-O', 'qcow2',
+ utils.execute('qemu-img', 'convert', '-O', 'qcow2',
mox.IgnoreArg(), mox.IgnoreArg(), run_as_root=True)
utils.execute(
'env', 'LC_ALL=C', 'qemu-img', 'info',
return blocksize, int(count)
+def check_for_odirect_support(src, dest, flag='oflag=direct'):
+
+ # Check whether O_DIRECT is supported
+ try:
+ utils.execute('dd', 'count=0', 'if=%s' % src, 'of=%s' % dest,
+ flag, run_as_root=True)
+ return True
+ except processutils.ProcessExecutionError:
+ return False
+
+
def copy_volume(srcstr, deststr, size_in_m, blocksize, sync=False,
execute=utils.execute, ionice=None):
# Use O_DIRECT to avoid thrashing the system buffer cache
extra_flags = []
- # Check whether O_DIRECT is supported to iflag and oflag separately
- for flag in ['iflag=direct', 'oflag=direct']:
- try:
- execute('dd', 'count=0', 'if=%s' % srcstr, 'of=%s' % deststr,
- flag, run_as_root=True)
- extra_flags.append(flag)
- except processutils.ProcessExecutionError:
- pass
+ if check_for_odirect_support(srcstr, deststr, 'iflag=direct'):
+ extra_flags.append('iflag=direct')
+
+ if check_for_odirect_support(srcstr, deststr, 'oflag=direct'):
+ extra_flags.append('oflag=direct')
# If the volume is being unprovisioned then
# request the data is persisted before returning,