diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py index 84d85289ef..4c6f47fc97 100644 --- a/nova/conf/libvirt.py +++ b/nova/conf/libvirt.py @@ -1652,6 +1652,15 @@ Possible values are: accessed by anyone else. The Libvirt secret is public and persistent. It can be read by anyone with sufficient access on the host. The instance can be live-migrated and automatically resumed after host reboot. +"""), + cfg.BoolOpt( + 'use_default_aio_mode_for_volumes', + default=False, + help=""" +With the NFS, FC, and iSCSI Cinder volume backends, Nova explicitly sets AIO +mode ``io=native`` in the Libvirt guest XML. Operators may set this option to +True in order to defer AIO mode selection to QEMU if forcing ``io=native`` is +not desired. """), ] diff --git a/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py b/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py index 55054652c3..0b5c9a82bd 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py +++ b/nova/tests/unit/virt/libvirt/volume/test_fibrechannel.py @@ -65,6 +65,22 @@ class LibvirtFibreChannelVolumeDriverTestCase( self.assertEqual('raw', tree.find('./driver').get('type')) self.assertEqual('native', tree.find('./driver').get('io')) + def test_libvirt_fibrechan_driver_get_config_default_aio_mode(self): + self.flags(use_default_aio_mode_for_volumes=True, group='libvirt') + + libvirt_driver = fibrechannel.LibvirtFibreChannelVolumeDriver( + self.fake_host) + device_path = '/dev/fake-dev' + connection_info = {'data': {'device_path': device_path}} + + conf = libvirt_driver.get_config(connection_info, self.disk_info) + tree = conf.format_dom() + + self.assertEqual('block', tree.get('type')) + self.assertEqual(device_path, tree.find('./source').get('dev')) + self.assertEqual('raw', tree.find('./driver').get('type')) + self.assertIsNone(tree.find('./driver').get('io')) + def test_extend_volume(self): device_path = '/dev/fake-dev' connection_info = {'data': {'device_path': device_path}} diff --git a/nova/tests/unit/virt/libvirt/volume/test_iscsi.py b/nova/tests/unit/virt/libvirt/volume/test_iscsi.py index a1111e0d12..4ac7171f37 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_iscsi.py +++ b/nova/tests/unit/virt/libvirt/volume/test_iscsi.py @@ -45,6 +45,22 @@ class LibvirtISCSIVolumeDriverTestCase( self.assertEqual('raw', tree.find('./driver').get('type')) self.assertEqual('native', tree.find('./driver').get('io')) + def test_libvirt_iscsi_driver_get_config_default_aio_mode(self): + self.flags(use_default_aio_mode_for_volumes=True, group='libvirt') + + libvirt_driver = iscsi.LibvirtISCSIVolumeDriver(self.fake_host) + + device_path = '/dev/fake-dev' + connection_info = {'data': {'device_path': device_path}} + + conf = libvirt_driver.get_config(connection_info, self.disk_info) + tree = conf.format_dom() + + self.assertEqual('block', tree.get('type')) + self.assertEqual(device_path, tree.find('./source').get('dev')) + self.assertEqual('raw', tree.find('./driver').get('type')) + self.assertIsNone(tree.find('./driver').get('io')) + @mock.patch.object(iscsi.LOG, 'warning') def test_libvirt_iscsi_driver_disconnect_volume_with_devicenotfound(self, mock_LOG_warning): diff --git a/nova/tests/unit/virt/libvirt/volume/test_nfs.py b/nova/tests/unit/virt/libvirt/volume/test_nfs.py index a98efaac1c..ccefb15e68 100644 --- a/nova/tests/unit/virt/libvirt/volume/test_nfs.py +++ b/nova/tests/unit/virt/libvirt/volume/test_nfs.py @@ -77,6 +77,24 @@ class LibvirtNFSVolumeDriverTestCase(test_volume.LibvirtVolumeBaseTestCase): self.assertEqual('raw', tree.find('./driver').get('type')) self.assertEqual('native', tree.find('./driver').get('io')) + def test_libvirt_nfs_driver_get_config_default_aio_mode(self): + self.flags(use_default_aio_mode_for_volumes=True, group='libvirt') + + libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_host) + export_string = '192.168.1.1:/nfs/share1' + export_mnt_base = os.path.join(self.mnt_base, + utils.get_hash_str(export_string)) + file_path = os.path.join(export_mnt_base, self.name) + + connection_info = {'data': {'export': export_string, + 'name': self.name, + 'device_path': file_path}} + conf = libvirt_driver.get_config(connection_info, self.disk_info) + tree = conf.format_dom() + self._assertFileTypeEquals(tree, file_path) + self.assertEqual('raw', tree.find('./driver').get('type')) + self.assertIsNone(tree.find('./driver').get('io')) + def test_libvirt_nfs_driver_with_opts(self): libvirt_driver = nfs.LibvirtNFSVolumeDriver(self.fake_host) export_string = '192.168.1.1:/nfs/share1' diff --git a/nova/virt/libvirt/volume/fibrechannel.py b/nova/virt/libvirt/volume/fibrechannel.py index 36e7d8904a..c293d64e20 100644 --- a/nova/virt/libvirt/volume/fibrechannel.py +++ b/nova/virt/libvirt/volume/fibrechannel.py @@ -45,7 +45,8 @@ class LibvirtFibreChannelVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): conf.source_type = "block" conf.source_path = connection_info['data']['device_path'] - conf.driver_io = "native" + if not CONF.libvirt.use_default_aio_mode_for_volumes: + conf.driver_io = "native" return conf def connect_volume(self, connection_info, instance): diff --git a/nova/virt/libvirt/volume/iscsi.py b/nova/virt/libvirt/volume/iscsi.py index 7c99615c38..2350333bd6 100644 --- a/nova/virt/libvirt/volume/iscsi.py +++ b/nova/virt/libvirt/volume/iscsi.py @@ -55,7 +55,8 @@ class LibvirtISCSIVolumeDriver(libvirt_volume.LibvirtBaseVolumeDriver): self).get_config(connection_info, disk_info) conf.source_type = "block" conf.source_path = connection_info['data']['device_path'] - conf.driver_io = "native" + if not CONF.libvirt.use_default_aio_mode_for_volumes: + conf.driver_io = "native" return conf def connect_volume(self, connection_info, instance): diff --git a/nova/virt/libvirt/volume/nfs.py b/nova/virt/libvirt/volume/nfs.py index d0a7bb2eb7..e6c1a5cc0c 100644 --- a/nova/virt/libvirt/volume/nfs.py +++ b/nova/virt/libvirt/volume/nfs.py @@ -34,7 +34,8 @@ class LibvirtNFSVolumeDriver(fs.LibvirtMountedFileSystemVolumeDriver): conf.source_type = 'file' conf.source_path = connection_info['data']['device_path'] conf.driver_format = connection_info['data'].get('format', 'raw') - conf.driver_io = "native" + if not CONF.libvirt.use_default_aio_mode_for_volumes: + conf.driver_io = "native" return conf def _mount_options(self, connection_info): diff --git a/releasenotes/notes/config-default-aio-mode-for-volumes-7c8bcf1ebf01fbd5.yaml b/releasenotes/notes/config-default-aio-mode-for-volumes-7c8bcf1ebf01fbd5.yaml new file mode 100644 index 0000000000..7daf0ff072 --- /dev/null +++ b/releasenotes/notes/config-default-aio-mode-for-volumes-7c8bcf1ebf01fbd5.yaml @@ -0,0 +1,10 @@ +features: + - | + A new configuration option ``[libvirt]use_default_aio_mode_for_volumes`` + has been added to enable use of QEMU default AIO modes for NFS, FC, and + iSCSI Cinder volumes. + By default, Nova explicitly sets AIO mode ``io=native`` in the Libvirt + guest XML for NFS, FC, and iSCSI Cinder volumes. Operators may set this + option to ``True`` in order to defer AIO mode selection to QEMU if forcing + ``io=native`` is not desired. +