libvirt/src/util/virstoragefile.c

5212 lines
146 KiB
C
Raw Normal View History

/*
* virstoragefile.c: file utility functions for FS storage backend
*
* Copyright (C) 2007-2017 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "virstoragefilebackend.h"
#include <unistd.h>
#include <fcntl.h>
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
#include "virxml.h"
#include "viruuid.h"
#include "virerror.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
#include "virfile.h"
#include "vircommand.h"
#include "virhash.h"
#include "virendian.h"
#include "virstring.h"
#include "virutil.h"
#include "viruri.h"
#include "virbuffer.h"
#include "virjson.h"
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
#include "virstorageencryption.h"
#include "virsecret.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
VIR_LOG_INIT("util.storagefile");
static virClassPtr virStorageSourceClass;
VIR_ENUM_IMPL(virStorage,
VIR_STORAGE_TYPE_LAST,
"none",
conf: move host disk type to util/ A continuation of the migration of disk details to virstoragefile. This patch moves a single enum, but converting the name has quite a bit of fallout. * src/conf/domain_conf.h (virDomainDiskType): Move... * src/util/virstoragefile.h (virStorageType): ...and rename. * src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr) (virBhyveProcessBuildLoadCmd): Update clients. * src/conf/domain_conf.c (virDomainDiskSourceDefParse) (virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal) (virDomainDiskDefFormat, virDomainDiskGetActualType) (virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType): Likewise. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML) (virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat): Likewise. * src/esx/esx_driver.c (esxAutodetectSCSIControllerModel) (esxDomainDefineXML): Likewise. * src/locking/domain_lock.c (virDomainLockManagerAddDisk): Likewise. * src/lxc/lxc_controller.c (virLXCControllerSetupLoopDeviceDisk) (virLXCControllerSetupNBDDeviceDisk) (virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk): Likewise. * src/parallels/parallels_driver.c (parallelsGetHddInfo): Likewise. * src/phyp/phyp_driver.c (phypDiskType): Likewise. * src/qemu/qemu_command.c (qemuGetDriveSourceString) (qemuDomainDiskGetSourceString, qemuBuildDriveStr) (qemuBuildCommandLine, qemuParseCommandLineDisk) (qemuParseCommandLine): Likewise. * src/qemu/qemu_conf.c (qemuCheckSharedDevice) (qemuTranslateDiskSourcePool) (qemuTranslateSnapshotDiskSourcePool): Likewise. * src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse) (qemuDomainDetermineDiskChain): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetBlockInfo) (qemuDomainSnapshotPrepareDiskExternalBackingInactive) (qemuDomainSnapshotPrepareDiskExternalBackingActive) (qemuDomainSnapshotPrepareDiskExternalOverlayActive) (qemuDomainSnapshotPrepareDiskExternalOverlayInactive) (qemuDomainSnapshotPrepareDiskInternal) (qemuDomainSnapshotPrepare) (qemuDomainSnapshotCreateSingleDiskActive): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia): Likewise. * src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise. * src/security/security_apparmor.c (AppArmorRestoreSecurityImageLabel) (AppArmorSetSecurityImageLabel): Likewise. * src/security/security_dac.c (virSecurityDACSetSecurityImageLabel) (virSecurityDACRestoreSecurityImageLabelInt) (virSecurityDACSetSecurityAllLabel): Likewise. * src/security/security_selinux.c (virSecuritySELinuxRestoreSecurityImageLabelInt) (virSecuritySELinuxSetSecurityImageLabel) (virSecuritySELinuxSetSecurityAllLabel): Likewise. * src/storage/storage_backend.c (virStorageFileBackendForType): Likewise. * src/storage/storage_backend_fs.c (virStorageFileBackendFile) (virStorageFileBackendBlock): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGluster): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives) (vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise. * src/vmware/vmware_conf.c (vmwareVmxPath): Likewise. * src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk) (virVMXFormatFloppy): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr) (xenFormatSxprDisk): Likewise. * src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise. * tests/securityselinuxlabeltest.c (testSELinuxLoadDef): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
"file",
"block",
conf: move host disk type to util/ A continuation of the migration of disk details to virstoragefile. This patch moves a single enum, but converting the name has quite a bit of fallout. * src/conf/domain_conf.h (virDomainDiskType): Move... * src/util/virstoragefile.h (virStorageType): ...and rename. * src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr) (virBhyveProcessBuildLoadCmd): Update clients. * src/conf/domain_conf.c (virDomainDiskSourceDefParse) (virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal) (virDomainDiskDefFormat, virDomainDiskGetActualType) (virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType): Likewise. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML) (virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat): Likewise. * src/esx/esx_driver.c (esxAutodetectSCSIControllerModel) (esxDomainDefineXML): Likewise. * src/locking/domain_lock.c (virDomainLockManagerAddDisk): Likewise. * src/lxc/lxc_controller.c (virLXCControllerSetupLoopDeviceDisk) (virLXCControllerSetupNBDDeviceDisk) (virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk): Likewise. * src/parallels/parallels_driver.c (parallelsGetHddInfo): Likewise. * src/phyp/phyp_driver.c (phypDiskType): Likewise. * src/qemu/qemu_command.c (qemuGetDriveSourceString) (qemuDomainDiskGetSourceString, qemuBuildDriveStr) (qemuBuildCommandLine, qemuParseCommandLineDisk) (qemuParseCommandLine): Likewise. * src/qemu/qemu_conf.c (qemuCheckSharedDevice) (qemuTranslateDiskSourcePool) (qemuTranslateSnapshotDiskSourcePool): Likewise. * src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse) (qemuDomainDetermineDiskChain): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetBlockInfo) (qemuDomainSnapshotPrepareDiskExternalBackingInactive) (qemuDomainSnapshotPrepareDiskExternalBackingActive) (qemuDomainSnapshotPrepareDiskExternalOverlayActive) (qemuDomainSnapshotPrepareDiskExternalOverlayInactive) (qemuDomainSnapshotPrepareDiskInternal) (qemuDomainSnapshotPrepare) (qemuDomainSnapshotCreateSingleDiskActive): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia): Likewise. * src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise. * src/security/security_apparmor.c (AppArmorRestoreSecurityImageLabel) (AppArmorSetSecurityImageLabel): Likewise. * src/security/security_dac.c (virSecurityDACSetSecurityImageLabel) (virSecurityDACRestoreSecurityImageLabelInt) (virSecurityDACSetSecurityAllLabel): Likewise. * src/security/security_selinux.c (virSecuritySELinuxRestoreSecurityImageLabelInt) (virSecuritySELinuxSetSecurityImageLabel) (virSecuritySELinuxSetSecurityAllLabel): Likewise. * src/storage/storage_backend.c (virStorageFileBackendForType): Likewise. * src/storage/storage_backend_fs.c (virStorageFileBackendFile) (virStorageFileBackendBlock): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGluster): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives) (vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise. * src/vmware/vmware_conf.c (vmwareVmxPath): Likewise. * src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk) (virVMXFormatFloppy): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr) (xenFormatSxprDisk): Likewise. * src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise. * tests/securityselinuxlabeltest.c (testSELinuxLoadDef): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
"dir",
"network",
"volume",
"nvme",
);
conf: move host disk type to util/ A continuation of the migration of disk details to virstoragefile. This patch moves a single enum, but converting the name has quite a bit of fallout. * src/conf/domain_conf.h (virDomainDiskType): Move... * src/util/virstoragefile.h (virStorageType): ...and rename. * src/bhyve/bhyve_command.c (bhyveBuildDiskArgStr) (virBhyveProcessBuildLoadCmd): Update clients. * src/conf/domain_conf.c (virDomainDiskSourceDefParse) (virDomainDiskDefParseXML, virDomainDiskSourceDefFormatInternal) (virDomainDiskDefFormat, virDomainDiskGetActualType) (virDomainDiskDefForeachPath, virDomainDiskSourceIsBlockType): Likewise. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefParseXML) (virDomainSnapshotAlignDisks, virDomainSnapshotDiskDefFormat): Likewise. * src/esx/esx_driver.c (esxAutodetectSCSIControllerModel) (esxDomainDefineXML): Likewise. * src/locking/domain_lock.c (virDomainLockManagerAddDisk): Likewise. * src/lxc/lxc_controller.c (virLXCControllerSetupLoopDeviceDisk) (virLXCControllerSetupNBDDeviceDisk) (virLXCControllerSetupLoopDevices, virLXCControllerSetupDisk): Likewise. * src/parallels/parallels_driver.c (parallelsGetHddInfo): Likewise. * src/phyp/phyp_driver.c (phypDiskType): Likewise. * src/qemu/qemu_command.c (qemuGetDriveSourceString) (qemuDomainDiskGetSourceString, qemuBuildDriveStr) (qemuBuildCommandLine, qemuParseCommandLineDisk) (qemuParseCommandLine): Likewise. * src/qemu/qemu_conf.c (qemuCheckSharedDevice) (qemuTranslateDiskSourcePool) (qemuTranslateSnapshotDiskSourcePool): Likewise. * src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse) (qemuDomainDetermineDiskChain): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetBlockInfo) (qemuDomainSnapshotPrepareDiskExternalBackingInactive) (qemuDomainSnapshotPrepareDiskExternalBackingActive) (qemuDomainSnapshotPrepareDiskExternalOverlayActive) (qemuDomainSnapshotPrepareDiskExternalOverlayInactive) (qemuDomainSnapshotPrepareDiskInternal) (qemuDomainSnapshotPrepare) (qemuDomainSnapshotCreateSingleDiskActive): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainChangeEjectableMedia): Likewise. * src/qemu/qemu_migration.c (qemuMigrationIsSafe): Likewise. * src/security/security_apparmor.c (AppArmorRestoreSecurityImageLabel) (AppArmorSetSecurityImageLabel): Likewise. * src/security/security_dac.c (virSecurityDACSetSecurityImageLabel) (virSecurityDACRestoreSecurityImageLabelInt) (virSecurityDACSetSecurityAllLabel): Likewise. * src/security/security_selinux.c (virSecuritySELinuxRestoreSecurityImageLabelInt) (virSecuritySELinuxSetSecurityImageLabel) (virSecuritySELinuxSetSecurityAllLabel): Likewise. * src/storage/storage_backend.c (virStorageFileBackendForType): Likewise. * src/storage/storage_backend_fs.c (virStorageFileBackendFile) (virStorageFileBackendBlock): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGluster): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainGetXMLDesc, vboxAttachDrives) (vboxDomainAttachDeviceImpl, vboxDomainDetachDevice): Likewise. * src/vmware/vmware_conf.c (vmwareVmxPath): Likewise. * src/vmx/vmx.c (virVMXParseDisk, virVMXFormatDisk) (virVMXFormatFloppy): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxprDisks, xenParseSxpr) (xenFormatSxprDisk): Likewise. * src/xenxs/xen_xm.c (xenParseXM, xenFormatXMDisk): Likewise. * tests/securityselinuxlabeltest.c (testSELinuxLoadDef): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-27 21:57:49 +00:00
VIR_ENUM_IMPL(virStorageFileFormat,
VIR_STORAGE_FILE_LAST,
"none",
"raw", "dir", "bochs",
"cloop", "dmg", "iso",
"vpc", "vdi",
/* Not direct file formats, but used for various drivers */
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
"fat", "vhd", "ploop",
/* Formats with backing file below here */
"cow", "qcow", "qcow2", "qed", "vmdk",
);
VIR_ENUM_IMPL(virStorageFileFeature,
VIR_STORAGE_FILE_FEATURE_LAST,
"lazy_refcounts",
);
VIR_ENUM_IMPL(virStorageNetProtocol,
VIR_STORAGE_NET_PROTOCOL_LAST,
"none",
"nbd",
"rbd",
"sheepdog",
"gluster",
"iscsi",
"http",
"https",
"ftp",
"ftps",
"tftp",
"ssh",
"vxhs",
);
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
VIR_ENUM_IMPL(virStorageNetHostTransport,
VIR_STORAGE_NET_HOST_TRANS_LAST,
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
"tcp",
"unix",
"rdma",
);
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
VIR_ENUM_IMPL(virStorageSourcePoolMode,
VIR_STORAGE_SOURCE_POOL_MODE_LAST,
"default",
"host",
"direct",
);
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
VIR_ENUM_IMPL(virStorageAuth,
VIR_STORAGE_AUTH_TYPE_LAST,
"none", "chap", "ceph",
);
enum lv_endian {
LV_LITTLE_ENDIAN = 1, /* 1234 */
LV_BIG_ENDIAN /* 4321 */
};
enum {
BACKING_STORE_OK,
BACKING_STORE_INVALID,
BACKING_STORE_ERROR,
};
#define FILE_TYPE_VERSIONS_LAST 3
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
struct FileEncryptionInfo {
int format; /* Encryption format to assign */
int magicOffset; /* Byte offset of the magic */
const char *magic; /* Optional string of magic */
enum lv_endian endian; /* Endianness of file format */
int versionOffset; /* Byte offset from start of file
* where we find version number,
* -1 to always fail the version test,
* -2 to always pass the version test */
int versionSize; /* Size in bytes of version data (0, 2, or 4) */
int versionNumbers[FILE_TYPE_VERSIONS_LAST];
/* Version numbers to validate. Zeroes are ignored. */
int modeOffset; /* Byte offset of the format native encryption mode */
char modeValue; /* Value expected at offset */
int payloadOffset; /* start offset of the volume data (in 512 byte sectors) */
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
};
struct FileTypeInfo {
int magicOffset; /* Byte offset of the magic */
const char *magic; /* Optional string of file magic
* to check at head of file */
enum lv_endian endian; /* Endianness of file format */
int versionOffset; /* Byte offset from start of file
* where we find version number,
* -1 to always fail the version test,
* -2 to always pass the version test */
int versionSize; /* Size in bytes of version data (0, 2, or 4) */
int versionNumbers[FILE_TYPE_VERSIONS_LAST];
/* Version numbers to validate. Zeroes are ignored. */
int sizeOffset; /* Byte offset from start of file
* where we find capacity info,
* -1 to use st_size as capacity */
int sizeBytes; /* Number of bytes for size field */
int sizeMultiplier; /* A scaling factor if size is not in bytes */
/* Store a COW base image path (possibly relative),
* or NULL if there is no COW base image, to RES;
* return BACKING_STORE_* */
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
const struct FileEncryptionInfo *cryptInfo; /* Encryption info */
int (*getBackingStore)(char **res, int *format,
const char *buf, size_t buf_size);
int (*getFeatures)(virBitmapPtr *features, int format,
char *buf, ssize_t len);
};
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
static int cowGetBackingStore(char **, int *,
const char *, size_t);
static int qcowXGetBackingStore(char **, int *,
const char *, size_t);
static int qcow2GetFeatures(virBitmapPtr *features, int format,
char *buf, ssize_t len);
static int vmdk4GetBackingStore(char **, int *,
const char *, size_t);
static int
qedGetBackingStore(char **, int *, const char *, size_t);
#define QCOWX_HDR_VERSION (4)
#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4)
#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8)
#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4)
#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1+2)
#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8)
#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8)
#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8)
#define QCOW2_HDR_EXTENSION_END 0
#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA
#define QCOW2_HDR_EXTENSION_DATA_FILE 0x44415441
#define QCOW2v3_HDR_FEATURES_INCOMPATIBLE (QCOW2_HDR_TOTAL_SIZE)
#define QCOW2v3_HDR_FEATURES_COMPATIBLE (QCOW2v3_HDR_FEATURES_INCOMPATIBLE+8)
#define QCOW2v3_HDR_FEATURES_AUTOCLEAR (QCOW2v3_HDR_FEATURES_COMPATIBLE+8)
/* The location of the header size [4 bytes] */
#define QCOW2v3_HDR_SIZE (QCOW2_HDR_TOTAL_SIZE+8+8+8+4)
#define QED_HDR_FEATURES_OFFSET (4+4+4+4)
#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8)
#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8)
#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4)
#define QED_F_BACKING_FILE 0x01
#define QED_F_BACKING_FORMAT_NO_PROBE 0x04
#define PLOOP_IMAGE_SIZE_OFFSET 36
#define PLOOP_SIZE_MULTIPLIER 512
#define LUKS_HDR_MAGIC_LEN 6
#define LUKS_HDR_VERSION_LEN 2
#define LUKS_HDR_CIPHER_NAME_LEN 32
#define LUKS_HDR_CIPHER_MODE_LEN 32
#define LUKS_HDR_HASH_SPEC_LEN 32
#define LUKS_HDR_PAYLOAD_LEN 4
/* Format described by qemu commit id '3e308f20e' */
#define LUKS_HDR_VERSION_OFFSET LUKS_HDR_MAGIC_LEN
#define LUKS_HDR_PAYLOAD_OFFSET (LUKS_HDR_MAGIC_LEN+\
LUKS_HDR_VERSION_LEN+\
LUKS_HDR_CIPHER_NAME_LEN+\
LUKS_HDR_CIPHER_MODE_LEN+\
LUKS_HDR_HASH_SPEC_LEN)
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
static struct FileEncryptionInfo const luksEncryptionInfo[] = {
{
.format = VIR_STORAGE_ENCRYPTION_FORMAT_LUKS,
/* Magic is 'L','U','K','S', 0xBA, 0xBE */
.magicOffset = 0,
.magic = "\x4c\x55\x4b\x53\xba\xbe",
.endian = LV_BIG_ENDIAN,
.versionOffset = LUKS_HDR_VERSION_OFFSET,
.versionSize = LUKS_HDR_VERSION_LEN,
.versionNumbers = {1},
.modeOffset = -1,
.modeValue = -1,
.payloadOffset = LUKS_HDR_PAYLOAD_OFFSET,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
},
{ 0 }
};
static struct FileEncryptionInfo const qcow1EncryptionInfo[] = {
{
.format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW,
.magicOffset = 0,
.magic = NULL,
.endian = LV_BIG_ENDIAN,
.versionOffset = -1,
.versionSize = 0,
.versionNumbers = {},
.modeOffset = QCOW1_HDR_CRYPT,
.modeValue = 1,
.payloadOffset = -1,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
},
{ 0 }
};
static struct FileEncryptionInfo const qcow2EncryptionInfo[] = {
{
.format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW,
.magicOffset = 0,
.magic = NULL,
.endian = LV_BIG_ENDIAN,
.versionOffset = -1,
.versionSize = 0,
.versionNumbers = {},
.modeOffset = QCOW2_HDR_CRYPT,
.modeValue = 1,
.payloadOffset = -1,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
},
{ 0 }
};
static struct FileTypeInfo const fileTypeInfo[] = {
[VIR_STORAGE_FILE_NONE] = { 0, NULL, LV_LITTLE_ENDIAN,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, {0}, 0, 0, 0, NULL, NULL, NULL },
[VIR_STORAGE_FILE_RAW] = { 0, NULL, LV_LITTLE_ENDIAN,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, {0}, 0, 0, 0,
luksEncryptionInfo,
NULL, NULL },
[VIR_STORAGE_FILE_DIR] = { 0, NULL, LV_LITTLE_ENDIAN,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, {0}, 0, 0, 0, NULL, NULL, NULL },
[VIR_STORAGE_FILE_BOCHS] = {
/*"Bochs Virtual HD Image", */ /* Untested */
0, NULL,
LV_LITTLE_ENDIAN, 64, 4, {0x20000},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL
},
[VIR_STORAGE_FILE_CLOOP] = {
/* #!/bin/sh
#V2.0 Format
modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1
*/ /* Untested */
0, NULL,
LV_LITTLE_ENDIAN, -1, 0, {0},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, 0, NULL, NULL, NULL
},
[VIR_STORAGE_FILE_DMG] = {
/* XXX QEMU says there's no magic for dmg,
* /usr/share/misc/magic lists double magic (both offsets
* would have to match) but then disables that check. */
0, NULL,
0, -1, 0, {0},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, 0, NULL, NULL, NULL
},
[VIR_STORAGE_FILE_ISO] = {
32769, "CD001",
LV_LITTLE_ENDIAN, -2, 0, {0},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, 0, NULL, NULL, NULL
},
[VIR_STORAGE_FILE_VPC] = {
0, "conectix",
LV_BIG_ENDIAN, 12, 4, {0x10000},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL
},
/* TODO: add getBackingStore function */
[VIR_STORAGE_FILE_VDI] = {
64, "\x7f\x10\xda\xbe",
LV_LITTLE_ENDIAN, 68, 4, {0x00010001},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL},
/* Not direct file formats, but used for various drivers */
[VIR_STORAGE_FILE_FAT] = { 0, NULL, LV_LITTLE_ENDIAN,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, {0}, 0, 0, 0, NULL, NULL, NULL },
[VIR_STORAGE_FILE_VHD] = { 0, NULL, LV_LITTLE_ENDIAN,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
-1, 0, {0}, 0, 0, 0, NULL, NULL, NULL },
[VIR_STORAGE_FILE_PLOOP] = { 0, "WithouFreSpacExt", LV_LITTLE_ENDIAN,
-2, 0, {0}, PLOOP_IMAGE_SIZE_OFFSET, 0,
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL },
/* All formats with a backing store probe below here */
[VIR_STORAGE_FILE_COW] = {
0, "OOOM",
LV_BIG_ENDIAN, 4, 4, {2},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
4+4+1024+4, 8, 1, NULL, cowGetBackingStore, NULL
},
[VIR_STORAGE_FILE_QCOW] = {
0, "QFI",
LV_BIG_ENDIAN, 4, 4, {1},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
QCOWX_HDR_IMAGE_SIZE, 8, 1,
qcow1EncryptionInfo,
qcowXGetBackingStore, NULL
},
[VIR_STORAGE_FILE_QCOW2] = {
0, "QFI",
LV_BIG_ENDIAN, 4, 4, {2, 3},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
QCOWX_HDR_IMAGE_SIZE, 8, 1,
qcow2EncryptionInfo,
qcowXGetBackingStore,
qcow2GetFeatures
},
[VIR_STORAGE_FILE_QED] = {
/* https://wiki.qemu.org/Features/QED */
0, "QED",
LV_LITTLE_ENDIAN, -2, 0, {0},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
QED_HDR_IMAGE_SIZE, 8, 1, NULL, qedGetBackingStore, NULL
},
[VIR_STORAGE_FILE_VMDK] = {
0, "KDMV",
LV_LITTLE_ENDIAN, 4, 4, {1, 2, 3},
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
4+4+4, 8, 512, NULL, vmdk4GetBackingStore, NULL
},
};
G_STATIC_ASSERT(G_N_ELEMENTS(fileTypeInfo) == VIR_STORAGE_FILE_LAST);
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
/* qcow2 compatible features in the order they appear on-disk */
enum qcow2CompatibleFeature {
QCOW2_COMPATIBLE_FEATURE_LAZY_REFCOUNTS = 0,
QCOW2_COMPATIBLE_FEATURE_LAST
};
/* conversion to virStorageFileFeature */
static const int qcow2CompatibleFeatureArray[] = {
VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS,
};
G_STATIC_ASSERT(G_N_ELEMENTS(qcow2CompatibleFeatureArray) ==
QCOW2_COMPATIBLE_FEATURE_LAST);
static int
cowGetBackingStore(char **res,
int *format,
const char *buf,
size_t buf_size)
{
#define COW_FILENAME_MAXLEN 1024
*res = NULL;
*format = VIR_STORAGE_FILE_AUTO;
if (buf_size < 4+4+ COW_FILENAME_MAXLEN)
return BACKING_STORE_INVALID;
if (buf[4+4] == '\0') { /* cow_header_v2.backing_file[0] */
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
*res = g_strndup((const char *)buf + 4 + 4, COW_FILENAME_MAXLEN);
return BACKING_STORE_OK;
}
static int
qcow2GetExtensions(const char *buf,
size_t buf_size,
int *backingFormat,
char **externalDataStoreRaw)
{
size_t offset;
size_t extension_start;
size_t extension_end;
int version = virReadBufInt32BE(buf + QCOWX_HDR_VERSION);
if (version < 2) {
/* QCow1 doesn't have the extensions capability
* used to store backing format */
return 0;
}
if (version == 2)
extension_start = QCOW2_HDR_TOTAL_SIZE;
else
extension_start = virReadBufInt32BE(buf + QCOW2v3_HDR_SIZE);
/*
* Traditionally QCow2 files had a layout of
*
* [header]
* [backingStoreName]
*
* Although the backingStoreName typically followed
* the header immediately, this was not required by
* the format. By specifying a higher byte offset for
* the backing file offset in the header, it was
* possible to leave space between the header and
* start of backingStore.
*
* This hack is now used to store extensions to the
* qcow2 format:
*
* [header]
* [extensions]
* [backingStoreName]
*
* Thus the file region to search for extensions is
* between the end of the header (QCOW2_HDR_TOTAL_SIZE)
* and the start of the backingStoreName (offset)
*
* for qcow2 v3 images, the length of the header
* is stored at QCOW2v3_HDR_SIZE
*/
extension_end = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET);
if (extension_end > buf_size)
return -1;
/*
* The extensions take format of
*
* int32: magic
* int32: length
* byte[length]: payload
*
* Unknown extensions can be ignored by skipping
* over "length" bytes in the data stream.
*/
offset = extension_start;
while (offset < (buf_size-8) &&
offset < (extension_end-8)) {
unsigned int magic = virReadBufInt32BE(buf + offset);
unsigned int len = virReadBufInt32BE(buf + offset + 4);
offset += 8;
if ((offset + len) < offset)
break;
if ((offset + len) > buf_size)
break;
switch (magic) {
case QCOW2_HDR_EXTENSION_BACKING_FORMAT: {
g_autofree char *tmp = NULL;
if (!backingFormat)
break;
if (VIR_ALLOC_N(tmp, len + 1) < 0)
return -1;
memcpy(tmp, buf + offset, len);
tmp[len] = '\0';
*backingFormat = virStorageFileFormatTypeFromString(tmp);
if (*backingFormat <= VIR_STORAGE_FILE_NONE)
return -1;
break;
}
case QCOW2_HDR_EXTENSION_DATA_FILE: {
if (!externalDataStoreRaw)
break;
if (VIR_ALLOC_N(*externalDataStoreRaw, len + 1) < 0)
return -1;
memcpy(*externalDataStoreRaw, buf + offset, len);
(*externalDataStoreRaw)[len] = '\0';
VIR_DEBUG("parsed externalDataStoreRaw='%s'",
*externalDataStoreRaw);
break;
}
case QCOW2_HDR_EXTENSION_END:
return 0;
}
offset += len;
}
return 0;
}
static int
qcowXGetBackingStore(char **res,
int *format,
const char *buf,
size_t buf_size)
{
unsigned long long offset;
unsigned int size;
*res = NULL;
*format = VIR_STORAGE_FILE_AUTO;
if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4)
return BACKING_STORE_INVALID;
offset = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET);
if (offset > buf_size)
return BACKING_STORE_INVALID;
if (offset == 0) {
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
size = virReadBufInt32BE(buf + QCOWX_HDR_BACKING_FILE_SIZE);
if (size == 0) {
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
if (size > 1023)
return BACKING_STORE_INVALID;
if (offset + size > buf_size || offset + size < offset)
return BACKING_STORE_INVALID;
if (VIR_ALLOC_N(*res, size + 1) < 0)
return BACKING_STORE_ERROR;
memcpy(*res, buf + offset, size);
(*res)[size] = '\0';
if (qcow2GetExtensions(buf, buf_size, format, NULL) < 0)
return BACKING_STORE_INVALID;
return BACKING_STORE_OK;
}
static int
vmdk4GetBackingStore(char **res,
int *format,
const char *buf,
size_t buf_size)
{
static const char prefix[] = "parentFileNameHint=\"";
char *start, *end;
size_t len;
g_autofree char *desc = NULL;
if (VIR_ALLOC_N(desc, VIR_STORAGE_MAX_HEADER) < 0)
return BACKING_STORE_ERROR;
*res = NULL;
/*
* Technically this should have been VMDK, since
* VMDK spec / VMware impl only support VMDK backed
* by VMDK. QEMU isn't following this though and
* does probing on VMDK backing files, hence we set
* AUTO
*/
*format = VIR_STORAGE_FILE_AUTO;
if (buf_size <= 0x200)
return BACKING_STORE_INVALID;
len = buf_size - 0x200;
if (len > VIR_STORAGE_MAX_HEADER)
len = VIR_STORAGE_MAX_HEADER;
memcpy(desc, buf + 0x200, len);
desc[len] = '\0';
start = strstr(desc, prefix);
if (start == NULL) {
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
start += strlen(prefix);
end = strchr(start, '"');
if (end == NULL)
return BACKING_STORE_INVALID;
if (end == start) {
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
*end = '\0';
*res = g_strdup(start);
return BACKING_STORE_OK;
}
static int
qedGetBackingStore(char **res,
int *format,
const char *buf,
size_t buf_size)
{
unsigned long long flags;
unsigned long offset, size;
*res = NULL;
/* Check if this image has a backing file */
if (buf_size < QED_HDR_FEATURES_OFFSET+8)
return BACKING_STORE_INVALID;
flags = virReadBufInt64LE(buf + QED_HDR_FEATURES_OFFSET);
if (!(flags & QED_F_BACKING_FILE)) {
*format = VIR_STORAGE_FILE_NONE;
return BACKING_STORE_OK;
}
/* Parse the backing file */
if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8)
return BACKING_STORE_INVALID;
offset = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_OFFSET);
if (offset > buf_size)
return BACKING_STORE_INVALID;
size = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_SIZE);
if (size == 0)
return BACKING_STORE_OK;
if (offset + size > buf_size || offset + size < offset)
return BACKING_STORE_INVALID;
if (VIR_ALLOC_N(*res, size + 1) < 0)
return BACKING_STORE_ERROR;
memcpy(*res, buf + offset, size);
(*res)[size] = '\0';
if (flags & QED_F_BACKING_FORMAT_NO_PROBE)
*format = VIR_STORAGE_FILE_RAW;
else
*format = VIR_STORAGE_FILE_AUTO_SAFE;
return BACKING_STORE_OK;
}
static bool
virStorageFileMatchesMagic(int magicOffset,
const char *magic,
char *buf,
size_t buflen)
{
int mlen;
if (magic == NULL)
return false;
/* Validate magic data */
mlen = strlen(magic);
if (magicOffset + mlen > buflen)
return false;
if (memcmp(buf + magicOffset, magic, mlen) != 0)
return false;
return true;
}
static bool
virStorageFileMatchesVersion(int versionOffset,
int versionSize,
const int *versionNumbers,
int endian,
char *buf,
size_t buflen)
{
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
int version;
size_t i;
/* Validate version number info */
if (versionOffset == -1)
return false;
/* -2 == non-versioned file format, so trivially match */
if (versionOffset == -2)
return true;
/* A positive versionOffset, requires using a valid versionSize */
if (versionSize != 2 && versionSize != 4)
return false;
if ((versionOffset + versionSize) > buflen)
return false;
if (endian == LV_LITTLE_ENDIAN) {
if (versionSize == 4)
version = virReadBufInt32LE(buf +
versionOffset);
else
version = virReadBufInt16LE(buf +
versionOffset);
} else {
if (versionSize == 4)
version = virReadBufInt32BE(buf +
versionOffset);
else
version = virReadBufInt16BE(buf +
versionOffset);
}
for (i = 0;
i < FILE_TYPE_VERSIONS_LAST && versionNumbers[i];
i++) {
VIR_DEBUG("Compare detected version %d vs one of the expected versions %d",
version, versionNumbers[i]);
if (version == versionNumbers[i])
return true;
}
return false;
}
bool
virStorageIsFile(const char *backing)
{
char *colon;
char *slash;
if (!backing)
return false;
colon = strchr(backing, ':');
slash = strchr(backing, '/');
/* Reject anything that looks like a protocol (such as nbd: or
* rbd:); if someone really does want a relative file name that
* includes ':', they can always prefix './'. */
if (colon && (!slash || colon < slash))
return false;
return true;
}
bool
virStorageIsRelative(const char *backing)
{
if (backing[0] == '/')
return false;
if (!virStorageIsFile(backing))
return false;
return true;
}
static int
virStorageFileProbeFormatFromBuf(const char *path,
char *buf,
size_t buflen)
{
int format = VIR_STORAGE_FILE_RAW;
size_t i;
int possibleFormat = VIR_STORAGE_FILE_RAW;
VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen);
/* First check file magic */
for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) {
if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset,
fileTypeInfo[i].magic,
buf, buflen)) {
if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset,
fileTypeInfo[i].versionSize,
fileTypeInfo[i].versionNumbers,
fileTypeInfo[i].endian,
buf, buflen)) {
possibleFormat = i;
continue;
}
format = i;
goto cleanup;
}
}
if (possibleFormat != VIR_STORAGE_FILE_RAW)
VIR_WARN("File %s matches %s magic, but version is wrong. "
"Please report new version to libvir-list@redhat.com",
path, virStorageFileFormatTypeToString(possibleFormat));
cleanup:
VIR_DEBUG("format=%d", format);
return format;
}
static int
qcow2GetFeatures(virBitmapPtr *features,
int format,
char *buf,
ssize_t len)
{
int version = -1;
virBitmapPtr feat = NULL;
uint64_t bits;
size_t i;
version = virReadBufInt32BE(buf + fileTypeInfo[format].versionOffset);
if (version == 2)
return 0;
if (len < QCOW2v3_HDR_SIZE)
return -1;
if (!(feat = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
return -1;
/* todo: check for incompatible or autoclear features? */
bits = virReadBufInt64BE(buf + QCOW2v3_HDR_FEATURES_COMPATIBLE);
for (i = 0; i < QCOW2_COMPATIBLE_FEATURE_LAST; i++) {
if (bits & ((uint64_t) 1 << i))
ignore_value(virBitmapSetBit(feat, qcow2CompatibleFeatureArray[i]));
}
*features = feat;
return 0;
}
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
static bool
virStorageFileHasEncryptionFormat(const struct FileEncryptionInfo *info,
char *buf,
size_t len)
{
if (!info->magic && info->modeOffset == -1)
return false; /* Shouldn't happen - expect at least one */
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
if (info->magic) {
if (!virStorageFileMatchesMagic(info->magicOffset,
info->magic,
buf, len))
return false;
if (info->versionOffset != -1 &&
!virStorageFileMatchesVersion(info->versionOffset,
info->versionSize,
info->versionNumbers,
info->endian,
buf, len))
return false;
return true;
} else if (info->modeOffset != -1) {
int crypt_format;
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
if (info->modeOffset >= len)
return false;
crypt_format = virReadBufInt32BE(buf + info->modeOffset);
if (crypt_format != info->modeValue)
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
return false;
return true;
} else {
return false;
}
}
static int
virStorageFileGetEncryptionPayloadOffset(const struct FileEncryptionInfo *info,
char *buf)
{
int payload_offset = -1;
if (info->payloadOffset != -1) {
if (info->endian == LV_LITTLE_ENDIAN)
payload_offset = virReadBufInt32LE(buf + info->payloadOffset);
else
payload_offset = virReadBufInt32BE(buf + info->payloadOffset);
}
return payload_offset;
}
/* Given a header in BUF with length LEN, as parsed from the storage file
* assuming it has the given FORMAT, populate information into META
* with information about the file and its backing store. Return format
* of the backing store as BACKING_FORMAT. PATH and FORMAT have to be
* pre-populated in META.
*
* Note that this function may be called repeatedly on @meta, so it must
* clean up any existing allocated memory which would be overwritten.
*/
static int
virStorageFileGetMetadataInternal(virStorageSourcePtr meta,
char *buf,
size_t len,
int *backingFormat)
{
int dummy;
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
size_t i;
if (!backingFormat)
backingFormat = &dummy;
VIR_DEBUG("path=%s, buf=%p, len=%zu, meta->format=%d",
meta->path, buf, len, meta->format);
if (meta->format == VIR_STORAGE_FILE_AUTO)
meta->format = virStorageFileProbeFormatFromBuf(meta->path, buf, len);
conf: track more fields in backing chain metadata The current use of virStorageFileMetadata is awkward; to learn some of the information about a child node, you have to read fields in the parent node. This does not lend itself well to modifying backing chains (whether inserting a new node in the chain, or consolidating existing nodes); better would be to learn about a child node directly in that node. This patch sets up some new fields which contain redundant information, although not necessarily in the final desired state for the new fields (see the next patch for actual tests of what is there now). Then later patches will do any refactoring necessary to get the fields to their desired states, and update clients to get the information from the new fields, so we can finally delete the fields that are tracking information about the wrong node. More concretely, compare these three example backing chains: good <- one missing <- two gluster://server/vol/img <- three Pre-patch, querying the chains gives: { .backingStore = "/path/to/good", .backingStoreRaw = "good", .backingStoreIsFile = true, .backingStoreFormat = VIR_STORAGE_FILE_RAW, .backingMeta = { .backingStore = NULL, .backingStoreRaw = NULL, .backingStoreIsFile = false, .backingMeta = NULL, } } { .backingStore = NULL, .backingStoreRaw = "missing", .backingStoreIsFile = false, .backingStoreFormat = VIR_STORAGE_FILE_NONE, .backingMeta = NULL, } { .backingStore = "gluster://server/vol/img", .backingStoreRaw = NULL, .backingStoreIsFile = false, .backingStoreFormat = VIR_STORAGE_FILE_RAW, .backingMeta = NULL, } Deciding whether to ignore a missing backing file (as in virsh vol-dumpxml) or report an error (as in security manager sVirt labeling) requires reading multiple fields. Plus, the format is hard-coded to treat all network protocols as end-of-the-chain, as if they were raw. By the end of this patch series, the goal is to instead represent these three situations as: { .path = "one", .canonPath = "/path/to/one", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "good", .backingMeta = { .path = "good", .canonPath = "/path/to/good", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_RAW, .backingStoreRaw = NULL, .backingMeta = NULL, } } { .path = "two", .canonPath = "/path/to/two", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "missing", .backingMeta = NULL, } { .path = "three", .canonPath = "/path/to/three", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "gluster://server/vol/img", .backingMeta = { .path = "gluster://server/vol/img", .canonPath = "gluster://server/vol/img", .type = VIR_STORAGE_TYPE_NETWORK, .format = VIR_STORAGE_FILE_RAW, .backingStoreRaw = NULL, .backingMeta = NULL, } } or, for the second file, maybe also allowing: { .path = "two", .canonPath = "/path/to/two", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "missing", .backingMeta = { .path = "missing", .canonPath = NULL, .type = VIR_STORAGE_TYPE_NONE, .format = VIR_STORAGE_FILE_NONE, .backingStoreRaw = NULL, .backingMeta = NULL, } } * src/util/virstoragefile.h (_virStorageFileMetadata): Add path, canonPath, relDir, type, and format fields. Reorder existing fields, and add lots of comments. * src/util/virstoragefile.c (virStorageFileFreeMetadata): Clean new fields. (virStorageFileGetMetadataInternal) (virStorageFileGetMetadataFromFDInternal): Start populating new fields. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-04-08 22:09:05 +00:00
if (meta->format <= VIR_STORAGE_FILE_NONE ||
meta->format >= VIR_STORAGE_FILE_LAST) {
virReportSystemError(EINVAL, _("unknown storage file meta->format %d"),
meta->format);
return -1;
}
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
if (fileTypeInfo[meta->format].cryptInfo != NULL) {
for (i = 0; fileTypeInfo[meta->format].cryptInfo[i].format != 0; i++) {
if (virStorageFileHasEncryptionFormat(&fileTypeInfo[meta->format].cryptInfo[i],
buf, len)) {
qemu: Fix crash hot plugging luks volume https://bugzilla.redhat.com/show_bug.cgi?id=1367259 Crash occurs because 'secrets' is being dereferenced in call: if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias, VIR_SECRET_USAGE_TYPE_VOLUME, NULL, &src->encryption->secrets[0]->seclookupdef, true) < 0) (gdb) p *src->encryption $1 = {format = 2, nsecrets = 0, secrets = 0x0, encinfo = {cipher_size = 0, cipher_name = 0x0, cipher_mode = 0x0, cipher_hash = 0x0, ivgen_name = 0x0, ivgen_hash = 0x0}} (gdb) bt priv=priv@entry=0x7fffc03be160, disk=disk@entry=0x7fffb4002ae0) at qemu/qemu_domain.c:1087 disk=0x7fffb4002ae0, vm=0x7fffc03a2580, driver=0x7fffc02ca390, conn=0x7fffb00009a0) at qemu/qemu_hotplug.c:355 Upon entry to qemuDomainAttachVirtioDiskDevice, src->encryption points at a valid 'secret' buffer w/ nsecrets == 1; however, the call to qemuDomainDetermineDiskChain will call virStorageFileGetMetadata and eventually virStorageFileGetMetadataInternal where the src->encryption was overwritten when probing the volume. Commit id 'a48c7141' added code to virStorageFileGetMetadataInternal to determine if the disk/volume would use/need encryption and allocated a meta->encryption. This overwrote an existing encryption buffer already provided by the XML This patch adds a check for meta->encryption already present before just allocating and overwriting an existing buffer. It then checks the existing encryption data to ensure the XML provided format for the disk matches the expected format read from the disk and errors if there is a mismatch.
2016-08-17 14:25:43 +00:00
int expt_fmt = fileTypeInfo[meta->format].cryptInfo[i].format;
if (!meta->encryption) {
if (VIR_ALLOC(meta->encryption) < 0)
return -1;
qemu: Fix crash hot plugging luks volume https://bugzilla.redhat.com/show_bug.cgi?id=1367259 Crash occurs because 'secrets' is being dereferenced in call: if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias, VIR_SECRET_USAGE_TYPE_VOLUME, NULL, &src->encryption->secrets[0]->seclookupdef, true) < 0) (gdb) p *src->encryption $1 = {format = 2, nsecrets = 0, secrets = 0x0, encinfo = {cipher_size = 0, cipher_name = 0x0, cipher_mode = 0x0, cipher_hash = 0x0, ivgen_name = 0x0, ivgen_hash = 0x0}} (gdb) bt priv=priv@entry=0x7fffc03be160, disk=disk@entry=0x7fffb4002ae0) at qemu/qemu_domain.c:1087 disk=0x7fffb4002ae0, vm=0x7fffc03a2580, driver=0x7fffc02ca390, conn=0x7fffb00009a0) at qemu/qemu_hotplug.c:355 Upon entry to qemuDomainAttachVirtioDiskDevice, src->encryption points at a valid 'secret' buffer w/ nsecrets == 1; however, the call to qemuDomainDetermineDiskChain will call virStorageFileGetMetadata and eventually virStorageFileGetMetadataInternal where the src->encryption was overwritten when probing the volume. Commit id 'a48c7141' added code to virStorageFileGetMetadataInternal to determine if the disk/volume would use/need encryption and allocated a meta->encryption. This overwrote an existing encryption buffer already provided by the XML This patch adds a check for meta->encryption already present before just allocating and overwriting an existing buffer. It then checks the existing encryption data to ensure the XML provided format for the disk matches the expected format read from the disk and errors if there is a mismatch.
2016-08-17 14:25:43 +00:00
meta->encryption->format = expt_fmt;
} else {
if (meta->encryption->format != expt_fmt) {
virReportError(VIR_ERR_XML_ERROR,
_("encryption format %d doesn't match "
"expected format %d"),
meta->encryption->format, expt_fmt);
return -1;
qemu: Fix crash hot plugging luks volume https://bugzilla.redhat.com/show_bug.cgi?id=1367259 Crash occurs because 'secrets' is being dereferenced in call: if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias, VIR_SECRET_USAGE_TYPE_VOLUME, NULL, &src->encryption->secrets[0]->seclookupdef, true) < 0) (gdb) p *src->encryption $1 = {format = 2, nsecrets = 0, secrets = 0x0, encinfo = {cipher_size = 0, cipher_name = 0x0, cipher_mode = 0x0, cipher_hash = 0x0, ivgen_name = 0x0, ivgen_hash = 0x0}} (gdb) bt priv=priv@entry=0x7fffc03be160, disk=disk@entry=0x7fffb4002ae0) at qemu/qemu_domain.c:1087 disk=0x7fffb4002ae0, vm=0x7fffc03a2580, driver=0x7fffc02ca390, conn=0x7fffb00009a0) at qemu/qemu_hotplug.c:355 Upon entry to qemuDomainAttachVirtioDiskDevice, src->encryption points at a valid 'secret' buffer w/ nsecrets == 1; however, the call to qemuDomainDetermineDiskChain will call virStorageFileGetMetadata and eventually virStorageFileGetMetadataInternal where the src->encryption was overwritten when probing the volume. Commit id 'a48c7141' added code to virStorageFileGetMetadataInternal to determine if the disk/volume would use/need encryption and allocated a meta->encryption. This overwrote an existing encryption buffer already provided by the XML This patch adds a check for meta->encryption already present before just allocating and overwriting an existing buffer. It then checks the existing encryption data to ensure the XML provided format for the disk matches the expected format read from the disk and errors if there is a mismatch.
2016-08-17 14:25:43 +00:00
}
}
meta->encryption->payload_offset =
virStorageFileGetEncryptionPayloadOffset(&fileTypeInfo[meta->format].cryptInfo[i], buf);
storage: remove "luks" storage volume type The current LUKS support has a "luks" volume type which has a "luks" encryption format. This partially makes sense if you consider the QEMU shorthand syntax only requires you to specify a format=luks, and it'll automagically uses "raw" as the next level driver. QEMU will however let you override the "raw" with any other driver it supports (vmdk, qcow, rbd, iscsi, etc, etc) IOW the intention though is that the "luks" encryption format is applied to all disk formats (whether raw, qcow2, rbd, gluster or whatever). As such it doesn't make much sense for libvirt to say the volume type is "luks" - we should be saying that it is a "raw" file, but with "luks" encryption applied. IOW, when creating a storage volume we should use this XML <volume> <name>demo.raw</name> <capacity>5368709120</capacity> <target> <format type='raw'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </target> </volume> and when configuring a guest disk we should use <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/home/berrange/VirtualMachines/demo.raw'/> <target dev='sda' bus='scsi'/> <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccd2f80d6f'/> </encryption> </disk> This commit thus removes the "luks" storage volume type added in commit 318ebb36f1027b3357a32d6f781bd77d7a9043fd Author: John Ferlan <jferlan@redhat.com> Date: Tue Jun 21 12:59:54 2016 -0400 util: Add 'luks' to the FileTypeInfo The storage file probing code is modified so that it can probe the actual encryption formats explicitly, rather than merely probing existance of encryption and letting the storage driver guess the format. The rest of the code is then adapted to deal with VIR_STORAGE_FILE_RAW w/ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS instead of just VIR_STORAGE_FILE_LUKS. The commit mentioned above was included in libvirt v2.0.0. So when querying volume XML this will be a change in behaviour vs the 2.0.0 release - it'll report 'raw' instead of 'luks' for the volume format, but still report 'luks' for encryption format. I think this change is OK because the storage driver did not include any support for creating volumes, nor starting guets with luks volumes in v2.0.0 - that only since then. Clearly if we change this we must do it before v2.1.0 though. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2016-07-26 16:41:46 +00:00
}
}
}
/* XXX we should consider moving virStorageBackendUpdateVolInfo
* code into this method, for non-magic files
*/
if (!fileTypeInfo[meta->format].magic)
return 0;
/* Optionally extract capacity from file */
if (fileTypeInfo[meta->format].sizeOffset != -1) {
if ((fileTypeInfo[meta->format].sizeOffset + 8) > len)
return 0;
if (fileTypeInfo[meta->format].endian == LV_LITTLE_ENDIAN)
meta->capacity = virReadBufInt64LE(buf +
fileTypeInfo[meta->format].sizeOffset);
else
meta->capacity = virReadBufInt64BE(buf +
fileTypeInfo[meta->format].sizeOffset);
/* Avoid unlikely, but theoretically possible overflow */
if (meta->capacity > (ULLONG_MAX /
fileTypeInfo[meta->format].sizeMultiplier))
return 0;
meta->capacity *= fileTypeInfo[meta->format].sizeMultiplier;
}
VIR_FREE(meta->backingStoreRaw);
if (fileTypeInfo[meta->format].getBackingStore != NULL) {
int store = fileTypeInfo[meta->format].getBackingStore(&meta->backingStoreRaw,
backingFormat,
buf, len);
if (store == BACKING_STORE_INVALID)
return 0;
if (store == BACKING_STORE_ERROR)
return -1;
}
virBitmapFree(meta->features);
meta->features = NULL;
if (fileTypeInfo[meta->format].getFeatures != NULL &&
fileTypeInfo[meta->format].getFeatures(&meta->features, meta->format, buf, len) < 0)
return -1;
VIR_FREE(meta->externalDataStoreRaw);
if (meta->format == VIR_STORAGE_FILE_QCOW2 &&
qcow2GetExtensions(buf, len, NULL, &meta->externalDataStoreRaw) < 0) {
return -1;
}
VIR_FREE(meta->compat);
if (meta->format == VIR_STORAGE_FILE_QCOW2 && meta->features)
meta->compat = g_strdup("1.1");
return 0;
}
/**
* virStorageFileProbeFormat:
*
* Probe for the format of 'path', returning the detected
* disk format.
*
* Callers are advised never to trust the returned 'format'
* unless it is listed as VIR_STORAGE_FILE_RAW, since a
* malicious guest can turn a raw file into any other non-raw
* format at will.
*
* Best option: Don't use this function
*/
int
virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid)
{
struct stat sb;
ssize_t len = VIR_STORAGE_MAX_HEADER;
VIR_AUTOCLOSE fd = -1;
g_autofree char *header = NULL;
if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
virReportSystemError(-fd, _("Failed to open file '%s'"), path);
return -1;
}
if (fstat(fd, &sb) < 0) {
virReportSystemError(errno, _("cannot stat file '%s'"), path);
return -1;
}
/* No header to probe for directories */
if (S_ISDIR(sb.st_mode))
return VIR_STORAGE_FILE_DIR;
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
virReportSystemError(errno, _("cannot set to start of '%s'"), path);
return -1;
}
if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) {
virReportSystemError(errno, _("cannot read header '%s'"), path);
return -1;
}
return virStorageFileProbeFormatFromBuf(path, header, len);
}
static virStorageSourcePtr
virStorageFileMetadataNew(const char *path,
int format)
{
g_autoptr(virStorageSource) def = NULL;
if (!(def = virStorageSourceNew()))
return NULL;
def->format = format;
def->type = VIR_STORAGE_TYPE_FILE;
def->path = g_strdup(path);
return g_steal_pointer(&def);
}
/**
* virStorageFileGetMetadataFromBuf:
* @path: name of file, for error messages
* @buf: header bytes from @path
* @len: length of @buf
* @format: format of the storage file
* @backingFormat: format of @backing
*
* Extract metadata about the storage volume with the specified image format.
* If image format is VIR_STORAGE_FILE_AUTO, it will probe to automatically
* identify the format. Does not recurse.
*
* Callers are advised never to use VIR_STORAGE_FILE_AUTO as a format on a file
* that might be raw if that file will then be passed to a guest, since a
* malicious guest can turn a raw file into any other non-raw format at will.
*
* If the returned @backingFormat is VIR_STORAGE_FILE_AUTO it indicates the
* image didn't specify an explicit format for its backing store. Callers are
* advised against probing for the backing store format in this case.
*
* Caller MUST free the result after use via virObjectUnref.
*/
virStorageSourcePtr
virStorageFileGetMetadataFromBuf(const char *path,
char *buf,
size_t len,
int format,
int *backingFormat)
{
virStorageSourcePtr ret = NULL;
int dummy;
if (!backingFormat)
backingFormat = &dummy;
if (!(ret = virStorageFileMetadataNew(path, format)))
return NULL;
if (virStorageFileGetMetadataInternal(ret, buf, len,
backingFormat) < 0) {
virObjectUnref(ret);
return NULL;
}
return ret;
}
/**
* virStorageFileGetMetadataFromFD:
*
* Extract metadata about the storage volume with the specified
* image format. If image format is VIR_STORAGE_FILE_AUTO, it
* will probe to automatically identify the format. Does not recurse.
*
* Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
* format, since a malicious guest can turn a raw file into any
* other non-raw format at will.
*
* Caller MUST free the result after use via virObjectUnref.
*/
virStorageSourcePtr
virStorageFileGetMetadataFromFD(const char *path,
int fd,
int format,
int *backingFormat)
{
ssize_t len = VIR_STORAGE_MAX_HEADER;
struct stat sb;
int dummy;
g_autofree char *buf = NULL;
g_autoptr(virStorageSource) meta = NULL;
if (!backingFormat)
backingFormat = &dummy;
*backingFormat = VIR_STORAGE_FILE_NONE;
if (fstat(fd, &sb) < 0) {
virReportSystemError(errno,
_("cannot stat file '%s'"), path);
return NULL;
}
if (!(meta = virStorageFileMetadataNew(path, format)))
return NULL;
if (S_ISDIR(sb.st_mode)) {
/* No header to probe for directories, but also no backing file. Just
* update the metadata.*/
conf: track more fields in backing chain metadata The current use of virStorageFileMetadata is awkward; to learn some of the information about a child node, you have to read fields in the parent node. This does not lend itself well to modifying backing chains (whether inserting a new node in the chain, or consolidating existing nodes); better would be to learn about a child node directly in that node. This patch sets up some new fields which contain redundant information, although not necessarily in the final desired state for the new fields (see the next patch for actual tests of what is there now). Then later patches will do any refactoring necessary to get the fields to their desired states, and update clients to get the information from the new fields, so we can finally delete the fields that are tracking information about the wrong node. More concretely, compare these three example backing chains: good <- one missing <- two gluster://server/vol/img <- three Pre-patch, querying the chains gives: { .backingStore = "/path/to/good", .backingStoreRaw = "good", .backingStoreIsFile = true, .backingStoreFormat = VIR_STORAGE_FILE_RAW, .backingMeta = { .backingStore = NULL, .backingStoreRaw = NULL, .backingStoreIsFile = false, .backingMeta = NULL, } } { .backingStore = NULL, .backingStoreRaw = "missing", .backingStoreIsFile = false, .backingStoreFormat = VIR_STORAGE_FILE_NONE, .backingMeta = NULL, } { .backingStore = "gluster://server/vol/img", .backingStoreRaw = NULL, .backingStoreIsFile = false, .backingStoreFormat = VIR_STORAGE_FILE_RAW, .backingMeta = NULL, } Deciding whether to ignore a missing backing file (as in virsh vol-dumpxml) or report an error (as in security manager sVirt labeling) requires reading multiple fields. Plus, the format is hard-coded to treat all network protocols as end-of-the-chain, as if they were raw. By the end of this patch series, the goal is to instead represent these three situations as: { .path = "one", .canonPath = "/path/to/one", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "good", .backingMeta = { .path = "good", .canonPath = "/path/to/good", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_RAW, .backingStoreRaw = NULL, .backingMeta = NULL, } } { .path = "two", .canonPath = "/path/to/two", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "missing", .backingMeta = NULL, } { .path = "three", .canonPath = "/path/to/three", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "gluster://server/vol/img", .backingMeta = { .path = "gluster://server/vol/img", .canonPath = "gluster://server/vol/img", .type = VIR_STORAGE_TYPE_NETWORK, .format = VIR_STORAGE_FILE_RAW, .backingStoreRaw = NULL, .backingMeta = NULL, } } or, for the second file, maybe also allowing: { .path = "two", .canonPath = "/path/to/two", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, .backingStoreRaw = "missing", .backingMeta = { .path = "missing", .canonPath = NULL, .type = VIR_STORAGE_TYPE_NONE, .format = VIR_STORAGE_FILE_NONE, .backingStoreRaw = NULL, .backingMeta = NULL, } } * src/util/virstoragefile.h (_virStorageFileMetadata): Add path, canonPath, relDir, type, and format fields. Reorder existing fields, and add lots of comments. * src/util/virstoragefile.c (virStorageFileFreeMetadata): Clean new fields. (virStorageFileGetMetadataInternal) (virStorageFileGetMetadataFromFDInternal): Start populating new fields. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-04-08 22:09:05 +00:00
meta->type = VIR_STORAGE_TYPE_DIR;
meta->format = VIR_STORAGE_FILE_DIR;
return g_steal_pointer(&meta);
}
if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
virReportSystemError(errno, _("cannot seek to start of '%s'"), meta->path);
return NULL;
}
if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) {
virReportSystemError(errno, _("cannot read header '%s'"), meta->path);
return NULL;
}
if (virStorageFileGetMetadataInternal(meta, buf, len, backingFormat) < 0)
return NULL;
if (S_ISREG(sb.st_mode))
meta->type = VIR_STORAGE_TYPE_FILE;
else if (S_ISBLK(sb.st_mode))
meta->type = VIR_STORAGE_TYPE_BLOCK;
return g_steal_pointer(&meta);
}
/**
* virStorageFileChainCheckBroken
*
* If CHAIN is broken, set *brokenFile to the broken file name,
* otherwise set it to NULL. Caller MUST free *brokenFile after use.
* Return 0 on success (including when brokenFile is set), negative on
* error (allocation failure).
*/
int
virStorageFileChainGetBroken(virStorageSourcePtr chain,
char **brokenFile)
{
virStorageSourcePtr tmp;
*brokenFile = NULL;
if (!chain)
return 0;
for (tmp = chain; virStorageSourceIsBacking(tmp); tmp = tmp->backingStore) {
/* Break when we hit end of chain; report error if we detected
* a missing backing file, infinite loop, or other error */
if (!tmp->backingStore && tmp->backingStoreRaw) {
*brokenFile = g_strdup(tmp->backingStoreRaw);
return 0;
}
}
return 0;
}
/**
* virStorageFileResize:
*
* Change the capacity of the raw storage file at 'path'.
*/
int
virStorageFileResize(const char *path,
unsigned long long capacity,
bool pre_allocate)
{
int rc;
VIR_AUTOCLOSE fd = -1;
if ((fd = open(path, O_RDWR)) < 0) {
virReportSystemError(errno, _("Unable to open '%s'"), path);
return -1;
}
if (pre_allocate) {
if ((rc = virFileAllocate(fd, 0, capacity)) != 0) {
if (rc == -2) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("preallocate is not supported on this platform"));
} else {
virReportSystemError(errno,
_("Failed to pre-allocate space for "
"file '%s'"), path);
}
return -1;
}
}
if (ftruncate(fd, capacity) < 0) {
virReportSystemError(errno,
_("Failed to truncate file '%s'"), path);
return -1;
}
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno, _("Unable to save '%s'"), path);
return -1;
}
return 0;
}
2012-02-21 21:58:50 +00:00
int virStorageFileIsClusterFS(const char *path)
{
/* These are coherent cluster filesystems known to be safe for
* migration with cache != none
*/
return virFileIsSharedFSType(path,
VIR_FILE_SHFS_GFS2 |
VIR_FILE_SHFS_OCFS |
VIR_FILE_SHFS_CEPH);
2012-02-21 21:58:50 +00:00
}
#ifdef LVS
int virStorageFileGetLVMKey(const char *path,
char **key)
{
/*
* # lvs --noheadings --unbuffered --nosuffix --options "uuid" LVNAME
* 06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky
*/
int status;
int ret = -1;
g_autoptr(virCommand) cmd = NULL;
cmd = virCommandNewArgList(LVS, "--noheadings",
"--unbuffered", "--nosuffix",
"--options", "uuid", path,
NULL
);
*key = NULL;
/* Run the program and capture its output */
virCommandSetOutputBuffer(cmd, key);
if (virCommandRun(cmd, &status) < 0)
goto cleanup;
/* Explicitly check status == 0, rather than passing NULL
* to virCommandRun because we don't want to raise an actual
* error in this scenario, just return a NULL key.
*/
if (status == 0 && *key) {
char *nl;
char *tmp = *key;
/* Find first non-space character */
while (*tmp && g_ascii_isspace(*tmp))
tmp++;
/* Kill leading spaces */
if (tmp != *key)
memmove(*key, tmp, strlen(tmp)+1);
/* Kill trailing newline */
if ((nl = strchr(*key, '\n')))
*nl = '\0';
}
ret = 0;
cleanup:
if (*key && STREQ(*key, ""))
VIR_FREE(*key);
return ret;
}
#else
int virStorageFileGetLVMKey(const char *path,
char **key G_GNUC_UNUSED)
{
virReportSystemError(ENOSYS, _("Unable to get LVM key for %s"), path);
return -1;
}
#endif
#ifdef WITH_UDEV
/* virStorageFileGetSCSIKey
* @path: Path to the SCSI device
* @key: Unique key to be returned
* @ignoreError: Used to not report ENOSYS
*
* Using a udev specific function, query the @path to get and return a
* unique @key for the caller to use.
*
* Returns:
* 0 On success, with the @key filled in or @key=NULL if the
* returned string was empty.
* -1 When WITH_UDEV is undefined and a system error is reported
* -2 When WITH_UDEV is defined, but calling virCommandRun fails
*/
int
virStorageFileGetSCSIKey(const char *path,
char **key,
bool ignoreError G_GNUC_UNUSED)
{
int status;
g_autoptr(virCommand) cmd = NULL;
cmd = virCommandNewArgList("/lib/udev/scsi_id",
"--replace-whitespace",
"--whitelisted",
"--device", path,
NULL
);
*key = NULL;
/* Run the program and capture its output */
virCommandSetOutputBuffer(cmd, key);
if (virCommandRun(cmd, &status) < 0)
return -2;
/* Explicitly check status == 0, rather than passing NULL
* to virCommandRun because we don't want to raise an actual
* error in this scenario, just return a NULL key.
*/
if (status == 0 && *key) {
char *nl = strchr(*key, '\n');
if (nl)
*nl = '\0';
}
if (*key && STREQ(*key, ""))
VIR_FREE(*key);
return 0;
}
#else
int virStorageFileGetSCSIKey(const char *path,
char **key G_GNUC_UNUSED,
bool ignoreError)
{
if (!ignoreError)
virReportSystemError(ENOSYS, _("Unable to get SCSI key for %s"), path);
return -1;
}
#endif
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
#ifdef WITH_UDEV
/* virStorageFileGetNPIVKey
* @path: Path to the NPIV device
* @key: Unique key to be returned
*
* Using a udev specific function, query the @path to get and return a
* unique @key for the caller to use. Unlike the GetSCSIKey method, an
* NPIV LUN is uniquely identified by its ID_TARGET_PORT value.
*
* Returns:
* 0 On success, with the @key filled in or @key=NULL if the
* returned output string didn't have the data we need to
* formulate a unique key value
* -1 When WITH_UDEV is undefined and a system error is reported
* -2 When WITH_UDEV is defined, but calling virCommandRun fails
*/
# define ID_SERIAL "ID_SERIAL="
# define ID_TARGET_PORT "ID_TARGET_PORT="
int
virStorageFileGetNPIVKey(const char *path,
char **key)
{
int status;
const char *serial;
const char *port;
g_autofree char *outbuf = NULL;
g_autoptr(virCommand) cmd = NULL;
cmd = virCommandNewArgList("/lib/udev/scsi_id",
"--replace-whitespace",
"--whitelisted",
"--export",
"--device", path,
NULL
);
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
*key = NULL;
/* Run the program and capture its output */
virCommandSetOutputBuffer(cmd, &outbuf);
if (virCommandRun(cmd, &status) < 0)
return -2;
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
/* Explicitly check status == 0, rather than passing NULL
* to virCommandRun because we don't want to raise an actual
* error in this scenario, just return a NULL key.
*/
if (status == 0 && *outbuf &&
(serial = strstr(outbuf, ID_SERIAL)) &&
(port = strstr(outbuf, ID_TARGET_PORT))) {
char *tmp;
serial += strlen(ID_SERIAL);
port += strlen(ID_TARGET_PORT);
if ((tmp = strchr(serial, '\n')))
*tmp = '\0';
if ((tmp = strchr(port, '\n')))
*tmp = '\0';
if (*serial != '\0' && *port != '\0')
*key = g_strdup_printf("%s_PORT%s", serial, port);
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
}
return 0;
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
}
#else
int virStorageFileGetNPIVKey(const char *path G_GNUC_UNUSED,
char **key G_GNUC_UNUSED)
util: Introduce virStorageFileGetNPIVKey The vHBA/NPIV LUNs created via the udev processing of the VPORT_CREATE command end up using the same serial value as seen/generated by the /lib/udev/scsi_id as returned during virStorageFileGetSCSIKey. Therefore, in order to generate a unique enough key to be used when adding the LUN as a volume during virStoragePoolObjAddVol a more unique key needs to be generated for an NPIV volume. The problem is illustrated by the following example, where scsi_host5 is a vHBA used with the following LUNs: $ lsscsi -tg ... [5:0:4:0] disk fc:0x5006016844602198,0x101f00 /dev/sdh /dev/sg23 [5:0:5:0] disk fc:0x5006016044602198,0x102000 /dev/sdi /dev/sg24 ... Calling virStorageFileGetSCSIKey would return: /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh 350060160c460219850060160c4602198 /lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi 350060160c460219850060160c4602198 Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they end up with the same serial number used for the vol->key value. When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol the second LUN fails to be added with the following message getting logged: virHashAddOrUpdateEntry:341 : internal error: Duplicate key To resolve this, virStorageFileGetNPIVKey will use a similar call sequence as virStorageFileGetSCSIKey, except that it will add the "--export" option to the call. This results in more detailed output which needs to be parsed in order to formulate a unique enough key to be used. In order to be unique enough, the returned value will concatenate the target port as returned in the "ID_TARGET_PORT" field from the command to the "ID_SERIAL" value. Signed-off-by: John Ferlan <jferlan@redhat.com> ACKed-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
2019-01-16 00:07:07 +00:00
{
return -1;
}
#endif
/**
* virStorageFileParseBackingStoreStr:
* @str: backing store specifier string to parse
* @target: returns target device portion of the string
* @chainIndex: returns the backing store portion of the string
*
* Parses the backing store specifier string such as vda[1], or sda into
* components and returns them via arguments. If the string did not specify an
* index, 0 is assumed.
*
* Returns 0 on success -1 on error
*/
int
virStorageFileParseBackingStoreStr(const char *str,
char **target,
unsigned int *chainIndex)
{
size_t nstrings;
unsigned int idx = 0;
char *suffix;
VIR_AUTOSTRINGLIST strings = NULL;
*chainIndex = 0;
if (!(strings = virStringSplitCount(str, "[", 2, &nstrings)))
return -1;
if (nstrings == 2) {
if (virStrToLong_uip(strings[1], &suffix, 10, &idx) < 0 ||
STRNEQ(suffix, "]"))
return -1;
}
if (target)
*target = g_strdup(strings[0]);
*chainIndex = idx;
return 0;
}
int
virStorageFileParseChainIndex(const char *diskTarget,
const char *name,
unsigned int *chainIndex)
{
unsigned int idx = 0;
g_autofree char *target = NULL;
*chainIndex = 0;
if (!name || !diskTarget)
return 0;
if (virStorageFileParseBackingStoreStr(name, &target, &idx) < 0)
return 0;
if (idx == 0)
return 0;
if (STRNEQ(diskTarget, target)) {
virReportError(VIR_ERR_INVALID_ARG,
_("requested target '%s' does not match target '%s'"),
target, diskTarget);
return -1;
}
*chainIndex = idx;
return 0;
}
/**
* virStorageSourceIsBacking:
* @src: storage source
*
* Returns true if @src is a eligible backing store structure. Useful
* for iterators.
*/
bool
virStorageSourceIsBacking(const virStorageSource *src)
{
return src && src->type != VIR_STORAGE_TYPE_NONE;
}
/**
* virStorageSourceHasBacking:
* @src: storage source
*
* Returns true if @src has backing store/chain.
*/
bool
virStorageSourceHasBacking(const virStorageSource *src)
{
return virStorageSourceIsBacking(src) && src->backingStore &&
src->backingStore->type != VIR_STORAGE_TYPE_NONE;
}
blockcommit: require base below top The block commit code looks for an explicit base file relative to the discovered top file; so for a chain of: base <- snap1 <- snap2 <- snap3 and a command of: virsh blockcommit $dom vda --base snap2 --top snap1 we got a sane message (here from libvirt 1.0.5): error: invalid argument: could not find base 'snap2' below 'snap1' in chain for 'vda' Meanwhile, recent refactoring has slightly reduced the quality of the libvirt error messages, by losing the phrase 'below xyz': error: invalid argument: could not find image 'snap2' in chain for 'snap3' But we had a one-off, where we were not excluding the top file itself in searching for the base; thankfully qemu still reports the error, but the quality is worse: virsh blockcommit $dom vda --base snap2 --top snap2 error: internal error unable to execute QEMU command 'block-commit': Base '/snap2' not found Fix the one-off in blockcommit by changing the semantics of name lookup - if a starting point is specified, then the result must be below that point, rather than including that point. The only other call to chain lookup was blockpull code, which was already forcing the lookup to omit the active layer and only needs a tweak to use the new semantics. This also fixes the bug exposed in the testsuite, where when doing a lookup pinned to an intermediate point in the chain, we were unable to return the name of the parent also in the chain. * src/util/virstoragefile.c (virStorageFileChainLookup): Change semantics for non-NULL startFrom. * src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Adjust caller, to keep existing semantics. * tests/virstoragetest.c (mymain): Adjust to expose new semantics. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-06-11 22:22:57 +00:00
/* Given a @chain, look for the backing store @name that is a backing file
* of @startFrom (or any member of @chain if @startFrom is NULL) and return
* that location within the chain. @chain must always point to the top of
* the chain. Pass NULL for @name and 0 for @idx to find the base of the
* chain. Pass nonzero @idx to find the backing source according to its
* position in the backing chain. If @parent is not NULL, set *@parent to
* the preferred name of the parent (or to NULL if @name matches the start
* of the chain). Since the results point within @chain, they must not be
* independently freed. Reports an error and returns NULL if @name is not
* found.
*/
virStorageSourcePtr
virStorageFileChainLookup(virStorageSourcePtr chain,
virStorageSourcePtr startFrom,
const char *name,
unsigned int idx,
virStorageSourcePtr *parent)
{
virStorageSourcePtr prev;
const char *start = chain->path;
char *parentDir = NULL;
bool nameIsFile = virStorageIsFile(name);
if (!parent)
parent = &prev;
*parent = NULL;
if (startFrom) {
while (virStorageSourceIsBacking(chain) &&
chain != startFrom->backingStore)
chain = chain->backingStore;
*parent = startFrom;
}
while (virStorageSourceIsBacking(chain)) {
if (!name && !idx) {
if (!virStorageSourceHasBacking(chain))
break;
} else if (idx) {
VIR_DEBUG("%u: %s", chain->id, chain->path);
if (idx == chain->id)
break;
} else {
if (STREQ_NULLABLE(name, chain->relPath) ||
STREQ_NULLABLE(name, chain->path))
break;
if (nameIsFile && virStorageSourceIsLocalStorage(chain)) {
if (*parent && virStorageSourceIsLocalStorage(*parent))
parentDir = g_path_get_dirname((*parent)->path);
else
parentDir = g_strdup(".");
int result = virFileRelLinkPointsTo(parentDir, name,
chain->path);
VIR_FREE(parentDir);
if (result < 0)
goto error;
if (result > 0)
break;
}
}
*parent = chain;
chain = chain->backingStore;
}
if (!virStorageSourceIsBacking(chain))
goto error;
return chain;
error:
if (idx) {
virReportError(VIR_ERR_INVALID_ARG,
_("could not find backing store index %u in chain "
"for '%s'"),
idx, NULLSTR(start));
} else if (name) {
blockcommit: require base below top The block commit code looks for an explicit base file relative to the discovered top file; so for a chain of: base <- snap1 <- snap2 <- snap3 and a command of: virsh blockcommit $dom vda --base snap2 --top snap1 we got a sane message (here from libvirt 1.0.5): error: invalid argument: could not find base 'snap2' below 'snap1' in chain for 'vda' Meanwhile, recent refactoring has slightly reduced the quality of the libvirt error messages, by losing the phrase 'below xyz': error: invalid argument: could not find image 'snap2' in chain for 'snap3' But we had a one-off, where we were not excluding the top file itself in searching for the base; thankfully qemu still reports the error, but the quality is worse: virsh blockcommit $dom vda --base snap2 --top snap2 error: internal error unable to execute QEMU command 'block-commit': Base '/snap2' not found Fix the one-off in blockcommit by changing the semantics of name lookup - if a starting point is specified, then the result must be below that point, rather than including that point. The only other call to chain lookup was blockpull code, which was already forcing the lookup to omit the active layer and only needs a tweak to use the new semantics. This also fixes the bug exposed in the testsuite, where when doing a lookup pinned to an intermediate point in the chain, we were unable to return the name of the parent also in the chain. * src/util/virstoragefile.c (virStorageFileChainLookup): Change semantics for non-NULL startFrom. * src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Adjust caller, to keep existing semantics. * tests/virstoragetest.c (mymain): Adjust to expose new semantics. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-06-11 22:22:57 +00:00
if (startFrom)
virReportError(VIR_ERR_INVALID_ARG,
_("could not find image '%s' beneath '%s' in "
"chain for '%s'"), name, NULLSTR(startFrom->path),
NULLSTR(start));
blockcommit: require base below top The block commit code looks for an explicit base file relative to the discovered top file; so for a chain of: base <- snap1 <- snap2 <- snap3 and a command of: virsh blockcommit $dom vda --base snap2 --top snap1 we got a sane message (here from libvirt 1.0.5): error: invalid argument: could not find base 'snap2' below 'snap1' in chain for 'vda' Meanwhile, recent refactoring has slightly reduced the quality of the libvirt error messages, by losing the phrase 'below xyz': error: invalid argument: could not find image 'snap2' in chain for 'snap3' But we had a one-off, where we were not excluding the top file itself in searching for the base; thankfully qemu still reports the error, but the quality is worse: virsh blockcommit $dom vda --base snap2 --top snap2 error: internal error unable to execute QEMU command 'block-commit': Base '/snap2' not found Fix the one-off in blockcommit by changing the semantics of name lookup - if a starting point is specified, then the result must be below that point, rather than including that point. The only other call to chain lookup was blockpull code, which was already forcing the lookup to omit the active layer and only needs a tweak to use the new semantics. This also fixes the bug exposed in the testsuite, where when doing a lookup pinned to an intermediate point in the chain, we were unable to return the name of the parent also in the chain. * src/util/virstoragefile.c (virStorageFileChainLookup): Change semantics for non-NULL startFrom. * src/qemu/qemu_driver.c (qemuDomainBlockJobImpl): Adjust caller, to keep existing semantics. * tests/virstoragetest.c (mymain): Adjust to expose new semantics. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-06-11 22:22:57 +00:00
else
virReportError(VIR_ERR_INVALID_ARG,
_("could not find image '%s' in chain for '%s'"),
name, NULLSTR(start));
} else {
virReportError(VIR_ERR_INVALID_ARG,
_("could not find base image in chain for '%s'"),
NULLSTR(start));
}
*parent = NULL;
return NULL;
}
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
void
virStorageNetHostDefClear(virStorageNetHostDefPtr def)
{
if (!def)
return;
VIR_FREE(def->name);
VIR_FREE(def->socket);
}
void
virStorageNetHostDefFree(size_t nhosts,
virStorageNetHostDefPtr hosts)
{
size_t i;
if (!hosts)
return;
for (i = 0; i < nhosts; i++)
virStorageNetHostDefClear(&hosts[i]);
VIR_FREE(hosts);
}
static void
virStoragePermsFree(virStoragePermsPtr def)
{
if (!def)
return;
VIR_FREE(def->label);
VIR_FREE(def);
}
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
virStorageNetHostDefPtr
virStorageNetHostDefCopy(size_t nhosts,
virStorageNetHostDefPtr hosts)
{
virStorageNetHostDefPtr ret = NULL;
size_t i;
if (VIR_ALLOC_N(ret, nhosts) < 0)
goto error;
for (i = 0; i < nhosts; i++) {
virStorageNetHostDefPtr src = &hosts[i];
virStorageNetHostDefPtr dst = &ret[i];
dst->transport = src->transport;
dst->port = src->port;
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
dst->name = g_strdup(src->name);
dst->socket = g_strdup(src->socket);
conf: split network host structs to util/ Continuing the refactoring of host-side storage descriptions out of conf/domain_conf and into util/virstoragefile, this patch focuses on details about a host name/port/transport as used by a network storage volume. * src/conf/domain_conf.h (virDomainDiskProtocolTransport) (virDomainDiskHostDef, virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): Move... * src/util/virstoragefile.h (virStorageNetHostTransport) (virStorageNetHostDef, virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): ...here, with better names. * src/util/virstoragefile.c (virStorageNetHostDefClear) (virStorageNetHostDefFree, virStorageNetHostDefCopy): Moved from... * src/conf/domain_conf.c (virDomainDiskHostDefClear) (virDomainDiskHostDefFree, virDomainDiskHostDefCopy): ...here. (virDomainDiskSourceDefClear, virDomainDiskSourceDefParse) (virDomainDiskSourceDefFormatInternal): Adjust callers. * src/conf/snapshot_conf.h (_virDomainSnapshotDiskDef): Likewise. * src/conf/snapshot_conf.c (virDomainSnapshotDiskDefClear): Likewise. * src/qemu/qemu_command.c (qemuAddRBDHost) (qemuParseDriveURIString, qemuParseNBDString) (qemuBuildNetworkDriveURI, qemuParseCommandLineDisk) (qemuParseCommandLine, qemuGetDriveSourceString): Likewise. * src/qemu/qemu_command.h: Likewise. * src/qemu/qemu_conf.c (qemuAddISCSIPoolSourceHost) (qemuTranslateDiskSourcePool): Likewise. * src/qemu/qemu_driver.c (qemuDomainSnapshotCreateSingleDiskActive) (qemuDomainSnapshotUndoSingleDiskActive): Likewise. * src/storage/storage_backend_gluster.c (virStorageFileBackendGlusterInit): Likewise. * src/storage/storage_driver.c (virStorageFileFree) (virStorageFileInitInternal): Likewise. * src/storage/storage_driver.h (_virStorageFile): Likewise. * src/libvirt_private.syms (domain_conf.h): Move symbols... (virstoragefile.h): ...as appropriate. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-03-26 22:33:08 +00:00
}
return ret;
error:
virStorageNetHostDefFree(nhosts, ret);
return NULL;
}
void
virStorageAuthDefFree(virStorageAuthDefPtr authdef)
{
if (!authdef)
return;
VIR_FREE(authdef->username);
VIR_FREE(authdef->secrettype);
virSecretLookupDefClear(&authdef->seclookupdef);
VIR_FREE(authdef);
}
virStorageAuthDefPtr
virStorageAuthDefCopy(const virStorageAuthDef *src)
{
g_autoptr(virStorageAuthDef) authdef = NULL;
if (VIR_ALLOC(authdef) < 0)
return NULL;
authdef->username = g_strdup(src->username);
/* Not present for storage pool, but used for disk source */
authdef->secrettype = g_strdup(src->secrettype);
authdef->authType = src->authType;
if (virSecretLookupDefCopy(&authdef->seclookupdef, &src->seclookupdef) < 0)
return NULL;
return g_steal_pointer(&authdef);
}
virStorageAuthDefPtr
virStorageAuthDefParse(xmlNodePtr node,
xmlXPathContextPtr ctxt)
{
xmlNodePtr saveNode = ctxt->node;
virStorageAuthDefPtr ret = NULL;
xmlNodePtr secretnode = NULL;
g_autoptr(virStorageAuthDef) authdef = NULL;
g_autofree char *authtype = NULL;
ctxt->node = node;
if (VIR_ALLOC(authdef) < 0)
goto cleanup;
if (!(authdef->username = virXPathString("string(./@username)", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing username for auth"));
goto cleanup;
}
authdef->authType = VIR_STORAGE_AUTH_TYPE_NONE;
authtype = virXPathString("string(./@type)", ctxt);
if (authtype) {
/* Used by the storage pool instead of the secret type field
* to define whether chap or ceph being used
*/
if ((authdef->authType = virStorageAuthTypeFromString(authtype)) < 0) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unknown auth type '%s'"), authtype);
goto cleanup;
}
}
if (!(secretnode = virXPathNode("./secret ", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing <secret> element in auth"));
goto cleanup;
}
/* Used by the domain disk xml parsing in order to ensure the
* <secret type='%s' value matches the expected secret type for
* the style of disk (iscsi is chap, nbd is ceph). For some reason
* the virSecretUsageType{From|To}String() cannot be linked here
* and because only the domain parsing code cares - just keep
* it as a string.
*/
authdef->secrettype = virXMLPropString(secretnode, "type");
if (virSecretLookupParseSecret(secretnode, &authdef->seclookupdef) < 0)
goto cleanup;
ret = g_steal_pointer(&authdef);
cleanup:
ctxt->node = saveNode;
return ret;
}
void
virStorageAuthDefFormat(virBufferPtr buf,
virStorageAuthDefPtr authdef)
{
if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) {
virBufferEscapeString(buf, "<auth username='%s'>\n", authdef->username);
} else {
virBufferAsprintf(buf, "<auth type='%s' ",
virStorageAuthTypeToString(authdef->authType));
virBufferEscapeString(buf, "username='%s'>\n", authdef->username);
}
virBufferAdjustIndent(buf, 2);
virSecretLookupFormatSecret(buf, authdef->secrettype,
&authdef->seclookupdef);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</auth>\n");
}
void
virStoragePRDefFree(virStoragePRDefPtr prd)
{
if (!prd)
return;
VIR_FREE(prd->path);
VIR_FREE(prd->mgralias);
VIR_FREE(prd);
}
virStoragePRDefPtr
virStoragePRDefParseXML(xmlXPathContextPtr ctxt)
{
virStoragePRDefPtr prd;
virStoragePRDefPtr ret = NULL;
g_autofree char *managed = NULL;
g_autofree char *type = NULL;
g_autofree char *path = NULL;
g_autofree char *mode = NULL;
if (VIR_ALLOC(prd) < 0)
return NULL;
if (!(managed = virXPathString("string(./@managed)", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing @managed attribute for <reservations/>"));
goto cleanup;
}
if ((prd->managed = virTristateBoolTypeFromString(managed)) <= 0) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid value for 'managed': %s"), managed);
goto cleanup;
}
type = virXPathString("string(./source[1]/@type)", ctxt);
path = virXPathString("string(./source[1]/@path)", ctxt);
mode = virXPathString("string(./source[1]/@mode)", ctxt);
if (prd->managed == VIR_TRISTATE_BOOL_NO || type || path || mode) {
if (!type) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing connection type for <reservations/>"));
goto cleanup;
}
if (!path) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing path for <reservations/>"));
goto cleanup;
}
if (!mode) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing connection mode for <reservations/>"));
goto cleanup;
}
}
if (type && STRNEQ(type, "unix")) {
virReportError(VIR_ERR_XML_ERROR,
_("unsupported connection type for <reservations/>: %s"),
type);
goto cleanup;
}
if (mode && STRNEQ(mode, "client")) {
virReportError(VIR_ERR_XML_ERROR,
_("unsupported connection mode for <reservations/>: %s"),
mode);
goto cleanup;
}
prd->path = g_steal_pointer(&path);
ret = g_steal_pointer(&prd);
cleanup:
virStoragePRDefFree(prd);
return ret;
}
void
virStoragePRDefFormat(virBufferPtr buf,
virStoragePRDefPtr prd,
bool migratable)
{
virBufferAsprintf(buf, "<reservations managed='%s'",
virTristateBoolTypeToString(prd->managed));
if (prd->path &&
(prd->managed == VIR_TRISTATE_BOOL_NO || !migratable)) {
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
virBufferAddLit(buf, "<source type='unix'");
virBufferEscapeString(buf, " path='%s'", prd->path);
virBufferAddLit(buf, " mode='client'/>\n");
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</reservations>\n");
} else {
virBufferAddLit(buf, "/>\n");
}
}
bool
virStoragePRDefIsEqual(virStoragePRDefPtr a,
virStoragePRDefPtr b)
{
if (!a && !b)
return true;
if (!a || !b)
return false;
if (a->managed != b->managed ||
STRNEQ_NULLABLE(a->path, b->path))
return false;
return true;
}
bool
virStoragePRDefIsManaged(virStoragePRDefPtr prd)
{
return prd && prd->managed == VIR_TRISTATE_BOOL_YES;
}
bool
virStorageSourceChainHasManagedPR(virStorageSourcePtr src)
{
virStorageSourcePtr n;
for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
if (virStoragePRDefIsManaged(n->pr))
return true;
}
return false;
}
static virStoragePRDefPtr
virStoragePRDefCopy(virStoragePRDefPtr src)
{
virStoragePRDefPtr copy = NULL;
virStoragePRDefPtr ret = NULL;
if (VIR_ALLOC(copy) < 0)
return NULL;
copy->managed = src->managed;
copy->path = g_strdup(src->path);
copy->mgralias = g_strdup(src->mgralias);
ret = g_steal_pointer(&copy);
virStoragePRDefFree(copy);
return ret;
}
static virStorageSourceNVMeDefPtr
virStorageSourceNVMeDefCopy(const virStorageSourceNVMeDef *src)
{
virStorageSourceNVMeDefPtr ret = NULL;
ret = g_new0(virStorageSourceNVMeDef, 1);
ret->namespace = src->namespace;
ret->managed = src->managed;
virPCIDeviceAddressCopy(&ret->pciAddr, &src->pciAddr);
return ret;
}
static bool
virStorageSourceNVMeDefIsEqual(const virStorageSourceNVMeDef *a,
const virStorageSourceNVMeDef *b)
{
if (!a && !b)
return true;
if (!a || !b)
return false;
if (a->namespace != b->namespace ||
a->managed != b->managed ||
!virPCIDeviceAddressEqual(&a->pciAddr, &b->pciAddr))
return false;
return true;
}
void
virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def)
{
if (!def)
return;
VIR_FREE(def);
}
bool
virStorageSourceChainHasNVMe(const virStorageSource *src)
{
const virStorageSource *n;
for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
if (n->type == VIR_STORAGE_TYPE_NVME)
return true;
}
return false;
}
virSecurityDeviceLabelDefPtr
virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src,
const char *model)
{
size_t i;
for (i = 0; i < src->nseclabels; i++) {
if (STREQ_NULLABLE(src->seclabels[i]->model, model))
return src->seclabels[i];
}
return NULL;
}
static void
virStorageSourceSeclabelsClear(virStorageSourcePtr def)
{
size_t i;
if (def->seclabels) {
for (i = 0; i < def->nseclabels; i++)
virSecurityDeviceLabelDefFree(def->seclabels[i]);
VIR_FREE(def->seclabels);
}
}
static int
virStorageSourceSeclabelsCopy(virStorageSourcePtr to,
const virStorageSource *from)
{
size_t i;
if (from->nseclabels == 0)
return 0;
if (VIR_ALLOC_N(to->seclabels, from->nseclabels) < 0)
return -1;
to->nseclabels = from->nseclabels;
for (i = 0; i < to->nseclabels; i++) {
if (!(to->seclabels[i] = virSecurityDeviceLabelDefCopy(from->seclabels[i])))
goto error;
}
return 0;
error:
virStorageSourceSeclabelsClear(to);
return -1;
}
static virStorageTimestampsPtr
virStorageTimestampsCopy(const virStorageTimestamps *src)
{
virStorageTimestampsPtr ret;
if (VIR_ALLOC(ret) < 0)
return NULL;
memcpy(ret, src, sizeof(*src));
return ret;
}
static virStoragePermsPtr
virStoragePermsCopy(const virStoragePerms *src)
{
virStoragePermsPtr ret;
if (VIR_ALLOC(ret) < 0)
return NULL;
ret->mode = src->mode;
ret->uid = src->uid;
ret->gid = src->gid;
ret->label = g_strdup(src->label);
return ret;
}
static virStorageSourcePoolDefPtr
virStorageSourcePoolDefCopy(const virStorageSourcePoolDef *src)
{
virStorageSourcePoolDefPtr ret;
if (VIR_ALLOC(ret) < 0)
return NULL;
ret->voltype = src->voltype;
ret->pooltype = src->pooltype;
ret->actualtype = src->actualtype;
ret->mode = src->mode;
ret->pool = g_strdup(src->pool);
ret->volume = g_strdup(src->volume);
return ret;
}
static virStorageSourceSlicePtr
virStorageSourceSliceCopy(const virStorageSourceSlice *src)
{
virStorageSourceSlicePtr ret = g_new0(virStorageSourceSlice, 1);
ret->offset = src->offset;
ret->size = src->size;
ret->nodename = g_strdup(src->nodename);
return ret;
}
static void
virStorageSourceSliceFree(virStorageSourceSlicePtr slice)
{
if (!slice)
return;
g_free(slice->nodename);
g_free(slice);
}
/**
* virStorageSourcePtr:
*
* Deep-copies a virStorageSource structure. If @backing chain is true
* then also copies the backing chain recursively, otherwise just
* the top element is copied. This function doesn't copy the
* storage driver access structure and thus the struct needs to be initialized
* separately.
*/
virStorageSourcePtr
virStorageSourceCopy(const virStorageSource *src,
bool backingChain)
{
g_autoptr(virStorageSource) def = NULL;
if (!(def = virStorageSourceNew()))
return NULL;
def->id = src->id;
def->type = src->type;
def->protocol = src->protocol;
def->format = src->format;
def->capacity = src->capacity;
def->allocation = src->allocation;
def->has_allocation = src->has_allocation;
def->physical = src->physical;
def->readonly = src->readonly;
def->shared = src->shared;
def->haveTLS = src->haveTLS;
def->tlsFromConfig = src->tlsFromConfig;
def->detected = src->detected;
def->debugLevel = src->debugLevel;
def->debug = src->debug;
def->iomode = src->iomode;
def->cachemode = src->cachemode;
def->discard = src->discard;
def->detect_zeroes = src->detect_zeroes;
/* storage driver metadata are not copied */
def->drv = NULL;
def->path = g_strdup(src->path);
def->volume = g_strdup(src->volume);
def->relPath = g_strdup(src->relPath);
def->backingStoreRaw = g_strdup(src->backingStoreRaw);
def->externalDataStoreRaw = g_strdup(src->externalDataStoreRaw);
def->snapshot = g_strdup(src->snapshot);
def->configFile = g_strdup(src->configFile);
def->nodeformat = g_strdup(src->nodeformat);
def->nodestorage = g_strdup(src->nodestorage);
def->compat = g_strdup(src->compat);
def->tlsAlias = g_strdup(src->tlsAlias);
def->tlsCertdir = g_strdup(src->tlsCertdir);
if (src->sliceStorage)
def->sliceStorage = virStorageSourceSliceCopy(src->sliceStorage);
if (src->nhosts) {
if (!(def->hosts = virStorageNetHostDefCopy(src->nhosts, src->hosts)))
return NULL;
def->nhosts = src->nhosts;
}
if (src->srcpool &&
!(def->srcpool = virStorageSourcePoolDefCopy(src->srcpool)))
return NULL;
if (src->features &&
!(def->features = virBitmapNewCopy(src->features)))
return NULL;
if (src->encryption &&
!(def->encryption = virStorageEncryptionCopy(src->encryption)))
return NULL;
if (src->perms &&
!(def->perms = virStoragePermsCopy(src->perms)))
return NULL;
if (src->timestamps &&
!(def->timestamps = virStorageTimestampsCopy(src->timestamps)))
return NULL;
if (virStorageSourceSeclabelsCopy(def, src) < 0)
return NULL;
if (src->auth &&
!(def->auth = virStorageAuthDefCopy(src->auth)))
return NULL;
if (src->pr &&
!(def->pr = virStoragePRDefCopy(src->pr)))
return NULL;
if (src->nvme)
def->nvme = virStorageSourceNVMeDefCopy(src->nvme);
if (virStorageSourceInitiatorCopy(&def->initiator, &src->initiator) < 0)
return NULL;
if (backingChain && src->backingStore) {
if (!(def->backingStore = virStorageSourceCopy(src->backingStore,
true)))
return NULL;
}
if (src->externalDataStore) {
if (!(def->externalDataStore = virStorageSourceCopy(src->externalDataStore,
true)))
return NULL;
}
return g_steal_pointer(&def);
}
/**
* virStorageSourceIsSameLocation:
*
* Returns true if the sources @a and @b point to the same storage location.
* This does not compare any other configuration option
*/
bool
virStorageSourceIsSameLocation(virStorageSourcePtr a,
virStorageSourcePtr b)
{
size_t i;
/* there are multiple possibilities to define an empty source */
if (virStorageSourceIsEmpty(a) &&
virStorageSourceIsEmpty(b))
return true;
if (virStorageSourceGetActualType(a) != virStorageSourceGetActualType(b))
return false;
if (STRNEQ_NULLABLE(a->path, b->path) ||
STRNEQ_NULLABLE(a->volume, b->volume) ||
STRNEQ_NULLABLE(a->snapshot, b->snapshot))
return false;
if (a->type == VIR_STORAGE_TYPE_NETWORK) {
if (a->protocol != b->protocol ||
a->nhosts != b->nhosts)
return false;
for (i = 0; i < a->nhosts; i++) {
if (a->hosts[i].transport != b->hosts[i].transport ||
a->hosts[i].port != b->hosts[i].port ||
STRNEQ_NULLABLE(a->hosts[i].name, b->hosts[i].name) ||
STRNEQ_NULLABLE(a->hosts[i].socket, b->hosts[i].socket))
return false;
}
}
if (a->type == VIR_STORAGE_TYPE_NVME &&
!virStorageSourceNVMeDefIsEqual(a->nvme, b->nvme))
return false;
return true;
}
/**
* virStorageSourceInitChainElement:
* @newelem: New backing chain element disk source
* @old: Existing top level disk source
* @transferLabels: Transfer security labels.
*
* Transfers relevant information from the existing disk source to the new
* backing chain element if they weren't supplied so that labelling info
* and possibly other stuff is correct.
*
* If @transferLabels is true, security labels from the existing disk are copied
* to the new disk. Otherwise the default domain imagelabel label will be used.
*
* Returns 0 on success, -1 on error.
*/
int
virStorageSourceInitChainElement(virStorageSourcePtr newelem,
virStorageSourcePtr old,
bool transferLabels)
{
if (transferLabels &&
!newelem->seclabels &&
virStorageSourceSeclabelsCopy(newelem, old) < 0)
return -1;
newelem->shared = old->shared;
newelem->readonly = old->readonly;
return 0;
}
void
virStorageSourcePoolDefFree(virStorageSourcePoolDefPtr def)
{
if (!def)
return;
VIR_FREE(def->pool);
VIR_FREE(def->volume);
VIR_FREE(def);
}
/**
* virStorageSourceGetActualType:
* @def: storage source definition
*
* Returns type of @def. In case when the type is VIR_STORAGE_TYPE_VOLUME
* and virDomainDiskTranslateSourcePool was called on @def the actual type
* of the storage volume is returned rather than VIR_STORAGE_TYPE_VOLUME.
*/
int
virStorageSourceGetActualType(const virStorageSource *def)
{
if (def->type == VIR_STORAGE_TYPE_VOLUME &&
def->srcpool &&
def->srcpool->actualtype != VIR_STORAGE_TYPE_NONE)
return def->srcpool->actualtype;
return def->type;
}
bool
virStorageSourceIsLocalStorage(const virStorageSource *src)
{
virStorageType type = virStorageSourceGetActualType(src);
switch (type) {
case VIR_STORAGE_TYPE_FILE:
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_DIR:
return true;
case VIR_STORAGE_TYPE_NETWORK:
case VIR_STORAGE_TYPE_VOLUME:
/* While NVMe disks are local, they are not accessible via src->path.
* Therefore, we have to return false here. */
case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_LAST:
case VIR_STORAGE_TYPE_NONE:
return false;
}
return false;
}
/**
* virStorageSourceIsEmpty:
*
* @src: disk source to check
*
* Returns true if the guest disk has no associated host storage source
* (such as an empty cdrom drive).
*/
bool
virStorageSourceIsEmpty(virStorageSourcePtr src)
{
if (virStorageSourceIsLocalStorage(src) && !src->path)
return true;
if (src->type == VIR_STORAGE_TYPE_NONE)
return true;
if (src->type == VIR_STORAGE_TYPE_NETWORK &&
src->protocol == VIR_STORAGE_NET_PROTOCOL_NONE)
return true;
return false;
}
/**
* virStorageSourceIsBlockLocal:
* @src: disk source definition
*
* Returns true if @src describes a locally accessible block storage source.
* This includes block devices and host-mapped iSCSI volumes.
*/
bool
virStorageSourceIsBlockLocal(const virStorageSource *src)
{
return virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_BLOCK;
}
/**
* virStorageSourceBackingStoreClear:
*
* @src: disk source to clear
*
* Clears information about backing store of the current storage file.
*/
void
virStorageSourceBackingStoreClear(virStorageSourcePtr def)
{
if (!def)
return;
VIR_FREE(def->relPath);
VIR_FREE(def->backingStoreRaw);
/* recursively free backing chain */
virObjectUnref(def->backingStore);
def->backingStore = NULL;
}
void
virStorageSourceClear(virStorageSourcePtr def)
{
if (!def)
return;
VIR_FREE(def->path);
VIR_FREE(def->volume);
VIR_FREE(def->snapshot);
VIR_FREE(def->configFile);
virStorageSourcePoolDefFree(def->srcpool);
virBitmapFree(def->features);
VIR_FREE(def->compat);
virStorageEncryptionFree(def->encryption);
virStoragePRDefFree(def->pr);
virStorageSourceNVMeDefFree(def->nvme);
virStorageSourceSeclabelsClear(def);
virStoragePermsFree(def->perms);
VIR_FREE(def->timestamps);
VIR_FREE(def->externalDataStoreRaw);
virStorageSourceSliceFree(def->sliceStorage);
virObjectUnref(def->externalDataStore);
def->externalDataStore = NULL;
virStorageNetHostDefFree(def->nhosts, def->hosts);
virStorageAuthDefFree(def->auth);
virObjectUnref(def->privateData);
VIR_FREE(def->nodestorage);
VIR_FREE(def->nodeformat);
virStorageSourceBackingStoreClear(def);
VIR_FREE(def->tlsAlias);
VIR_FREE(def->tlsCertdir);
virStorageSourceInitiatorClear(&def->initiator);
/* clear everything except the class header as the object APIs
* will break otherwise */
memset((char *) def + sizeof(def->parent), 0,
sizeof(*def) - sizeof(def->parent));
}
static void
virStorageSourceDispose(void *obj)
{
virStorageSourcePtr src = obj;
virStorageSourceClear(src);
}
static int
virStorageSourceOnceInit(void)
{
if (!VIR_CLASS_NEW(virStorageSource, virClassForObject()))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virStorageSource);
virStorageSourcePtr
virStorageSourceNew(void)
{
if (virStorageSourceInitialize() < 0)
return NULL;
return virObjectNew(virStorageSourceClass);
}
static virStorageSourcePtr
virStorageSourceNewFromBackingRelative(virStorageSourcePtr parent,
const char *rel)
{
g_autofree char *dirname = NULL;
g_autoptr(virStorageSource) def = NULL;
if (!(def = virStorageSourceNew()))
return NULL;
/* store relative name */
def->relPath = g_strdup(rel);
dirname = g_path_get_dirname(parent->path);
if (STRNEQ(dirname, "/")) {
def->path = g_strdup_printf("%s/%s", dirname, rel);
} else {
def->path = g_strdup_printf("/%s", rel);
}
if (virStorageSourceGetActualType(parent) == VIR_STORAGE_TYPE_NETWORK) {
def->type = VIR_STORAGE_TYPE_NETWORK;
/* copy the host network part */
def->protocol = parent->protocol;
if (parent->nhosts) {
if (!(def->hosts = virStorageNetHostDefCopy(parent->nhosts,
parent->hosts)))
return NULL;
def->nhosts = parent->nhosts;
}
def->volume = g_strdup(parent->volume);
} else {
/* set the type to _FILE, the caller shall update it to the actual type */
def->type = VIR_STORAGE_TYPE_FILE;
}
return g_steal_pointer(&def);
}
static int
virStorageSourceParseBackingURI(virStorageSourcePtr src,
const char *uristr)
{
g_autoptr(virURI) uri = NULL;
const char *path = NULL;
VIR_AUTOSTRINGLIST scheme = NULL;
if (!(uri = virURIParse(uristr))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("failed to parse backing file location '%s'"),
uristr);
return -1;
}
if (VIR_ALLOC(src->hosts) < 0)
return -1;
src->nhosts = 1;
if (!(scheme = virStringSplit(uri->scheme, "+", 2)))
return -1;
if (!scheme[0] ||
(src->protocol = virStorageNetProtocolTypeFromString(scheme[0])) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid backing protocol '%s'"),
NULLSTR(scheme[0]));
return -1;
}
if (scheme[1] &&
(src->hosts->transport = virStorageNetHostTransportTypeFromString(scheme[1])) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid protocol transport type '%s'"),
scheme[1]);
return -1;
}
/* handle socket stored as a query */
if (uri->query)
src->hosts->socket = g_strdup(STRSKIP(uri->query, "socket="));
/* uri->path is NULL if the URI does not contain slash after host:
* transport://host:port */
if (uri->path)
path = uri->path;
else
path = "";
/* possibly skip the leading slash */
if (path[0] == '/')
path++;
/* NBD allows empty export name (path) */
if (src->protocol == VIR_STORAGE_NET_PROTOCOL_NBD &&
path[0] == '\0')
path = NULL;
src->path = g_strdup(path);
if (src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) {
char *tmp;
if (!src->path) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("missing volume name and path for gluster volume"));
return -1;
}
if (!(tmp = strchr(src->path, '/')) ||
tmp == src->path) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("missing volume name or file name in "
"gluster source path '%s'"), src->path);
return -1;
}
src->volume = src->path;
src->path = g_strdup(tmp + 1);
tmp[0] = '\0';
}
src->hosts->port = uri->port;
src->hosts->name = g_strdup(uri->server);
/* Libvirt doesn't handle inline authentication. Make the caller aware. */
if (uri->user)
return 1;
return 0;
}
static int
virStorageSourceRBDAddHost(virStorageSourcePtr src,
char *hostport)
{
char *port;
size_t skip;
VIR_AUTOSTRINGLIST parts = NULL;
if (VIR_EXPAND_N(src->hosts, src->nhosts, 1) < 0)
return -1;
if ((port = strchr(hostport, ']'))) {
/* ipv6, strip brackets */
hostport += 1;
skip = 3;
} else {
port = strstr(hostport, "\\:");
skip = 2;
}
if (port) {
*port = '\0';
port += skip;
if (virStringParsePort(port, &src->hosts[src->nhosts - 1].port) < 0)
goto error;
}
parts = virStringSplit(hostport, "\\:", 0);
if (!parts)
goto error;
src->hosts[src->nhosts-1].name = virStringListJoin((const char **)parts, ":");
if (!src->hosts[src->nhosts-1].name)
goto error;
src->hosts[src->nhosts-1].transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
src->hosts[src->nhosts-1].socket = NULL;
return 0;
error:
VIR_FREE(src->hosts[src->nhosts-1].name);
return -1;
}
int
virStorageSourceParseRBDColonString(const char *rbdstr,
virStorageSourcePtr src)
{
char *p, *e, *next;
g_autofree char *options = NULL;
g_autoptr(virStorageAuthDef) authdef = NULL;
/* optionally skip the "rbd:" prefix if provided */
if (STRPREFIX(rbdstr, "rbd:"))
rbdstr += strlen("rbd:");
src->path = g_strdup(rbdstr);
p = strchr(src->path, ':');
if (p) {
options = g_strdup(p + 1);
*p = '\0';
}
/* snapshot name */
if ((p = strchr(src->path, '@'))) {
src->snapshot = g_strdup(p + 1);
*p = '\0';
}
/* pool vs. image name */
if ((p = strchr(src->path, '/'))) {
src->volume = g_steal_pointer(&src->path);
src->path = g_strdup(p + 1);
*p = '\0';
}
/* options */
if (!options)
return 0; /* all done */
p = options;
while (*p) {
/* find : delimiter or end of string */
for (e = p; *e && *e != ':'; ++e) {
if (*e == '\\') {
e++;
if (*e == '\0')
break;
}
}
if (*e == '\0') {
next = e; /* last kv pair */
} else {
next = e + 1;
*e = '\0';
}
if (STRPREFIX(p, "id=")) {
/* formulate authdef for src->auth */
if (src->auth) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("duplicate 'id' found in '%s'"), src->path);
return -1;
}
if (VIR_ALLOC(authdef) < 0)
return -1;
authdef->username = g_strdup(p + strlen("id="));
authdef->secrettype = g_strdup(virSecretUsageTypeToString(VIR_SECRET_USAGE_TYPE_CEPH));
src->auth = g_steal_pointer(&authdef);
src->authInherited = true;
/* Cannot formulate a secretType (eg, usage or uuid) given
* what is provided.
*/
}
if (STRPREFIX(p, "mon_host=")) {
char *h, *sep;
h = p + strlen("mon_host=");
while (h < e) {
for (sep = h; sep < e; ++sep) {
if (*sep == '\\' && (sep[1] == ',' ||
sep[1] == ';' ||
sep[1] == ' ')) {
*sep = '\0';
sep += 2;
break;
}
}
if (virStorageSourceRBDAddHost(src, h) < 0)
return -1;
h = sep;
}
}
if (STRPREFIX(p, "conf="))
src->configFile = g_strdup(p + strlen("conf="));
p = next;
}
return 0;
}
static int
virStorageSourceParseNBDColonString(const char *nbdstr,
virStorageSourcePtr src)
{
VIR_AUTOSTRINGLIST backing = NULL;
const char *exportname;
if (!(backing = virStringSplit(nbdstr, ":", 0)))
return -1;
/* we know that backing[0] now equals to "nbd" */
if (VIR_ALLOC_N(src->hosts, 1) < 0)
return -1;
src->nhosts = 1;
src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
/* format: [] denotes optional sections, uppercase are variable strings
* nbd:unix:/PATH/TO/SOCKET[:exportname=EXPORTNAME]
* nbd:HOSTNAME:PORT[:exportname=EXPORTNAME]
*/
if (!backing[1]) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing remote information in '%s' for protocol nbd"),
nbdstr);
return -1;
} else if (STREQ(backing[1], "unix")) {
if (!backing[2]) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing unix socket path in nbd backing string %s"),
nbdstr);
return -1;
}
src->hosts->socket = g_strdup(backing[2]);
src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX;
} else {
src->hosts->name = g_strdup(backing[1]);
if (!backing[2]) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing port in nbd string '%s'"),
nbdstr);
return -1;
}
if (virStringParsePort(backing[2], &src->hosts->port) < 0)
return -1;
}
if ((exportname = strstr(nbdstr, "exportname="))) {
exportname += strlen("exportname=");
src->path = g_strdup(exportname);
}
return 0;
}
static int
virStorageSourceParseBackingColon(virStorageSourcePtr src,
const char *path)
{
const char *p;
g_autofree char *protocol = NULL;
if (!(p = strchr(path, ':'))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid backing protocol string '%s'"),
path);
return -1;
}
protocol = g_strndup(path, p - path);
if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("invalid backing protocol '%s'"),
protocol);
return -1;
}
switch ((virStorageNetProtocol) src->protocol) {
case VIR_STORAGE_NET_PROTOCOL_NBD:
if (virStorageSourceParseNBDColonString(path, src) < 0)
return -1;
break;
case VIR_STORAGE_NET_PROTOCOL_RBD:
if (virStorageSourceParseRBDColonString(path, src) < 0)
return -1;
break;
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
case VIR_STORAGE_NET_PROTOCOL_LAST:
case VIR_STORAGE_NET_PROTOCOL_NONE:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store parser is not implemented for protocol %s"),
protocol);
return -1;
case VIR_STORAGE_NET_PROTOCOL_HTTP:
case VIR_STORAGE_NET_PROTOCOL_HTTPS:
case VIR_STORAGE_NET_PROTOCOL_FTP:
case VIR_STORAGE_NET_PROTOCOL_FTPS:
case VIR_STORAGE_NET_PROTOCOL_TFTP:
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
case VIR_STORAGE_NET_PROTOCOL_SSH:
case VIR_STORAGE_NET_PROTOCOL_VXHS:
virReportError(VIR_ERR_INTERNAL_ERROR,
_("malformed backing store path for protocol %s"),
protocol);
return -1;
}
return 0;
}
static int
virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr,
bool allowformat);
static int
virStorageSourceParseBackingJSONPath(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int type)
{
const char *path;
if (!(path = virJSONValueObjectGetString(json, "filename"))) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'filename' field in JSON backing volume "
"definition"));
return -1;
}
src->path = g_strdup(path);
src->type = type;
return 0;
}
static int
virStorageSourceParseBackingJSONUriStr(virStorageSourcePtr src,
const char *uri,
int protocol)
{
int rc;
if ((rc = virStorageSourceParseBackingURI(src, uri)) < 0)
return -1;
if (src->protocol != protocol) {
virReportError(VIR_ERR_INVALID_ARG,
_("expected protocol '%s' but got '%s' in URI JSON volume "
"definition"),
virStorageNetProtocolTypeToString(protocol),
virStorageNetProtocolTypeToString(src->protocol));
return -1;
}
return rc;
}
static int
virStorageSourceParseBackingJSONUri(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int protocol)
{
const char *uri;
if (!(uri = virJSONValueObjectGetString(json, "url"))) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'url' in JSON backing volume definition"));
return -1;
}
return virStorageSourceParseBackingJSONUriStr(src, uri, protocol);
}
static int
virStorageSourceParseBackingJSONInetSocketAddress(virStorageNetHostDefPtr host,
virJSONValuePtr json)
{
const char *hostname;
const char *port;
if (!json) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing remote server specification in JSON "
"backing volume definition"));
return -1;
}
hostname = virJSONValueObjectGetString(json, "host");
port = virJSONValueObjectGetString(json, "port");
if (!hostname) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing hostname for tcp backing server in "
"JSON backing volume definition"));
return -1;
}
host->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
host->name = g_strdup(hostname);
if (virStringParsePort(port, &host->port) < 0)
return -1;
return 0;
}
static int
virStorageSourceParseBackingJSONSocketAddress(virStorageNetHostDefPtr host,
virJSONValuePtr json)
{
const char *type;
const char *socket;
if (!json) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing remote server specification in JSON "
"backing volume definition"));
return -1;
}
if (!(type = virJSONValueObjectGetString(json, "type"))) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing socket address type in "
"JSON backing volume definition"));
return -1;
}
if (STREQ(type, "tcp") || STREQ(type, "inet")) {
return virStorageSourceParseBackingJSONInetSocketAddress(host, json);
} else if (STREQ(type, "unix")) {
host->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX;
socket = virJSONValueObjectGetString(json, "path");
/* check for old spelling for gluster protocol */
if (!socket)
socket = virJSONValueObjectGetString(json, "socket");
if (!socket) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing socket path for udp backing server in "
"JSON backing volume definition"));
return -1;
}
host->socket = g_strdup(socket);
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store protocol '%s' is not yet supported"),
type);
return -1;
}
return 0;
}
static int
virStorageSourceParseBackingJSONGluster(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *uri = virJSONValueObjectGetString(json, "filename");
const char *volume = virJSONValueObjectGetString(json, "volume");
const char *path = virJSONValueObjectGetString(json, "path");
virJSONValuePtr server = virJSONValueObjectGetArray(json, "server");
size_t nservers;
size_t i;
/* legacy URI based syntax passed via 'filename' option */
if (uri)
return virStorageSourceParseBackingJSONUriStr(src, uri,
VIR_STORAGE_NET_PROTOCOL_GLUSTER);
if (!volume || !path || !server) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'volume', 'path' or 'server' attribute in "
"JSON backing definition for gluster volume"));
return -1;
}
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_GLUSTER;
src->volume = g_strdup(volume);
src->path = g_strdup(path);
nservers = virJSONValueArraySize(server);
if (nservers == 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("at least 1 server is necessary in "
"JSON backing definition for gluster volume"));
return -1;
}
if (VIR_ALLOC_N(src->hosts, nservers) < 0)
return -1;
src->nhosts = nservers;
for (i = 0; i < nservers; i++) {
if (virStorageSourceParseBackingJSONSocketAddress(src->hosts + i,
virJSONValueArrayGet(server, i)) < 0)
return -1;
}
return 0;
}
static int
virStorageSourceParseBackingJSONiSCSI(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *transport = virJSONValueObjectGetString(json, "transport");
const char *portal = virJSONValueObjectGetString(json, "portal");
const char *target = virJSONValueObjectGetString(json, "target");
const char *lun = virJSONValueObjectGetStringOrNumber(json, "lun");
const char *uri;
char *port;
/* legacy URI based syntax passed via 'filename' option */
if ((uri = virJSONValueObjectGetString(json, "filename")))
return virStorageSourceParseBackingJSONUriStr(src, uri,
VIR_STORAGE_NET_PROTOCOL_ISCSI);
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_ISCSI;
if (!lun)
lun = "0";
if (VIR_ALLOC(src->hosts) < 0)
return -1;
src->nhosts = 1;
if (STRNEQ_NULLABLE(transport, "tcp")) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("only TCP transport is supported for iSCSI volumes"));
return -1;
}
src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
if (!portal) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'portal' address in iSCSI backing definition"));
return -1;
}
if (!target) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'target' in iSCSI backing definition"));
return -1;
}
src->hosts->name = g_strdup(portal);
if ((port = strrchr(src->hosts->name, ':')) &&
!strchr(port, ']')) {
if (virStringParsePort(port + 1, &src->hosts->port) < 0)
return -1;
*port = '\0';
}
src->path = g_strdup_printf("%s/%s", target, lun);
/* Libvirt doesn't handle inline authentication. Make the caller aware. */
if (virJSONValueObjectGetString(json, "user") ||
virJSONValueObjectGetString(json, "password"))
return 1;
return 0;
}
static int
virStorageSourceParseBackingJSONNbd(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *path = virJSONValueObjectGetString(json, "path");
const char *host = virJSONValueObjectGetString(json, "host");
const char *port = virJSONValueObjectGetString(json, "port");
const char *export = virJSONValueObjectGetString(json, "export");
virJSONValuePtr server = virJSONValueObjectGetObject(json, "server");
if (!path && !host && !server) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing host specification of NBD server in JSON "
"backing volume definition"));
return -1;
}
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_NBD;
src->path = g_strdup(export);
if (VIR_ALLOC_N(src->hosts, 1) < 0)
return -1;
src->nhosts = 1;
if (server) {
if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0)
return -1;
} else {
if (path) {
src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_UNIX;
src->hosts[0].socket = g_strdup(path);
} else {
src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
src->hosts[0].name = g_strdup(host);
if (virStringParsePort(port, &src->hosts[0].port) < 0)
return -1;
}
}
return 0;
}
static int
virStorageSourceParseBackingJSONSheepdog(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *filename;
const char *vdi = virJSONValueObjectGetString(json, "vdi");
virJSONValuePtr server = virJSONValueObjectGetObject(json, "server");
/* legacy URI based syntax passed via 'filename' option */
if ((filename = virJSONValueObjectGetString(json, "filename"))) {
if (strstr(filename, "://"))
return virStorageSourceParseBackingJSONUriStr(src, filename,
VIR_STORAGE_NET_PROTOCOL_SHEEPDOG);
/* libvirt doesn't implement a parser for the legacy non-URI syntax */
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing sheepdog URI in JSON backing volume definition"));
return -1;
}
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_SHEEPDOG;
if (!vdi) {
virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing sheepdog vdi name"));
return -1;
}
src->path = g_strdup(vdi);
if (VIR_ALLOC(src->hosts) < 0)
return -1;
src->nhosts = 1;
if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0)
return -1;
return 0;
}
static int
virStorageSourceParseBackingJSONSSH(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *path = virJSONValueObjectGetString(json, "path");
const char *host = virJSONValueObjectGetString(json, "host");
const char *port = virJSONValueObjectGetString(json, "port");
virJSONValuePtr server = virJSONValueObjectGetObject(json, "server");
if (!(host || server) || !path) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing host/server or path of SSH JSON backing "
"volume definition"));
return -1;
}
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_SSH;
src->path = g_strdup(path);
if (VIR_ALLOC_N(src->hosts, 1) < 0)
return -1;
src->nhosts = 1;
if (server) {
if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts,
server) < 0)
return -1;
} else {
src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP;
src->hosts[0].name = g_strdup(host);
if (virStringParsePort(port, &src->hosts[0].port) < 0)
return -1;
}
return 0;
}
static int
virStorageSourceParseBackingJSONRBD(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *filename;
const char *pool = virJSONValueObjectGetString(json, "pool");
const char *image = virJSONValueObjectGetString(json, "image");
const char *conf = virJSONValueObjectGetString(json, "conf");
const char *snapshot = virJSONValueObjectGetString(json, "snapshot");
virJSONValuePtr servers = virJSONValueObjectGetArray(json, "server");
size_t nservers;
size_t i;
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_RBD;
/* legacy syntax passed via 'filename' option */
if ((filename = virJSONValueObjectGetString(json, "filename")))
return virStorageSourceParseRBDColonString(filename, src);
if (!pool || !image) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing pool or image name in ceph backing volume "
"JSON specification"));
return -1;
}
src->volume = g_strdup(pool);
src->path = g_strdup(image);
src->snapshot = g_strdup(snapshot);
src->configFile = g_strdup(conf);
if (servers) {
nservers = virJSONValueArraySize(servers);
if (VIR_ALLOC_N(src->hosts, nservers) < 0)
return -1;
src->nhosts = nservers;
for (i = 0; i < nservers; i++) {
if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i,
virJSONValueArrayGet(servers, i)) < 0)
return -1;
}
}
return 0;
}
static int
virStorageSourceParseBackingJSONRaw(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr,
int opaque G_GNUC_UNUSED)
{
bool has_offset = virJSONValueObjectHasKey(json, "offset");
bool has_size = virJSONValueObjectHasKey(json, "size");
virJSONValuePtr file;
if (has_offset || has_size) {
src->sliceStorage = g_new0(virStorageSourceSlice, 1);
if (has_offset &&
virJSONValueObjectGetNumberUlong(json, "offset", &src->sliceStorage->offset) < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("malformed 'offset' property of 'raw' driver"));
return -1;
}
if (has_size &&
virJSONValueObjectGetNumberUlong(json, "size", &src->sliceStorage->size) < 0) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("malformed 'size' property of 'raw' driver"));
return -1;
}
}
/* 'raw' is a format driver so it can have protocol driver children */
if (!(file = virJSONValueObjectGetObject(json, "file"))) {
virReportError(VIR_ERR_INVALID_ARG,
_("JSON backing volume definition '%s' lacks 'file' object"),
jsonstr);
return -1;
}
return virStorageSourceParseBackingJSONInternal(src, file, jsonstr, false);
}
static int
virStorageSourceParseBackingJSONVxHS(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr G_GNUC_UNUSED,
int opaque G_GNUC_UNUSED)
{
const char *vdisk_id = virJSONValueObjectGetString(json, "vdisk-id");
virJSONValuePtr server = virJSONValueObjectGetObject(json, "server");
if (!vdisk_id || !server) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("missing 'vdisk-id' or 'server' attribute in "
"JSON backing definition for VxHS volume"));
return -1;
}
src->type = VIR_STORAGE_TYPE_NETWORK;
src->protocol = VIR_STORAGE_NET_PROTOCOL_VXHS;
src->path = g_strdup(vdisk_id);
if (VIR_ALLOC_N(src->hosts, 1) < 0)
return -1;
src->nhosts = 1;
if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts,
server) < 0)
return -1;
return 0;
}
struct virStorageSourceJSONDriverParser {
const char *drvname;
bool formatdriver;
/**
* The callback gets a pre-allocated storage source @src and the JSON
* object to parse. The callback shall return -1 on error and report error
* 0 on success and 1 in cases when the configuration itself is valid, but
* can't be converted to libvirt's configuration (e.g. inline authentication
* credentials are present).
*/
int (*func)(virStorageSourcePtr src, virJSONValuePtr json, const char *jsonstr, int opaque);
int opaque;
};
static const struct virStorageSourceJSONDriverParser jsonParsers[] = {
{"file", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_FILE},
{"host_device", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK},
{"host_cdrom", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK},
{"http", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTP},
{"https", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTPS},
{"ftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTP},
{"ftps", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTPS},
{"tftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_TFTP},
{"gluster", false, virStorageSourceParseBackingJSONGluster, 0},
{"iscsi", false, virStorageSourceParseBackingJSONiSCSI, 0},
{"nbd", false, virStorageSourceParseBackingJSONNbd, 0},
{"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0},
{"ssh", false, virStorageSourceParseBackingJSONSSH, 0},
{"rbd", false, virStorageSourceParseBackingJSONRBD, 0},
{"raw", true, virStorageSourceParseBackingJSONRaw, 0},
{"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0},
};
static int
virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src,
virJSONValuePtr json,
const char *jsonstr,
bool allowformat)
{
const char *drvname;
size_t i;
if (!(drvname = virJSONValueObjectGetString(json, "driver"))) {
virReportError(VIR_ERR_INVALID_ARG,
_("JSON backing volume definition '%s' lacks driver name"),
jsonstr);
return -1;
}
for (i = 0; i < G_N_ELEMENTS(jsonParsers); i++) {
if (STRNEQ(drvname, jsonParsers[i].drvname))
continue;
if (jsonParsers[i].formatdriver && !allowformat) {
virReportError(VIR_ERR_INVALID_ARG,
_("JSON backing volume definition '%s' must not have nested format drivers"),
jsonstr);
return -1;
}
return jsonParsers[i].func(src, json, jsonstr, jsonParsers[i].opaque);
}
virReportError(VIR_ERR_INTERNAL_ERROR,
_("missing parser implementation for JSON backing volume "
"driver '%s'"), drvname);
return -1;
}
static int
virStorageSourceParseBackingJSON(virStorageSourcePtr src,
const char *json)
{
g_autoptr(virJSONValue) root = NULL;
g_autoptr(virJSONValue) deflattened = NULL;
virJSONValuePtr file = NULL;
if (!(root = virJSONValueFromString(json)))
return -1;
if (!(deflattened = virJSONValueObjectDeflatten(root)))
return -1;
/* There are 2 possible syntaxes:
* 1) json:{"file":{"driver":...}}
* 2) json:{"driver":...}
* Remove the 'file' wrapper object in case 1.
*/
if (!virJSONValueObjectHasKey(deflattened, "driver"))
file = virJSONValueObjectGetObject(deflattened, "file");
if (!file)
file = deflattened;
return virStorageSourceParseBackingJSONInternal(src, file, json, true);
}
/**
* virStorageSourceNewFromBackingAbsolute
* @path: string representing absolute location of a storage source
* @src: filled with virStorageSource object representing @path
*
* Returns 0 on success, 1 if we could parse all location data but @path
* specified other data unrepresentable by libvirt (e.g. inline authentication).
* In both cases @src is filled. On error -1 is returned @src is NULL and an
* error is reported.
*/
int
virStorageSourceNewFromBackingAbsolute(const char *path,
virStorageSourcePtr *src)
{
const char *json;
int rc = 0;
g_autoptr(virStorageSource) def = NULL;
*src = NULL;
if (!(def = virStorageSourceNew()))
return -1;
if (virStorageIsFile(path)) {
def->type = VIR_STORAGE_TYPE_FILE;
def->path = g_strdup(path);
} else {
def->type = VIR_STORAGE_TYPE_NETWORK;
VIR_DEBUG("parsing backing store string: '%s'", path);
/* handle URI formatted backing stores */
if ((json = STRSKIP(path, "json:")))
rc = virStorageSourceParseBackingJSON(def, json);
else if (strstr(path, "://"))
rc = virStorageSourceParseBackingURI(def, path);
else
rc = virStorageSourceParseBackingColon(def, path);
if (rc < 0)
return -1;
virStorageSourceNetworkAssignDefaultPorts(def);
/* Some of the legacy parsers parse authentication data since they are
* also used in other places. For backing store detection the
* authentication data would be invalid anyways, so we clear it */
if (def->auth) {
virStorageAuthDefFree(def->auth);
def->auth = NULL;
}
}
*src = g_steal_pointer(&def);
return rc;
}
/**
* virStorageSourceNewFromChild:
* @parent: storage source parent
* @child: returned child/backing store definition
* @parentRaw: raw child string (backingStoreRaw)
*
* Creates a storage source which describes the backing image of @parent and
* fills it into @backing depending on the passed parentRaw (backingStoreRaw)
* and other data. Note that for local storage this function accesses the file
* to update the actual type of the child store.
*
* Returns 0 on success, 1 if we could parse all location data but the child
* store specification contained other data unrepresentable by libvirt (e.g.
* inline authentication).
* In both cases @src is filled. On error -1 is returned @src is NULL and an
* error is reported.
*/
static int
virStorageSourceNewFromChild(virStorageSourcePtr parent,
const char *parentRaw,
virStorageSourcePtr *child)
{
struct stat st;
g_autoptr(virStorageSource) def = NULL;
int rc = 0;
*child = NULL;
if (virStorageIsRelative(parentRaw)) {
if (!(def = virStorageSourceNewFromBackingRelative(parent, parentRaw)))
return -1;
} else {
if ((rc = virStorageSourceNewFromBackingAbsolute(parentRaw, &def)) < 0)
return -1;
}
/* possibly update local type */
if (def->type == VIR_STORAGE_TYPE_FILE) {
if (stat(def->path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
def->type = VIR_STORAGE_TYPE_DIR;
def->format = VIR_STORAGE_FILE_DIR;
} else if (S_ISBLK(st.st_mode)) {
def->type = VIR_STORAGE_TYPE_BLOCK;
}
}
}
/* copy parent's labelling and other top level stuff */
if (virStorageSourceInitChainElement(def, parent, true) < 0)
return -1;
def->detected = true;
*child = g_steal_pointer(&def);
return rc;
}
int
virStorageSourceNewFromBacking(virStorageSourcePtr parent,
virStorageSourcePtr *backing)
{
int rc;
if ((rc = virStorageSourceNewFromChild(parent,
parent->backingStoreRaw,
backing)) < 0)
return rc;
(*backing)->readonly = true;
return rc;
}
static int
virStorageSourceNewFromExternalData(virStorageSourcePtr parent,
virStorageSourcePtr *externalDataStore)
{
int rc;
if ((rc = virStorageSourceNewFromChild(parent,
parent->externalDataStoreRaw,
externalDataStore)) < 0)
return rc;
/* qcow2 data_file can only be raw */
(*externalDataStore)->format = VIR_STORAGE_FILE_RAW;
(*externalDataStore)->readonly = parent->readonly;
return rc;
}
/**
* @src: disk source definition structure
* @fd: file descriptor
* @sb: stat buffer
*
* Updates src->physical depending on the actual type of storage being used.
* To be called for domain storage source reporting as the volume code does
* not set/use the 'type' field for the voldef->source.target
*
* Returns 0 on success, -1 on error. No libvirt errors are reported.
*/
int
virStorageSourceUpdatePhysicalSize(virStorageSourcePtr src,
int fd,
struct stat const *sb)
{
off_t end;
virStorageType actual_type = virStorageSourceGetActualType(src);
switch (actual_type) {
case VIR_STORAGE_TYPE_FILE:
case VIR_STORAGE_TYPE_NETWORK:
src->physical = sb->st_size;
break;
case VIR_STORAGE_TYPE_BLOCK:
if ((end = lseek(fd, 0, SEEK_END)) == (off_t) -1)
return -1;
src->physical = end;
break;
case VIR_STORAGE_TYPE_DIR:
src->physical = 0;
break;
/* We shouldn't get VOLUME, but the switch requires all cases */
case VIR_STORAGE_TYPE_VOLUME:
case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
return -1;
}
return 0;
}
/**
* @src: disk source definition structure
* @fd: file descriptor
* @sb: stat buffer
*
* Update the capacity, allocation, physical values for the storage @src
* Shared between the domain storage source for an inactive domain and the
* voldef source target as the result is not affected by the 'type' field.
*
* Returns 0 on success, -1 on error.
*/
int
virStorageSourceUpdateBackingSizes(virStorageSourcePtr src,
int fd,
struct stat const *sb)
{
/* Get info for normal formats */
if (S_ISREG(sb->st_mode) || fd == -1) {
#ifndef WIN32
src->allocation = (unsigned long long)sb->st_blocks *
(unsigned long long)DEV_BSIZE;
#else
src->allocation = sb->st_size;
#endif
/* Regular files may be sparse, so logical size (capacity) is not same
* as actual allocation above
*/
src->capacity = sb->st_size;
/* Allocation tracks when the file is sparse, physical is the
* last offset of the file. */
src->physical = sb->st_size;
} else if (S_ISDIR(sb->st_mode)) {
src->allocation = 0;
src->capacity = 0;
src->physical = 0;
} else if (fd >= 0) {
off_t end;
/* XXX this is POSIX compliant, but doesn't work for CHAR files,
* only BLOCK. There is a Linux specific ioctl() for getting
* size of both CHAR / BLOCK devices we should check for in
* configure
*
* NB. Because we configure with AC_SYS_LARGEFILE, off_t
* should be 64 bits on all platforms. For block devices, we
* have to seek (safe even if someone else is writing) to
* determine physical size, and assume that allocation is the
* same as physical (but can refine that assumption later if
* qemu is still running).
*/
if ((end = lseek(fd, 0, SEEK_END)) == (off_t)-1) {
virReportSystemError(errno,
_("failed to seek to end of %s"), src->path);
return -1;
}
src->physical = end;
src->allocation = end;
src->capacity = end;
}
return 0;
}
/**
* @src: disk source definition structure
* @buf: buffer to the storage file header
* @len: length of the storage file header
* @probe: allow probe
*
* Update the storage @src capacity. This may involve probing the storage
* @src in order to "see" if we can recognize what exists.
*
* Returns 0 on success, -1 on error.
*/
int
virStorageSourceUpdateCapacity(virStorageSourcePtr src,
char *buf,
ssize_t len,
bool probe)
{
int format = src->format;
g_autoptr(virStorageSource) meta = NULL;
/* Raw files: capacity is physical size. For all other files: if
* the metadata has a capacity, use that, otherwise fall back to
* physical size. */
if (format == VIR_STORAGE_FILE_NONE) {
if (!probe) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("no disk format for %s and probing is disabled"),
src->path);
return -1;
}
if ((format = virStorageFileProbeFormatFromBuf(src->path,
buf, len)) < 0)
return -1;
src->format = format;
}
if (format == VIR_STORAGE_FILE_RAW && !src->encryption) {
src->capacity = src->physical;
} else if ((meta = virStorageFileGetMetadataFromBuf(src->path, buf,
len, format, NULL))) {
src->capacity = meta->capacity ? meta->capacity : src->physical;
if (src->encryption && meta->encryption)
src->encryption->payload_offset = meta->encryption->payload_offset;
} else {
return -1;
}
if (src->encryption && src->encryption->payload_offset != -1)
src->capacity -= src->encryption->payload_offset * 512;
return 0;
}
static char *
virStorageFileCanonicalizeFormatPath(char **components,
size_t ncomponents,
bool beginSlash,
bool beginDoubleSlash)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
size_t i;
char *ret = NULL;
if (beginSlash)
virBufferAddLit(&buf, "/");
if (beginDoubleSlash)
virBufferAddLit(&buf, "/");
for (i = 0; i < ncomponents; i++) {
if (i != 0)
virBufferAddLit(&buf, "/");
virBufferAdd(&buf, components[i], -1);
}
/* if the output string is empty just return an empty string */
if (!(ret = virBufferContentAndReset(&buf)))
ret = g_strdup("");
return ret;
}
static int
virStorageFileCanonicalizeInjectSymlink(const char *path,
size_t at,
char ***components,
size_t *ncomponents)
{
char **tmp = NULL;
char **next;
size_t ntmp = 0;
int ret = -1;
if (!(tmp = virStringSplitCount(path, "/", 0, &ntmp)))
goto cleanup;
/* prepend */
for (next = tmp; *next; next++) {
if (VIR_INSERT_ELEMENT(*components, at, *ncomponents, *next) < 0)
goto cleanup;
at++;
}
ret = 0;
cleanup:
virStringListFreeCount(tmp, ntmp);
return ret;
}
char *
virStorageFileCanonicalizePath(const char *path,
virStorageFileSimplifyPathReadlinkCallback cb,
void *cbdata)
{
virHashTablePtr cycle = NULL;
bool beginSlash = false;
bool beginDoubleSlash = false;
char **components = NULL;
size_t ncomponents = 0;
size_t i = 0;
size_t j = 0;
int rc;
char *ret = NULL;
g_autofree char *linkpath = NULL;
g_autofree char *currentpath = NULL;
if (path[0] == '/') {
beginSlash = true;
if (path[1] == '/' && path[2] != '/')
beginDoubleSlash = true;
}
if (!(cycle = virHashCreate(10, NULL)))
goto cleanup;
if (!(components = virStringSplitCount(path, "/", 0, &ncomponents)))
goto cleanup;
j = 0;
while (j < ncomponents) {
/* skip slashes */
if (STREQ(components[j], "")) {
VIR_FREE(components[j]);
VIR_DELETE_ELEMENT(components, j, ncomponents);
continue;
}
j++;
}
while (i < ncomponents) {
/* skip '.'s unless it's the last one remaining */
if (STREQ(components[i], ".") &&
(beginSlash || ncomponents > 1)) {
VIR_FREE(components[i]);
VIR_DELETE_ELEMENT(components, i, ncomponents);
continue;
}
/* resolve changes to parent directory */
if (STREQ(components[i], "..")) {
if (!beginSlash &&
(i == 0 || STREQ(components[i - 1], ".."))) {
i++;
continue;
}
VIR_FREE(components[i]);
VIR_DELETE_ELEMENT(components, i, ncomponents);
if (i != 0) {
VIR_FREE(components[i - 1]);
VIR_DELETE_ELEMENT(components, i - 1, ncomponents);
i--;
}
continue;
}
/* check if the actual path isn't resulting into a symlink */
if (!(currentpath = virStorageFileCanonicalizeFormatPath(components,
i + 1,
beginSlash,
beginDoubleSlash)))
goto cleanup;
if ((rc = cb(currentpath, &linkpath, cbdata)) < 0)
goto cleanup;
if (rc == 0) {
if (virHashLookup(cycle, currentpath)) {
virReportSystemError(ELOOP,
_("Failed to canonicalize path '%s'"), path);
goto cleanup;
}
if (virHashAddEntry(cycle, currentpath, (void *) 1) < 0)
goto cleanup;
if (linkpath[0] == '/') {
/* kill everything from the beginning including the actual component */
i++;
while (i--) {
VIR_FREE(components[0]);
VIR_DELETE_ELEMENT(components, 0, ncomponents);
}
beginSlash = true;
if (linkpath[1] == '/' && linkpath[2] != '/')
beginDoubleSlash = true;
else
beginDoubleSlash = false;
i = 0;
} else {
VIR_FREE(components[i]);
VIR_DELETE_ELEMENT(components, i, ncomponents);
}
if (virStorageFileCanonicalizeInjectSymlink(linkpath,
i,
&components,
&ncomponents) < 0)
goto cleanup;
j = 0;
while (j < ncomponents) {
/* skip slashes */
if (STREQ(components[j], "")) {
VIR_FREE(components[j]);
VIR_DELETE_ELEMENT(components, j, ncomponents);
continue;
}
j++;
}
VIR_FREE(linkpath);
VIR_FREE(currentpath);
continue;
}
VIR_FREE(currentpath);
i++;
}
ret = virStorageFileCanonicalizeFormatPath(components, ncomponents,
beginSlash, beginDoubleSlash);
cleanup:
virHashFree(cycle);
virStringListFreeCount(components, ncomponents);
return ret;
}
/**
* virStorageFileRemoveLastPathComponent:
*
* @path: Path string to remove the last component from
*
* Removes the last path component of a path. This function is designed to be
* called on file paths only (no trailing slashes in @path). Caller is
* responsible to free the returned string.
*/
static char *
virStorageFileRemoveLastPathComponent(const char *path)
{
char *ret;
ret = g_strdup(NULLSTR_EMPTY(path));
virFileRemoveLastComponent(ret);
return ret;
}
/*
* virStorageFileGetRelativeBackingPath:
*
* Resolve relative path to be written to the overlay of @top image when
* collapsing the backing chain between @top and @base.
*
* Returns 0 on success; 1 if backing chain isn't relative and -1 on error.
*/
int
virStorageFileGetRelativeBackingPath(virStorageSourcePtr top,
virStorageSourcePtr base,
char **relpath)
{
virStorageSourcePtr next;
g_autofree char *tmp = NULL;
g_autofree char *path = NULL;
*relpath = NULL;
for (next = top; virStorageSourceIsBacking(next); next = next->backingStore) {
if (!next->relPath)
return 1;
if (!(tmp = virStorageFileRemoveLastPathComponent(path)))
return -1;
VIR_FREE(path);
path = g_strdup_printf("%s%s", tmp, next->relPath);
VIR_FREE(tmp);
if (next == base)
break;
}
if (next != base) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to resolve relative backing name: "
"base image is not in backing chain"));
return -1;
}
*relpath = g_steal_pointer(&path);
return 0;
}
/*
* virStorageFileCheckCompat
*/
int
virStorageFileCheckCompat(const char *compat)
{
unsigned int result;
VIR_AUTOSTRINGLIST version = NULL;
if (!compat)
return 0;
version = virStringSplit(compat, ".", 2);
if (!version || !version[1] ||
virStrToLong_ui(version[0], NULL, 10, &result) < 0 ||
virStrToLong_ui(version[1], NULL, 10, &result) < 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("forbidden characters in 'compat' attribute"));
return -1;
}
return 0;
}
/**
* virStorageSourceIsRelative:
* @src: storage source to check
*
* Returns true if given storage source definition is a relative path.
*/
bool
virStorageSourceIsRelative(virStorageSourcePtr src)
{
virStorageType actual_type = virStorageSourceGetActualType(src);
if (!src->path)
return false;
switch (actual_type) {
case VIR_STORAGE_TYPE_FILE:
case VIR_STORAGE_TYPE_BLOCK:
case VIR_STORAGE_TYPE_DIR:
return src->path[0] != '/';
case VIR_STORAGE_TYPE_NETWORK:
case VIR_STORAGE_TYPE_VOLUME:
case VIR_STORAGE_TYPE_NVME:
case VIR_STORAGE_TYPE_NONE:
case VIR_STORAGE_TYPE_LAST:
return false;
}
return false;
}
/**
* virStorageSourceFindByNodeName:
* @top: backing chain top
* @nodeName: node name to find in backing chain
* @index: if provided the index in the backing chain
*
* Looks up the given storage source in the backing chain and returns the
* pointer to it. If @index is passed then it's filled by the index in the
* backing chain. On failure NULL is returned and no error is reported.
*/
virStorageSourcePtr
virStorageSourceFindByNodeName(virStorageSourcePtr top,
const char *nodeName,
unsigned int *idx)
{
virStorageSourcePtr tmp;
if (idx)
*idx = 0;
for (tmp = top; virStorageSourceIsBacking(tmp); tmp = tmp->backingStore) {
if ((tmp->nodeformat && STREQ(tmp->nodeformat, nodeName)) ||
(tmp->nodestorage && STREQ(tmp->nodestorage, nodeName)))
return tmp;
if (idx)
(*idx)++;
}
if (idx)
*idx = 0;
return NULL;
}
static unsigned int
virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol)
{
switch (protocol) {
case VIR_STORAGE_NET_PROTOCOL_HTTP:
return 80;
case VIR_STORAGE_NET_PROTOCOL_HTTPS:
return 443;
case VIR_STORAGE_NET_PROTOCOL_FTP:
return 21;
case VIR_STORAGE_NET_PROTOCOL_FTPS:
return 990;
case VIR_STORAGE_NET_PROTOCOL_TFTP:
return 69;
case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
return 7000;
case VIR_STORAGE_NET_PROTOCOL_NBD:
return 10809;
case VIR_STORAGE_NET_PROTOCOL_SSH:
return 22;
case VIR_STORAGE_NET_PROTOCOL_ISCSI:
return 3260;
case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
return 24007;
case VIR_STORAGE_NET_PROTOCOL_RBD:
/* we don't provide a default for RBD */
return 0;
case VIR_STORAGE_NET_PROTOCOL_VXHS:
return 9999;
case VIR_STORAGE_NET_PROTOCOL_LAST:
case VIR_STORAGE_NET_PROTOCOL_NONE:
return 0;
}
return 0;
}
void
virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src)
{
size_t i;
for (i = 0; i < src->nhosts; i++) {
if (src->hosts[i].transport == VIR_STORAGE_NET_HOST_TRANS_TCP &&
src->hosts[i].port == 0)
src->hosts[i].port = virStorageSourceNetworkDefaultPort(src->protocol);
}
}
int
virStorageSourcePrivateDataParseRelPath(xmlXPathContextPtr ctxt,
virStorageSourcePtr src)
{
src->relPath = virXPathString("string(./relPath)", ctxt);
return 0;
}
int
virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src,
virBufferPtr buf)
{
if (src->relPath)
virBufferEscapeString(buf, "<relPath>%s</relPath>\n", src->relPath);
return 0;
}
void
virStorageSourceInitiatorParseXML(xmlXPathContextPtr ctxt,
virStorageSourceInitiatorDefPtr initiator)
{
initiator->iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
}
void
virStorageSourceInitiatorFormatXML(virStorageSourceInitiatorDefPtr initiator,
virBufferPtr buf)
{
if (!initiator->iqn)
return;
virBufferAddLit(buf, "<initiator>\n");
virBufferAdjustIndent(buf, 2);
virBufferEscapeString(buf, "<iqn name='%s'/>\n", initiator->iqn);
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</initiator>\n");
}
int
virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest,
const virStorageSourceInitiatorDef *src)
{
dest->iqn = g_strdup(src->iqn);
return 0;
}
void
virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator)
{
VIR_FREE(initiator->iqn);
}
static bool
virStorageFileIsInitialized(const virStorageSource *src)
{
return src && src->drv;
}
/**
* virStorageFileGetBackendForSupportCheck:
* @src: storage source to check support for
* @backend: pointer to the storage backend for @src if it's supported
*
* Returns 0 if @src is not supported by any storage backend currently linked
* 1 if it is supported and -1 on error with an error reported.
*/
static int
virStorageFileGetBackendForSupportCheck(const virStorageSource *src,
virStorageFileBackendPtr *backend)
{
int actualType;
if (!src) {
*backend = NULL;
return 0;
}
if (src->drv) {
*backend = src->drv->backend;
return 1;
}
actualType = virStorageSourceGetActualType(src);
if (virStorageFileBackendForType(actualType, src->protocol, false, backend) < 0)
return -1;
if (!*backend)
return 0;
return 1;
}
int
virStorageFileSupportsBackingChainTraversal(const virStorageSource *src)
{
virStorageFileBackendPtr backend;
int rv;
if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1)
return rv;
return backend->storageFileGetUniqueIdentifier &&
backend->storageFileRead &&
backend->storageFileAccess ? 1 : 0;
}
/**
* virStorageFileSupportsSecurityDriver:
*
* @src: a storage file structure
*
* Check if a storage file supports operations needed by the security
* driver to perform labelling
*/
int
virStorageFileSupportsSecurityDriver(const virStorageSource *src)
{
virStorageFileBackendPtr backend;
int rv;
if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1)
return rv;
return backend->storageFileChown ? 1 : 0;
}
/**
* virStorageFileSupportsAccess:
*
* @src: a storage file structure
*
* Check if a storage file supports checking if the storage source is accessible
* for the given vm.
*/
int
virStorageFileSupportsAccess(const virStorageSource *src)
{
virStorageFileBackendPtr backend;
int rv;
if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1)
return rv;
return backend->storageFileAccess ? 1 : 0;
}
/**
* virStorageFileSupportsCreate:
* @src: a storage file structure
*
* Check if the storage driver supports creating storage described by @src
* via virStorageFileCreate.
*/
int
virStorageFileSupportsCreate(const virStorageSource *src)
{
virStorageFileBackendPtr backend;
int rv;
if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1)
return rv;
return backend->storageFileCreate ? 1 : 0;
}
void
virStorageFileDeinit(virStorageSourcePtr src)
{
if (!virStorageFileIsInitialized(src))
return;
if (src->drv->backend &&
src->drv->backend->backendDeinit)
src->drv->backend->backendDeinit(src);
VIR_FREE(src->drv);
}
/**
* virStorageFileInitAs:
*
* @src: storage source definition
* @uid: uid used to access the file, or -1 for current uid
* @gid: gid used to access the file, or -1 for current gid
*
* Initialize a storage source to be used with storage driver. Use the provided
* uid and gid if possible for the operations.
*
* Returns 0 if the storage file was successfully initialized, -1 if the
* initialization failed. Libvirt error is reported.
*/
int
virStorageFileInitAs(virStorageSourcePtr src,
uid_t uid, gid_t gid)
{
int actualType = virStorageSourceGetActualType(src);
if (VIR_ALLOC(src->drv) < 0)
return -1;
if (uid == (uid_t) -1)
src->drv->uid = geteuid();
else
src->drv->uid = uid;
if (gid == (gid_t) -1)
src->drv->gid = getegid();
else
src->drv->gid = gid;
if (virStorageFileBackendForType(actualType,
src->protocol,
true,
&src->drv->backend) < 0)
goto error;
if (src->drv->backend->backendInit &&
src->drv->backend->backendInit(src) < 0)
goto error;
return 0;
error:
VIR_FREE(src->drv);
return -1;
}
/**
* virStorageFileInit:
*
* See virStorageFileInitAs. The file is initialized to be accessed by the
* current user.
*/
int
virStorageFileInit(virStorageSourcePtr src)
{
return virStorageFileInitAs(src, -1, -1);
}
/**
* virStorageFileCreate: Creates an empty storage file via storage driver
*
* @src: file structure pointing to the file
*
* Returns 0 on success, -2 if the function isn't supported by the backend,
* -1 on other failure. Errno is set in case of failure.
*/
int
virStorageFileCreate(virStorageSourcePtr src)
{
int ret;
if (!virStorageFileIsInitialized(src) ||
!src->drv->backend->storageFileCreate) {
errno = ENOSYS;
return -2;
}
ret = src->drv->backend->storageFileCreate(src);
VIR_DEBUG("created storage file %p: ret=%d, errno=%d",
src, ret, errno);
return ret;
}
/**
* virStorageFileUnlink: Unlink storage file via storage driver
*
* @src: file structure pointing to the file
*
* Unlinks the file described by the @file structure.
*
* Returns 0 on success, -2 if the function isn't supported by the backend,
* -1 on other failure. Errno is set in case of failure.
*/
int
virStorageFileUnlink(virStorageSourcePtr src)
{
int ret;
if (!virStorageFileIsInitialized(src) ||
!src->drv->backend->storageFileUnlink) {
errno = ENOSYS;
return -2;
}
ret = src->drv->backend->storageFileUnlink(src);
VIR_DEBUG("unlinked storage file %p: ret=%d, errno=%d",
src, ret, errno);
return ret;
}
/**
* virStorageFileStat: returns stat struct of a file via storage driver
*
* @src: file structure pointing to the file
* @stat: stat structure to return data
*
* Returns 0 on success, -2 if the function isn't supported by the backend,
* -1 on other failure. Errno is set in case of failure.
*/
int
virStorageFileStat(virStorageSourcePtr src,
struct stat *st)
{
int ret;
if (!virStorageFileIsInitialized(src) ||
!src->drv->backend->storageFileStat) {
errno = ENOSYS;
return -2;
}
ret = src->drv->backend->storageFileStat(src, st);
VIR_DEBUG("stat of storage file %p: ret=%d, errno=%d",
src, ret, errno);
return ret;
}
/**
* virStorageFileRead: read bytes from a file into a buffer
*
* @src: file structure pointing to the file
* @offset: number of bytes to skip in the storage file
* @len: maximum number of bytes read from the storage file
* @buf: buffer to read the data into. (buffer shall be freed by caller)
*
* Returns the count of bytes read on success and -1 on failure, -2 if the
* function isn't supported by the backend.
* Libvirt error is reported on failure.
*/
ssize_t
virStorageFileRead(virStorageSourcePtr src,
size_t offset,
size_t len,
char **buf)
{
ssize_t ret;
if (!virStorageFileIsInitialized(src)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("storage file backend not initialized"));
return -1;
}
if (!src->drv->backend->storageFileRead)
return -2;
ret = src->drv->backend->storageFileRead(src, offset, len, buf);
VIR_DEBUG("read '%zd' bytes from storage '%p' starting at offset '%zu'",
ret, src, offset);
return ret;
}
/*
* virStorageFileGetUniqueIdentifier: Get a unique string describing the volume
*
* @src: file structure pointing to the file
*
* Returns a string uniquely describing a single volume (canonical path).
* The string shall not be freed and is valid until the storage file is
* deinitialized. Returns NULL on error and sets a libvirt error code */
const char *
virStorageFileGetUniqueIdentifier(virStorageSourcePtr src)
{
if (!virStorageFileIsInitialized(src)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("storage file backend not initialized"));
return NULL;
}
if (!src->drv->backend->storageFileGetUniqueIdentifier) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unique storage file identifier not implemented for "
"storage type %s (protocol: %s)'"),
virStorageTypeToString(src->type),
virStorageNetProtocolTypeToString(src->protocol));
return NULL;
}
return src->drv->backend->storageFileGetUniqueIdentifier(src);
}
/**
* virStorageFileAccess: Check accessibility of a storage file
*
* @src: storage file to check access permissions
* @mode: accessibility check options (see man 2 access)
*
* Returns 0 on success, -1 on error and sets errno. No libvirt
* error is reported. Returns -2 if the operation isn't supported
* by libvirt storage backend.
*/
int
virStorageFileAccess(virStorageSourcePtr src,
int mode)
{
if (!virStorageFileIsInitialized(src) ||
!src->drv->backend->storageFileAccess) {
errno = ENOSYS;
return -2;
}
return src->drv->backend->storageFileAccess(src, mode);
}
/**
* virStorageFileChown: Change owner of a storage file
*
* @src: storage file to change owner of
* @uid: new owner id
* @gid: new group id
*
* Returns 0 on success, -1 on error and sets errno. No libvirt
* error is reported. Returns -2 if the operation isn't supported
* by libvirt storage backend.
*/
int
virStorageFileChown(const virStorageSource *src,
uid_t uid,
gid_t gid)
{
if (!virStorageFileIsInitialized(src) ||
!src->drv->backend->storageFileChown) {
errno = ENOSYS;
return -2;
}
VIR_DEBUG("chown of storage file %p to %u:%u",
src, (unsigned int)uid, (unsigned int)gid);
return src->drv->backend->storageFileChown(src, uid, gid);
}
/**
* virStorageFileReportBrokenChain:
*
* @errcode: errno when accessing @src
* @src: inaccessible file in the backing chain of @parent
* @parent: root virStorageSource being checked
*
* Reports the correct error message if @src is missing in the backing chain
* for @parent.
*/
void
virStorageFileReportBrokenChain(int errcode,
virStorageSourcePtr src,
virStorageSourcePtr parent)
{
if (src->drv) {
unsigned int access_user = src->drv->uid;
unsigned int access_group = src->drv->gid;
if (src == parent) {
virReportSystemError(errcode,
_("Cannot access storage file '%s' "
"(as uid:%u, gid:%u)"),
src->path, access_user, access_group);
} else {
virReportSystemError(errcode,
_("Cannot access backing file '%s' "
"of storage file '%s' (as uid:%u, gid:%u)"),
src->path, parent->path, access_user, access_group);
}
} else {
if (src == parent) {
virReportSystemError(errcode,
_("Cannot access storage file '%s'"),
src->path);
} else {
virReportSystemError(errcode,
_("Cannot access backing file '%s' "
"of storage file '%s'"),
src->path, parent->path);
}
}
}
static int
virStorageFileGetMetadataRecurseReadHeader(virStorageSourcePtr src,
virStorageSourcePtr parent,
uid_t uid,
gid_t gid,
char **buf,
size_t *headerLen,
virHashTablePtr cycle)
{
int ret = -1;
const char *uniqueName;
ssize_t len;
if (virStorageFileInitAs(src, uid, gid) < 0)
return -1;
if (virStorageFileAccess(src, F_OK) < 0) {
virStorageFileReportBrokenChain(errno, src, parent);
goto cleanup;
}
if (!(uniqueName = virStorageFileGetUniqueIdentifier(src)))
goto cleanup;
if (virHashHasEntry(cycle, uniqueName)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("backing store for %s (%s) is self-referential"),
NULLSTR(src->path), uniqueName);
goto cleanup;
}
if (virHashAddEntry(cycle, uniqueName, NULL) < 0)
goto cleanup;
if ((len = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, buf)) < 0)
goto cleanup;
*headerLen = len;
ret = 0;
cleanup:
virStorageFileDeinit(src);
return ret;
}
/* Recursive workhorse for virStorageFileGetMetadata. */
static int
virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
virStorageSourcePtr parent,
uid_t uid, gid_t gid,
bool report_broken,
virHashTablePtr cycle,
unsigned int depth)
{
int ret = -1;
size_t headerLen;
int backingFormat;
int rv;
g_autofree char *buf = NULL;
g_autoptr(virStorageSource) backingStore = NULL;
VIR_DEBUG("path=%s format=%d uid=%u gid=%u",
NULLSTR(src->path), src->format,
(unsigned int)uid, (unsigned int)gid);
/* exit if we can't load information about the current image */
rv = virStorageFileSupportsBackingChainTraversal(src);
if (rv <= 0)
return rv;
if (virStorageFileGetMetadataRecurseReadHeader(src, parent, uid, gid,
&buf, &headerLen, cycle) < 0)
return -1;
if (virStorageFileGetMetadataInternal(src, buf, headerLen,
&backingFormat) < 0)
goto cleanup;
if (src->backingStoreRaw) {
if ((rv = virStorageSourceNewFromBacking(src, &backingStore)) < 0)
goto cleanup;
if (rv == 1) {
/* the backing file would not be usable for VM usage */
ret = 0;
goto cleanup;
}
backingStore->format = backingFormat;
if (backingStore->format == VIR_STORAGE_FILE_AUTO) {
/* Assuming the backing store to be raw can lead to failures. We do
* it only when we must not report an error to prevent losing VMs.
* Otherwise report an error.
*/
if (report_broken) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("format of backing image '%s' of image '%s' was not specified in the image metadata "
"(See https://libvirt.org/kbase/backing_chains.html for troubleshooting)"),
src->backingStoreRaw, NULLSTR(src->path));
return -1;
}
backingStore->format = VIR_STORAGE_FILE_RAW;
}
if (backingStore->format == VIR_STORAGE_FILE_AUTO_SAFE)
backingStore->format = VIR_STORAGE_FILE_AUTO;
if ((ret = virStorageFileGetMetadataRecurse(backingStore, parent,
uid, gid,
report_broken,
cycle, depth + 1)) < 0) {
if (report_broken)
goto cleanup;
/* if we fail somewhere midway, just accept and return a
* broken chain */
ret = 0;
goto cleanup;
}
backingStore->id = depth;
src->backingStore = g_steal_pointer(&backingStore);
} else {
/* add terminator */
if (!(src->backingStore = virStorageSourceNew()))
goto cleanup;
}
if (src->externalDataStoreRaw) {
g_autoptr(virStorageSource) externalDataStore = NULL;
if ((rv = virStorageSourceNewFromExternalData(src,
&externalDataStore)) < 0)
goto cleanup;
if (rv == 1) {
/* the file would not be usable for VM usage */
ret = 0;
goto cleanup;
}
src->externalDataStore = g_steal_pointer(&externalDataStore);
}
ret = 0;
cleanup:
return ret;
}
/**
* virStorageFileGetMetadata:
*
* Extract metadata about the storage volume with the specified
* image format. If image format is VIR_STORAGE_FILE_AUTO, it
* will probe to automatically identify the format. Recurses through
* the entire chain.
*
* Open files using UID and GID (or pass -1 for the current user/group).
* Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
*
* Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
* format, since a malicious guest can turn a raw file into any
* other non-raw format at will.
*
* If @report_broken is true, the whole function fails with a possibly sane
* error instead of just returning a broken chain. Note that the inability for
* libvirt to traverse a given source is not considered an error.
*
* Caller MUST free result after use via virObjectUnref.
*/
int
virStorageFileGetMetadata(virStorageSourcePtr src,
uid_t uid, gid_t gid,
bool report_broken)
{
VIR_DEBUG("path=%s format=%d uid=%u gid=%u report_broken=%d",
src->path, src->format, (unsigned int)uid, (unsigned int)gid,
report_broken);
virHashTablePtr cycle = NULL;
virStorageType actualType = virStorageSourceGetActualType(src);
int ret = -1;
if (!(cycle = virHashCreate(5, NULL)))
return -1;
if (src->format <= VIR_STORAGE_FILE_NONE) {
if (actualType == VIR_STORAGE_TYPE_DIR)
src->format = VIR_STORAGE_FILE_DIR;
else
src->format = VIR_STORAGE_FILE_RAW;
}
ret = virStorageFileGetMetadataRecurse(src, src, uid, gid,
report_broken, cycle, 1);
virHashFree(cycle);
return ret;
}
/**
* virStorageFileGetBackingStoreStr:
* @src: storage object
*
* Extracts the backing store string as stored in the storage volume described
* by @src and returns it to the user. Caller is responsible for freeing it.
* In case when the string can't be retrieved or does not exist NULL is
* returned.
*/
int
virStorageFileGetBackingStoreStr(virStorageSourcePtr src,
char **backing)
{
ssize_t headerLen;
int rv;
g_autofree char *buf = NULL;
g_autoptr(virStorageSource) tmp = NULL;
*backing = NULL;
/* exit if we can't load information about the current image */
if (!virStorageFileSupportsBackingChainTraversal(src))
return 0;
rv = virStorageFileAccess(src, F_OK);
if (rv == -2)
return 0;
if (rv < 0) {
virStorageFileReportBrokenChain(errno, src, src);
return -1;
}
if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER,
&buf)) < 0) {
if (headerLen == -2)
return 0;
return -1;
}
if (!(tmp = virStorageSourceCopy(src, false)))
return -1;
if (virStorageFileGetMetadataInternal(tmp, buf, headerLen, NULL) < 0)
return -1;
*backing = g_steal_pointer(&tmp->backingStoreRaw);
return 0;
}