mirror of https://gitee.com/openkylin/libvirt.git
snapshot: also support disks by path
I got confused when 'virsh domblkinfo dom disk' required the path to a disk (which can be ambiguous, since a single file can back multiple disks), rather than the unambiguous target device name that I was using in disk snapshots. So, in true developer fashion, I went for the best of both worlds - all interfaces that operate on a disk (aka block) now accept either the target name or the unambiguous path to the backing file used by the disk. * src/conf/domain_conf.h (virDomainDiskIndexByName): Add parameter. (virDomainDiskPathByName): New prototype. * src/libvirt_private.syms (domain_conf.h): Export it. * src/conf/domain_conf.c (virDomainDiskIndexByName): Also allow searching by path, and decide whether ambiguity is okay. (virDomainDiskPathByName): New function. (virDomainDiskRemoveByName, virDomainSnapshotAlignDisks): Update callers. * src/qemu/qemu_driver.c (qemudDomainBlockPeek) (qemuDomainAttachDeviceConfig, qemuDomainUpdateDeviceConfig) (qemuDomainGetBlockInfo, qemuDiskPathToAlias): Likewise. * src/qemu/qemu_process.c (qemuProcessFindDomainDiskByPath): Likewise. * src/libxl/libxl_driver.c (libxlDomainAttachDeviceDiskLive) (libxlDomainDetachDeviceDiskLive, libxlDomainAttachDeviceConfig) (libxlDomainUpdateDeviceConfig): Likewise. * src/uml/uml_driver.c (umlDomainBlockPeek): Likewise. * src/xen/xend_internal.c (xenDaemonDomainBlockPeek): Likewise. * docs/formatsnapshot.html.in: Update documentation. * tools/virsh.pod (domblkstat, domblkinfo): Likewise. * docs/schemas/domaincommon.rng (diskTarget): Tighten pattern on disk targets. * docs/schemas/domainsnapshot.rng (disksnapshot): Update to match. * tests/domainsnapshotxml2xmlin/disk_snapshot.xml: Update test.
This commit is contained in:
parent
d6f6b2d194
commit
89b6284fd9
|
@ -129,8 +129,9 @@
|
||||||
<dt><code>disk</code></dt>
|
<dt><code>disk</code></dt>
|
||||||
<dd>This sub-element describes the snapshot properties of a
|
<dd>This sub-element describes the snapshot properties of a
|
||||||
specific disk. The attribute <code>name</code> is
|
specific disk. The attribute <code>name</code> is
|
||||||
mandatory, and must match the <code><target
|
mandatory, and must match either the <code><target
|
||||||
dev='name'/></code> of one of
|
dev='name'/></code> or an unambiguous <code><source
|
||||||
|
file='name'/></code> of one of
|
||||||
the <a href="formatdomain.html#elementsDisks">disk
|
the <a href="formatdomain.html#elementsDisks">disk
|
||||||
devices</a> specified for the domain at the time of the
|
devices</a> specified for the domain at the time of the
|
||||||
snapshot. The attribute <code>snapshot</code> is
|
snapshot. The attribute <code>snapshot</code> is
|
||||||
|
@ -203,7 +204,7 @@
|
||||||
<domainsnapshot>
|
<domainsnapshot>
|
||||||
<description>Snapshot of OS install and updates</description>
|
<description>Snapshot of OS install and updates</description>
|
||||||
<disks>
|
<disks>
|
||||||
<disk name='vda'>
|
<disk name='/path/to/old'>
|
||||||
<source file='/path/to/new'/>
|
<source file='/path/to/new'/>
|
||||||
</disk>
|
</disk>
|
||||||
<disk name='vdb' snapshot='no'/>
|
<disk name='vdb' snapshot='no'/>
|
||||||
|
|
|
@ -770,10 +770,15 @@
|
||||||
</choice>
|
</choice>
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
<define name="diskTarget">
|
||||||
|
<data type="string">
|
||||||
|
<param name="pattern">(ioemu:)?(fd|hd|sd|vd|xvd|ubd)[a-zA-Z0-9_]+</param>
|
||||||
|
</data>
|
||||||
|
</define>
|
||||||
<define name="target">
|
<define name="target">
|
||||||
<element name="target">
|
<element name="target">
|
||||||
<attribute name="dev">
|
<attribute name="dev">
|
||||||
<ref name="deviceName"/>
|
<ref name="diskTarget"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
<optional>
|
<optional>
|
||||||
<attribute name="bus">
|
<attribute name="bus">
|
||||||
|
|
|
@ -82,7 +82,10 @@
|
||||||
<define name='disksnapshot'>
|
<define name='disksnapshot'>
|
||||||
<element name='disk'>
|
<element name='disk'>
|
||||||
<attribute name='name'>
|
<attribute name='name'>
|
||||||
<ref name='deviceName'/>
|
<choice>
|
||||||
|
<ref name='diskTarget'/>
|
||||||
|
<ref name='absFilePath'/>
|
||||||
|
</choice>
|
||||||
</attribute>
|
</attribute>
|
||||||
<choice>
|
<choice>
|
||||||
<attribute name='snapshot'>
|
<attribute name='snapshot'>
|
||||||
|
|
|
@ -5811,17 +5811,44 @@ virDomainChrTargetTypeToString(int deviceType,
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
int virDomainDiskIndexByName(virDomainDefPtr def, const char *name)
|
int
|
||||||
|
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
|
||||||
|
bool allow_ambiguous)
|
||||||
{
|
{
|
||||||
virDomainDiskDefPtr vdisk;
|
virDomainDiskDefPtr vdisk;
|
||||||
int i;
|
int i;
|
||||||
|
int candidate = -1;
|
||||||
|
|
||||||
|
/* We prefer the <target dev='name'/> name (it's shorter, required
|
||||||
|
* for all disks, and should be unambiguous), but also support
|
||||||
|
* <source file='name'/> (if unambiguous). Assume dst if there is
|
||||||
|
* no leading slash, source name otherwise. */
|
||||||
for (i = 0; i < def->ndisks; i++) {
|
for (i = 0; i < def->ndisks; i++) {
|
||||||
vdisk = def->disks[i];
|
vdisk = def->disks[i];
|
||||||
if (STREQ(vdisk->dst, name))
|
if (*name != '/') {
|
||||||
return i;
|
if (STREQ(vdisk->dst, name))
|
||||||
|
return i;
|
||||||
|
} else if (vdisk->src &&
|
||||||
|
STREQ(vdisk->src, name)) {
|
||||||
|
if (allow_ambiguous)
|
||||||
|
return i;
|
||||||
|
if (candidate >= 0)
|
||||||
|
return -1;
|
||||||
|
candidate = i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the path to a disk image if a string identifies at least one
|
||||||
|
* disk belonging to the domain (both device strings 'vda' and paths
|
||||||
|
* '/path/to/file' are converted into '/path/to/file'). */
|
||||||
|
const char *
|
||||||
|
virDomainDiskPathByName(virDomainDefPtr def, const char *name)
|
||||||
|
{
|
||||||
|
int i = virDomainDiskIndexByName(def, name, true);
|
||||||
|
|
||||||
|
return i < 0 ? NULL : def->disks[i]->src;
|
||||||
}
|
}
|
||||||
|
|
||||||
int virDomainDiskInsert(virDomainDefPtr def,
|
int virDomainDiskInsert(virDomainDefPtr def,
|
||||||
|
@ -5897,7 +5924,7 @@ void virDomainDiskRemove(virDomainDefPtr def, size_t i)
|
||||||
|
|
||||||
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
|
int virDomainDiskRemoveByName(virDomainDefPtr def, const char *name)
|
||||||
{
|
{
|
||||||
int i = virDomainDiskIndexByName(def, name);
|
int i = virDomainDiskIndexByName(def, name, false);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return -1;
|
return -1;
|
||||||
virDomainDiskRemove(def, i);
|
virDomainDiskRemove(def, i);
|
||||||
|
@ -11651,11 +11678,12 @@ disksorter(const void *a, const void *b)
|
||||||
|
|
||||||
/* Align def->disks to def->domain. Sort the list of def->disks,
|
/* Align def->disks to def->domain. Sort the list of def->disks,
|
||||||
* filling in any missing disks or snapshot state defaults given by
|
* filling in any missing disks or snapshot state defaults given by
|
||||||
* the domain, with a fallback to a passed in default. Issue an error
|
* the domain, with a fallback to a passed in default. Convert paths
|
||||||
* and return -1 if any def->disks[n]->name appears more than once or
|
* to disk targets for uniformity. Issue an error and return -1 if
|
||||||
* does not map to dom->disks. If require_match, also require that
|
* any def->disks[n]->name appears more than once or does not map to
|
||||||
* existing def->disks snapshot states do not override explicit
|
* dom->disks. If require_match, also require that existing
|
||||||
* def->dom settings. */
|
* def->disks snapshot states do not override explicit def->dom
|
||||||
|
* settings. */
|
||||||
int
|
int
|
||||||
virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
||||||
int default_snapshot,
|
int default_snapshot,
|
||||||
|
@ -11693,7 +11721,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
||||||
/* Double check requested disks. */
|
/* Double check requested disks. */
|
||||||
for (i = 0; i < def->ndisks; i++) {
|
for (i = 0; i < def->ndisks; i++) {
|
||||||
virDomainSnapshotDiskDefPtr disk = &def->disks[i];
|
virDomainSnapshotDiskDefPtr disk = &def->disks[i];
|
||||||
int idx = virDomainDiskIndexByName(def->dom, disk->name);
|
int idx = virDomainDiskIndexByName(def->dom, disk->name, false);
|
||||||
int disk_snapshot;
|
int disk_snapshot;
|
||||||
|
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
|
@ -11731,6 +11759,13 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
||||||
disk->file, disk->name);
|
disk->file, disk->name);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
if (STRNEQ(disk->name, def->dom->disks[idx]->dst)) {
|
||||||
|
VIR_FREE(disk->name);
|
||||||
|
if (!(disk->name = strdup(def->dom->disks[idx]->dst))) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provide defaults for all remaining disks. */
|
/* Provide defaults for all remaining disks. */
|
||||||
|
|
|
@ -1648,7 +1648,9 @@ int virDomainVcpuPinAdd(virDomainDefPtr def,
|
||||||
|
|
||||||
int virDomainVcpuPinDel(virDomainDefPtr def, int vcpu);
|
int virDomainVcpuPinDel(virDomainDefPtr def, int vcpu);
|
||||||
|
|
||||||
int virDomainDiskIndexByName(virDomainDefPtr def, const char *name);
|
int virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
|
||||||
|
bool allow_ambiguous);
|
||||||
|
const char *virDomainDiskPathByName(virDomainDefPtr, const char *name);
|
||||||
int virDomainDiskInsert(virDomainDefPtr def,
|
int virDomainDiskInsert(virDomainDefPtr def,
|
||||||
virDomainDiskDefPtr disk);
|
virDomainDiskDefPtr disk);
|
||||||
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
|
void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
|
||||||
|
|
|
@ -287,6 +287,7 @@ virDomainDiskInsert;
|
||||||
virDomainDiskInsertPreAlloced;
|
virDomainDiskInsertPreAlloced;
|
||||||
virDomainDiskIoTypeFromString;
|
virDomainDiskIoTypeFromString;
|
||||||
virDomainDiskIoTypeToString;
|
virDomainDiskIoTypeToString;
|
||||||
|
virDomainDiskPathByName;
|
||||||
virDomainDiskRemove;
|
virDomainDiskRemove;
|
||||||
virDomainDiskRemoveByName;
|
virDomainDiskRemoveByName;
|
||||||
virDomainDiskSnapshotTypeFromString;
|
virDomainDiskSnapshotTypeFromString;
|
||||||
|
|
|
@ -2929,7 +2929,7 @@ libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
|
||||||
break;
|
break;
|
||||||
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
||||||
if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
|
if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
|
||||||
if (virDomainDiskIndexByName(vm->def, l_disk->dst) >= 0) {
|
if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
|
||||||
libxlError(VIR_ERR_OPERATION_FAILED,
|
libxlError(VIR_ERR_OPERATION_FAILED,
|
||||||
_("target %s already exists"), l_disk->dst);
|
_("target %s already exists"), l_disk->dst);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -2991,7 +2991,8 @@ libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
|
||||||
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
|
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
|
||||||
|
|
||||||
if ((i = virDomainDiskIndexByName(vm->def,
|
if ((i = virDomainDiskIndexByName(vm->def,
|
||||||
dev->data.disk->dst)) < 0) {
|
dev->data.disk->dst,
|
||||||
|
false)) < 0) {
|
||||||
libxlError(VIR_ERR_OPERATION_FAILED,
|
libxlError(VIR_ERR_OPERATION_FAILED,
|
||||||
_("disk %s not found"), dev->data.disk->dst);
|
_("disk %s not found"), dev->data.disk->dst);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -3061,7 +3062,7 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
|
||||||
switch (dev->type) {
|
switch (dev->type) {
|
||||||
case VIR_DOMAIN_DEVICE_DISK:
|
case VIR_DOMAIN_DEVICE_DISK:
|
||||||
disk = dev->data.disk;
|
disk = dev->data.disk;
|
||||||
if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
|
if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
|
||||||
libxlError(VIR_ERR_INVALID_ARG,
|
libxlError(VIR_ERR_INVALID_ARG,
|
||||||
_("target %s already exists."), disk->dst);
|
_("target %s already exists."), disk->dst);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -3172,9 +3173,9 @@ libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
|
||||||
switch (dev->type) {
|
switch (dev->type) {
|
||||||
case VIR_DOMAIN_DEVICE_DISK:
|
case VIR_DOMAIN_DEVICE_DISK:
|
||||||
disk = dev->data.disk;
|
disk = dev->data.disk;
|
||||||
if ((i = virDomainDiskIndexByName(vmdef, disk->dst)) < 0) {
|
if ((i = virDomainDiskIndexByName(vmdef, disk->dst, false)) < 0) {
|
||||||
libxlError(VIR_ERR_INVALID_ARG,
|
libxlError(VIR_ERR_INVALID_ARG,
|
||||||
_("target %s doesn't exists."), disk->dst);
|
_("target %s doesn't exist."), disk->dst);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
orig = vmdef->disks[i];
|
orig = vmdef->disks[i];
|
||||||
|
|
|
@ -5495,7 +5495,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
|
||||||
switch (dev->type) {
|
switch (dev->type) {
|
||||||
case VIR_DOMAIN_DEVICE_DISK:
|
case VIR_DOMAIN_DEVICE_DISK:
|
||||||
disk = dev->data.disk;
|
disk = dev->data.disk;
|
||||||
if (virDomainDiskIndexByName(vmdef, disk->dst) >= 0) {
|
if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("target %s already exists."), disk->dst);
|
_("target %s already exists."), disk->dst);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -5613,10 +5613,10 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
|
||||||
switch (dev->type) {
|
switch (dev->type) {
|
||||||
case VIR_DOMAIN_DEVICE_DISK:
|
case VIR_DOMAIN_DEVICE_DISK:
|
||||||
disk = dev->data.disk;
|
disk = dev->data.disk;
|
||||||
pos = virDomainDiskIndexByName(vmdef, disk->dst);
|
pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
|
||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("target %s doesn't exists."), disk->dst);
|
_("target %s doesn't exist."), disk->dst);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
orig = vmdef->disks[pos];
|
orig = vmdef->disks[pos];
|
||||||
|
@ -7355,7 +7355,8 @@ qemudDomainBlockPeek (virDomainPtr dom,
|
||||||
{
|
{
|
||||||
struct qemud_driver *driver = dom->conn->privateData;
|
struct qemud_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
int fd = -1, ret = -1, i;
|
int fd = -1, ret = -1;
|
||||||
|
const char *actual;
|
||||||
|
|
||||||
virCheckFlags(0, -1);
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
@ -7377,41 +7378,34 @@ qemudDomainBlockPeek (virDomainPtr dom,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the path belongs to this domain. */
|
/* Check the path belongs to this domain. */
|
||||||
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
if (!(actual = virDomainDiskPathByName(vm->def, path))) {
|
||||||
if (vm->def->disks[i]->src != NULL &&
|
|
||||||
STREQ (vm->def->disks[i]->src, path)) {
|
|
||||||
ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
ret = -1;
|
|
||||||
/* The path is correct, now try to open it and get its size. */
|
|
||||||
fd = open (path, O_RDONLY);
|
|
||||||
if (fd == -1) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("%s: failed to open"), path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Seek and read. */
|
|
||||||
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
|
||||||
* be 64 bits on all platforms.
|
|
||||||
*/
|
|
||||||
if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
|
|
||||||
saferead (fd, buffer, size) == (ssize_t) -1) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("%s: failed to seek or read"), path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
"%s", _("invalid path"));
|
_("invalid path '%s'"), path);
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
path = actual;
|
||||||
|
|
||||||
|
/* The path is correct, now try to open it and get its size. */
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("%s: failed to open"), path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Seek and read. */
|
||||||
|
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
||||||
|
* be 64 bits on all platforms.
|
||||||
|
*/
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
|
||||||
|
saferead(fd, buffer, size) == (ssize_t) -1) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("%s: failed to seek or read"), path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FORCE_CLOSE(fd);
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
@ -7491,7 +7485,7 @@ qemudDomainMemoryPeek (virDomainPtr dom,
|
||||||
qemuDomainObjExitMonitor(driver, vm);
|
qemuDomainObjExitMonitor(driver, vm);
|
||||||
|
|
||||||
/* Read the memory file into buffer. */
|
/* Read the memory file into buffer. */
|
||||||
if (saferead (fd, buffer, size) == (ssize_t) -1) {
|
if (saferead(fd, buffer, size) == (ssize_t) -1) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("failed to read temporary file "
|
_("failed to read temporary file "
|
||||||
"created with template %s"), tmp);
|
"created with template %s"), tmp);
|
||||||
|
@ -7527,8 +7521,8 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||||
virStorageFileMetadata *meta = NULL;
|
virStorageFileMetadata *meta = NULL;
|
||||||
virDomainDiskDefPtr disk = NULL;
|
virDomainDiskDefPtr disk = NULL;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int i;
|
|
||||||
int format;
|
int format;
|
||||||
|
const char *actual;
|
||||||
|
|
||||||
virCheckFlags(0, -1);
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
@ -7550,22 +7544,15 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the path belongs to this domain. */
|
/* Check the path belongs to this domain. */
|
||||||
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
if (!(actual = virDomainDiskPathByName(vm->def, path))) {
|
||||||
if (vm->def->disks[i]->src != NULL &&
|
|
||||||
STREQ (vm->def->disks[i]->src, path)) {
|
|
||||||
disk = vm->def->disks[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!disk) {
|
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
_("invalid path %s not assigned to domain"), path);
|
_("invalid path %s not assigned to domain"), path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
path = actual;
|
||||||
|
|
||||||
/* The path is correct, now try to open it and get its size. */
|
/* The path is correct, now try to open it and get its size. */
|
||||||
fd = open (path, O_RDONLY);
|
fd = open(path, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("failed to open path '%s'"), path);
|
_("failed to open path '%s'"), path);
|
||||||
|
@ -7624,7 +7611,7 @@ static int qemuDomainGetBlockInfo(virDomainPtr dom,
|
||||||
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
||||||
* be 64 bits on all platforms.
|
* be 64 bits on all platforms.
|
||||||
*/
|
*/
|
||||||
end = lseek (fd, 0, SEEK_END);
|
end = lseek(fd, 0, SEEK_END);
|
||||||
if (end == (off_t)-1) {
|
if (end == (off_t)-1) {
|
||||||
virReportSystemError(errno,
|
virReportSystemError(errno,
|
||||||
_("failed to seek to end of %s"), path);
|
_("failed to seek to end of %s"), path);
|
||||||
|
@ -9831,23 +9818,26 @@ static const char *
|
||||||
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path) {
|
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path) {
|
||||||
int i;
|
int i;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
|
virDomainDiskDefPtr disk;
|
||||||
|
|
||||||
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
i = virDomainDiskIndexByName(vm->def, path, true);
|
||||||
virDomainDiskDefPtr disk = vm->def->disks[i];
|
if (i < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
|
disk = vm->def->disks[i];
|
||||||
disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (disk->src != NULL && STREQ(disk->src, path)) {
|
if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
|
||||||
if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
|
disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
|
||||||
virReportOOMError();
|
goto cleanup;
|
||||||
return NULL;
|
|
||||||
}
|
if (disk->src) {
|
||||||
break;
|
if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
qemuReportError(VIR_ERR_INVALID_ARG,
|
qemuReportError(VIR_ERR_INVALID_ARG,
|
||||||
"%s", _("No device found for specified path"));
|
"%s", _("No device found for specified path"));
|
||||||
|
|
|
@ -192,15 +192,10 @@ static virDomainDiskDefPtr
|
||||||
qemuProcessFindDomainDiskByPath(virDomainObjPtr vm,
|
qemuProcessFindDomainDiskByPath(virDomainObjPtr vm,
|
||||||
const char *path)
|
const char *path)
|
||||||
{
|
{
|
||||||
int i;
|
int i = virDomainDiskIndexByName(vm->def, path, true);
|
||||||
|
|
||||||
for (i = 0; i < vm->def->ndisks; i++) {
|
if (i >= 0)
|
||||||
virDomainDiskDefPtr disk;
|
return vm->def->disks[i];
|
||||||
|
|
||||||
disk = vm->def->disks[i];
|
|
||||||
if (disk->src != NULL && STREQ(disk->src, path))
|
|
||||||
return disk;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
_("no disk found with path %s"),
|
_("no disk found with path %s"),
|
||||||
|
|
|
@ -2175,7 +2175,8 @@ umlDomainBlockPeek(virDomainPtr dom,
|
||||||
{
|
{
|
||||||
struct uml_driver *driver = dom->conn->privateData;
|
struct uml_driver *driver = dom->conn->privateData;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
int fd = -1, ret = -1, i;
|
int fd = -1, ret = -1;
|
||||||
|
const char *actual;
|
||||||
|
|
||||||
virCheckFlags(0, -1);
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
@ -2196,41 +2197,34 @@ umlDomainBlockPeek(virDomainPtr dom,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the path belongs to this domain. */
|
/* Check the path belongs to this domain. */
|
||||||
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
if (!(actual = virDomainDiskPathByName(vm->def, path))) {
|
||||||
if (vm->def->disks[i]->src != NULL &&
|
umlReportError(VIR_ERR_INVALID_ARG,
|
||||||
STREQ (vm->def->disks[i]->src, path)) {
|
_("invalid path '%s'"), path);
|
||||||
ret = 0;
|
goto cleanup;
|
||||||
break;
|
}
|
||||||
}
|
path = actual;
|
||||||
|
|
||||||
|
/* The path is correct, now try to open it and get its size. */
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("cannot open %s"), path);
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0) {
|
/* Seek and read. */
|
||||||
ret = -1;
|
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
||||||
/* The path is correct, now try to open it and get its size. */
|
* be 64 bits on all platforms.
|
||||||
fd = open (path, O_RDONLY);
|
*/
|
||||||
if (fd == -1) {
|
if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
|
||||||
virReportSystemError(errno,
|
saferead(fd, buffer, size) == (ssize_t) -1) {
|
||||||
_("cannot open %s"), path);
|
virReportSystemError(errno,
|
||||||
goto cleanup;
|
_("cannot read %s"), path);
|
||||||
}
|
goto cleanup;
|
||||||
|
|
||||||
/* Seek and read. */
|
|
||||||
/* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
|
|
||||||
* be 64 bits on all platforms.
|
|
||||||
*/
|
|
||||||
if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
|
|
||||||
saferead (fd, buffer, size) == (ssize_t) -1) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("cannot read %s"), path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
umlReportError(VIR_ERR_INVALID_ARG, "%s",
|
|
||||||
_("invalid path"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FORCE_CLOSE(fd);
|
VIR_FORCE_CLOSE(fd);
|
||||||
if (vm)
|
if (vm)
|
||||||
|
|
|
@ -3849,11 +3849,11 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
|
||||||
xenUnifiedPrivatePtr priv;
|
xenUnifiedPrivatePtr priv;
|
||||||
struct sexpr *root = NULL;
|
struct sexpr *root = NULL;
|
||||||
int fd = -1, ret = -1;
|
int fd = -1, ret = -1;
|
||||||
int found = 0, i;
|
|
||||||
virDomainDefPtr def;
|
virDomainDefPtr def;
|
||||||
int id;
|
int id;
|
||||||
char * tty;
|
char * tty;
|
||||||
int vncport;
|
int vncport;
|
||||||
|
const char *actual;
|
||||||
|
|
||||||
priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
|
priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
|
||||||
|
|
||||||
|
@ -3889,18 +3889,12 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
|
||||||
vncport)))
|
vncport)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (i = 0 ; i < def->ndisks ; i++) {
|
if (!(actual = virDomainDiskPathByName(def, path))) {
|
||||||
if (def->disks[i]->src &&
|
|
||||||
STREQ(def->disks[i]->src, path)) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
virXendError(VIR_ERR_INVALID_ARG,
|
virXendError(VIR_ERR_INVALID_ARG,
|
||||||
_("%s: invalid path"), path);
|
_("%s: invalid path"), path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
path = actual;
|
||||||
|
|
||||||
/* The path is correct, now try to open it and get its size. */
|
/* The path is correct, now try to open it and get its size. */
|
||||||
fd = open (path, O_RDONLY);
|
fd = open (path, O_RDONLY);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<name>my snap name</name>
|
<name>my snap name</name>
|
||||||
<description>!@#$%^</description>
|
<description>!@#$%^</description>
|
||||||
<disks>
|
<disks>
|
||||||
<disk name='hda'/>
|
<disk name='/dev/HostVG/QEMUGuest1'/>
|
||||||
<disk name='hdb' snapshot='no'/>
|
<disk name='hdb' snapshot='no'/>
|
||||||
<disk name='hdc' snapshot='internal'/>
|
<disk name='hdc' snapshot='internal'/>
|
||||||
<disk name='hdd' snapshot='external'>
|
<disk name='hdd' snapshot='external'>
|
||||||
|
|
|
@ -503,7 +503,9 @@ snapshot metadata with B<snapshot-create>.
|
||||||
|
|
||||||
=item B<domblkstat> I<domain> I<block-device>
|
=item B<domblkstat> I<domain> I<block-device>
|
||||||
|
|
||||||
Get device block stats for a running domain.
|
Get device block stats for a running domain. A I<block-device> corresponds
|
||||||
|
to a unique target name (<target dev='name'/>) or source file (<source
|
||||||
|
file='name'/>) for one of the disk devices attached to I<domain>.
|
||||||
|
|
||||||
=item B<domifstat> I<domain> I<interface-device>
|
=item B<domifstat> I<domain> I<interface-device>
|
||||||
|
|
||||||
|
@ -515,7 +517,9 @@ Get memory stats for a running domain.
|
||||||
|
|
||||||
=item B<domblkinfo> I<domain> I<block-device>
|
=item B<domblkinfo> I<domain> I<block-device>
|
||||||
|
|
||||||
Get block device size info for a domain.
|
Get block device size info for a domain. A I<block-device> corresponds
|
||||||
|
to a unique target name (<target dev='name'/>) or source file (<source
|
||||||
|
file='name'/>) for one of the disk devices attached to I<domain>.
|
||||||
|
|
||||||
=item B<blockpull> I<domain> I<path> [I<bandwidth>]
|
=item B<blockpull> I<domain> I<path> [I<bandwidth>]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue