mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-21 10:52:22 +00:00
virDomainBlockPeek call
* configure.in: Document AC_SYS_LARGEFILE. * docs/hvsupport.html.in: Document HV support for virDomainBlockPeek. * include/libvirt/libvirt.h.in, src/driver.h, src/libvirt.c, src/libvirt_sym.version: Add virDomainBlockPeek infrastructure. * src/qemu_driver.c, src/test.c: Null versions of this call. * src/xen_unified.c, src/xend_internal.c, src/xend_internal.h, src/xm_internal.c, src/xm_internal.h: Xen implementation. * tests/sexpr2xmldata/sexpr2xml-curmem.xml, tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml: XML output has been reordered slightly in the Xen driver, but should be functionally the same.
This commit is contained in:
parent
0bd57cdbe1
commit
8354895e68
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
Thu Jun 5 14:10:00 BST 2008 Richard W.M. Jones <rjones@redhat.com>
|
||||
|
||||
virDomainBlockPeek call
|
||||
* configure.in: Document AC_SYS_LARGEFILE.
|
||||
* docs/hvsupport.html.in: Document HV support for virDomainBlockPeek.
|
||||
* include/libvirt/libvirt.h.in, src/driver.h, src/libvirt.c,
|
||||
src/libvirt_sym.version: Add virDomainBlockPeek infrastructure.
|
||||
* src/qemu_driver.c, src/test.c: Null versions of this call.
|
||||
* src/xen_unified.c, src/xend_internal.c, src/xend_internal.h,
|
||||
src/xm_internal.c, src/xm_internal.h: Xen implementation.
|
||||
* tests/sexpr2xmldata/sexpr2xml-curmem.xml,
|
||||
tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml: XML output
|
||||
has been reordered slightly in the Xen driver, but should be
|
||||
functionally the same.
|
||||
|
||||
Wed Jun 4 23:02:21 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>
|
||||
|
||||
* src/lxc_driver.c: Add sanity of tty pid before kill()
|
||||
|
@ -60,6 +60,10 @@ AM_PROG_CC_C_O
|
||||
|
||||
LIBVIRT_COMPILE_WARNINGS([maximum])
|
||||
|
||||
dnl Support large files / 64 bit seek offsets.
|
||||
dnl Use --disable-largefile if you don't want this.
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
dnl Availability of various common functions (non-fatal if missing).
|
||||
AC_CHECK_FUNCS([cfmakeraw regexec uname sched_getaffinity])
|
||||
|
||||
@ -982,8 +986,6 @@ AC_SUBST([CYGWIN_EXTRA_LIBADD])
|
||||
AC_SUBST([CYGWIN_EXTRA_PYTHON_LIBADD])
|
||||
AC_SUBST([MINGW_EXTRA_LDFLAGS])
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# Set LV_LIBTOOL_OBJDIR to "." or $lt_cv_objdir, depending on whether
|
||||
# we're building shared libraries. This is the name of the directory
|
||||
# in which .o files will be created.
|
||||
|
@ -137,7 +137,7 @@ in.
|
||||
</p>
|
||||
<p>
|
||||
This information changes frequently. This page was last checked or
|
||||
updated on <i>2007-08-20</i>.
|
||||
updated on <i>2008-06-05</i>.
|
||||
</p>
|
||||
<h3>Domain functions</h3>
|
||||
<p> x = not supported; empty cell means no information </p>
|
||||
@ -254,6 +254,14 @@ updated on <i>2007-08-20</i>.
|
||||
<td> ≥ 0.2.0 </td>
|
||||
<td> ≥ 0.3.0 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virConnectOpenAuth </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virConnectOpenReadOnly </td>
|
||||
<td> All </td>
|
||||
@ -270,6 +278,14 @@ updated on <i>2007-08-20</i>.
|
||||
<td> x </td>
|
||||
<td> ≥ 0.3.0 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virDomainBlockPeek </td>
|
||||
<td> 0.4.3 </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virDomainBlockStats </td>
|
||||
<td> 0.3.2 </td>
|
||||
|
@ -9,7 +9,7 @@ in.
|
||||
</p>
|
||||
<p>
|
||||
This information changes frequently. This page was last checked or
|
||||
updated on <i>2007-08-20</i>.
|
||||
updated on <i>2008-06-05</i>.
|
||||
</p>
|
||||
<h3>Domain functions</h3>
|
||||
<p> x = not supported; empty cell means no information </p>
|
||||
@ -118,6 +118,14 @@ updated on <i>2007-08-20</i>.
|
||||
<td> ≥ 0.2.0 </td>
|
||||
<td> ≥ 0.3.0 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virConnectOpenAuth </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virConnectOpenReadOnly </td>
|
||||
<td> All </td>
|
||||
@ -134,6 +142,14 @@ updated on <i>2007-08-20</i>.
|
||||
<td> x </td>
|
||||
<td> ≥ 0.3.0 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virDomainBlockPeek </td>
|
||||
<td> 0.4.3 </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
<td> x </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> virDomainBlockStats </td>
|
||||
<td> 0.3.2 </td>
|
||||
|
@ -530,7 +530,12 @@ int virDomainInterfaceStats (virDomainPtr dom,
|
||||
const char *path,
|
||||
virDomainInterfaceStatsPtr stats,
|
||||
size_t size);
|
||||
|
||||
int virDomainBlockPeek (virDomainPtr dom,
|
||||
const char *path,
|
||||
unsigned long long offset,
|
||||
size_t size,
|
||||
void *buffer,
|
||||
unsigned int flags);
|
||||
|
||||
/*
|
||||
* defined but not running domains
|
||||
|
@ -530,7 +530,12 @@ int virDomainInterfaceStats (virDomainPtr dom,
|
||||
const char *path,
|
||||
virDomainInterfaceStatsPtr stats,
|
||||
size_t size);
|
||||
|
||||
int virDomainBlockPeek (virDomainPtr dom,
|
||||
const char *path,
|
||||
unsigned long long offset,
|
||||
size_t size,
|
||||
void *buffer,
|
||||
unsigned int flags);
|
||||
|
||||
/*
|
||||
* defined but not running domains
|
||||
|
@ -225,6 +225,13 @@ typedef int
|
||||
const char *path,
|
||||
struct _virDomainInterfaceStats *stats);
|
||||
|
||||
typedef int
|
||||
(*virDrvDomainBlockPeek)
|
||||
(virDomainPtr domain,
|
||||
const char *path,
|
||||
unsigned long long offset, size_t size,
|
||||
void *buffer);
|
||||
|
||||
typedef int
|
||||
(*virDrvDomainMigratePrepare)
|
||||
(virConnectPtr dconn,
|
||||
@ -337,6 +344,7 @@ struct _virDriver {
|
||||
virDrvDomainMigrateFinish domainMigrateFinish;
|
||||
virDrvDomainBlockStats domainBlockStats;
|
||||
virDrvDomainInterfaceStats domainInterfaceStats;
|
||||
virDrvDomainBlockPeek domainBlockPeek;
|
||||
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
|
||||
virDrvNodeGetFreeMemory getFreeMemory;
|
||||
};
|
||||
|
@ -2586,7 +2586,84 @@ virDomainInterfaceStats (virDomainPtr dom, const char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* virDomainBlockPeek:
|
||||
* @dom: pointer to the domain object
|
||||
* @path: path to the block device
|
||||
* @offset: offset within block device
|
||||
* @size: size to read
|
||||
* @buffer: return buffer (must be at least size bytes)
|
||||
* @flags: unused, always pass 0
|
||||
*
|
||||
* This function allows you to read the contents of a domain's
|
||||
* disk device.
|
||||
*
|
||||
* Typical uses for this are to determine if the domain has
|
||||
* written a Master Boot Record (indicating that the domain
|
||||
* has completed installation), or to try to work out the state
|
||||
* of the domain's filesystems.
|
||||
*
|
||||
* (Note that in the local case you might try to open the
|
||||
* block device or file directly, but that won't work in the
|
||||
* remote case, nor if you don't have sufficient permission.
|
||||
* Hence the need for this call).
|
||||
*
|
||||
* 'path' must be a device or file corresponding to the domain.
|
||||
* In other words it must be the precise string returned in
|
||||
* a <disk><source dev='...'/></disk> from
|
||||
* virDomainGetXMLDesc.
|
||||
*
|
||||
* 'offset' and 'size' represent an area which must lie entirely
|
||||
* within the device or file. 'size' may be 0 to test if the
|
||||
* call would succeed.
|
||||
*
|
||||
* 'buffer' is the return buffer and must be at least 'size' bytes.
|
||||
*
|
||||
* Returns: 0 in case of success or -1 in case of failure.
|
||||
*/
|
||||
int
|
||||
virDomainBlockPeek (virDomainPtr dom,
|
||||
const char *path,
|
||||
unsigned long long offset /* really 64 bits */,
|
||||
size_t size,
|
||||
void *buffer,
|
||||
unsigned int flags)
|
||||
{
|
||||
virConnectPtr conn;
|
||||
DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p",
|
||||
dom, path, offset, size, buffer);
|
||||
|
||||
if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
|
||||
virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
conn = dom->conn;
|
||||
|
||||
if (!path) {
|
||||
virLibDomainError (dom, VIR_ERR_INVALID_ARG,
|
||||
_("path is NULL"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags != 0) {
|
||||
virLibDomainError (dom, VIR_ERR_INVALID_ARG,
|
||||
_("flags must be zero"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allow size == 0 as an access test. */
|
||||
if (size > 0 && !buffer) {
|
||||
virLibDomainError (dom, VIR_ERR_INVALID_ARG,
|
||||
_("buffer is NULL"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->driver->domainBlockPeek)
|
||||
return conn->driver->domainBlockPeek (dom, path, offset, size, buffer);
|
||||
|
||||
virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
|
@ -73,6 +73,7 @@
|
||||
virDomainSetSchedulerParameters;
|
||||
virDomainBlockStats;
|
||||
virDomainInterfaceStats;
|
||||
virDomainBlockPeek;
|
||||
virDomainAttachDevice;
|
||||
virDomainDetachDevice;
|
||||
|
||||
|
@ -3521,6 +3521,7 @@ static virDriver qemuDriver = {
|
||||
NULL, /* domainMigrateFinish */
|
||||
qemudDomainBlockStats, /* domainBlockStats */
|
||||
qemudDomainInterfaceStats, /* domainInterfaceStats */
|
||||
NULL, /* domainBlockPeek */
|
||||
#if HAVE_NUMACTL
|
||||
qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
||||
qemudNodeGetFreeMemory, /* getFreeMemory */
|
||||
|
@ -2060,6 +2060,7 @@ static virDriver testDriver = {
|
||||
NULL, /* domainMigrateFinish */
|
||||
NULL, /* domainBlockStats */
|
||||
NULL, /* domainInterfaceStats */
|
||||
NULL, /* domainBlockPeek */
|
||||
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
||||
NULL, /* getFreeMemory */
|
||||
};
|
||||
|
@ -1234,6 +1234,29 @@ xenUnifiedDomainInterfaceStats (virDomainPtr dom, const char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path,
|
||||
unsigned long long offset, size_t size,
|
||||
void *buffer)
|
||||
{
|
||||
int r;
|
||||
GET_PRIVATE (dom->conn);
|
||||
|
||||
if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
|
||||
r = xenDaemonDomainBlockPeek (dom, path, offset, size, buffer);
|
||||
if (r != -2) return r;
|
||||
/* r == -2 means declined, so fall through to XM driver ... */
|
||||
}
|
||||
|
||||
if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
|
||||
if (xenXMDomainBlockPeek (dom, path, offset, size, buffer) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems,
|
||||
int startCell, int maxCells)
|
||||
@ -1329,6 +1352,7 @@ static virDriver xenUnifiedDriver = {
|
||||
.domainMigrateFinish = xenUnifiedDomainMigrateFinish,
|
||||
.domainBlockStats = xenUnifiedDomainBlockStats,
|
||||
.domainInterfaceStats = xenUnifiedDomainInterfaceStats,
|
||||
.domainBlockPeek = xenUnifiedDomainBlockPeek,
|
||||
.nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory,
|
||||
.getFreeMemory = xenUnifiedNodeGetFreeMemory,
|
||||
};
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -1705,6 +1707,219 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef int
|
||||
(*sexp_blockdevs_cb)
|
||||
(virConnectPtr conn, void *data,
|
||||
int isBlock, int cdrom, int isNoSrcCdrom, int hvm,
|
||||
const char *drvName, const char *drvType,
|
||||
const char *src, const char *dst,
|
||||
const char *mode);
|
||||
|
||||
/**
|
||||
* xend_parse_sexp_blockdevs:
|
||||
* @conn: connection
|
||||
* @root: root sexpr
|
||||
* @xendConfigVersion: version of xend
|
||||
* @fn: callback function
|
||||
* @data: optional data for callback function
|
||||
*
|
||||
* This parses out block devices from the domain sexpr and calls
|
||||
* fn (conn, data, ...) for each block device found.
|
||||
*
|
||||
* Returns 0 if successful or -1 if failed.
|
||||
*/
|
||||
static int
|
||||
xend_parse_sexp_blockdevs (virConnectPtr conn, struct sexpr *root,
|
||||
int xendConfigVersion,
|
||||
sexp_blockdevs_cb fn, void *data)
|
||||
{
|
||||
struct sexpr *cur, *node;
|
||||
int hvm;
|
||||
|
||||
hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
|
||||
|
||||
for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
|
||||
node = cur->u.s.car;
|
||||
/* Normally disks are in a (device (vbd ...)) block
|
||||
but blktap disks ended up in a differently named
|
||||
(device (tap ....)) block.... */
|
||||
if (sexpr_lookup(node, "device/vbd") ||
|
||||
sexpr_lookup(node, "device/tap")) {
|
||||
char *offset;
|
||||
int ret = -1;
|
||||
int isBlock = 0;
|
||||
int cdrom = 0;
|
||||
int isNoSrcCdrom = 0;
|
||||
char *drvName = NULL;
|
||||
char *drvType = NULL;
|
||||
const char *src = NULL;
|
||||
const char *dst = NULL;
|
||||
const char *mode = NULL;
|
||||
|
||||
/* Again dealing with (vbd...) vs (tap ...) differences */
|
||||
if (sexpr_lookup(node, "device/vbd")) {
|
||||
src = sexpr_node(node, "device/vbd/uname");
|
||||
dst = sexpr_node(node, "device/vbd/dev");
|
||||
mode = sexpr_node(node, "device/vbd/mode");
|
||||
} else {
|
||||
src = sexpr_node(node, "device/tap/uname");
|
||||
dst = sexpr_node(node, "device/tap/dev");
|
||||
mode = sexpr_node(node, "device/tap/mode");
|
||||
}
|
||||
|
||||
if (dst == NULL) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domain information incomplete, vbd has no dev"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (src == NULL) {
|
||||
/* There is a case without the uname to the CD-ROM device */
|
||||
offset = strchr(dst, ':');
|
||||
if (offset) {
|
||||
if (hvm && STREQ(offset, ":cdrom")) {
|
||||
isNoSrcCdrom = 1;
|
||||
}
|
||||
offset[0] = '\0';
|
||||
}
|
||||
if (!isNoSrcCdrom) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domain information incomplete, vbd has no src"));
|
||||
goto bad_parse;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNoSrcCdrom) {
|
||||
offset = strchr(src, ':');
|
||||
if (!offset) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse vbd filename, missing driver name"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(drvName, (offset-src)+1) < 0) {
|
||||
virXendError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("allocate new buffer"));
|
||||
goto bad_parse;
|
||||
}
|
||||
strncpy(drvName, src, (offset-src));
|
||||
drvName[offset-src] = '\0';
|
||||
|
||||
src = offset + 1;
|
||||
|
||||
if (STREQ (drvName, "tap")) {
|
||||
offset = strchr(src, ':');
|
||||
if (!offset) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse vbd filename, missing driver type"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(drvType, (offset-src)+1)< 0) {
|
||||
virXendError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("allocate new buffer"));
|
||||
goto bad_parse;
|
||||
}
|
||||
strncpy(drvType, src, (offset-src));
|
||||
drvType[offset-src] = '\0';
|
||||
src = offset + 1;
|
||||
/* Its possible to use blktap driver for block devs
|
||||
too, but kinda pointless because blkback is better,
|
||||
so we assume common case here. If blktap becomes
|
||||
omnipotent, we can revisit this, perhaps stat()'ing
|
||||
the src file in question */
|
||||
isBlock = 0;
|
||||
} else if (STREQ(drvName, "phy")) {
|
||||
isBlock = 1;
|
||||
} else if (STREQ(drvName, "file")) {
|
||||
isBlock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (STREQLEN (dst, "ioemu:", 6))
|
||||
dst += 6;
|
||||
|
||||
/* New style disk config from Xen >= 3.0.3 */
|
||||
if (xendConfigVersion > 1) {
|
||||
offset = strrchr(dst, ':');
|
||||
if (offset) {
|
||||
if (STREQ (offset, ":cdrom")) {
|
||||
cdrom = 1;
|
||||
} else if (STREQ (offset, ":disk")) {
|
||||
/* The default anyway */
|
||||
} else {
|
||||
/* Unknown, lets pretend its a disk too */
|
||||
}
|
||||
offset[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the callback function. */
|
||||
ret = fn (conn, data, isBlock, cdrom, isNoSrcCdrom, hvm,
|
||||
drvName, drvType, src, dst, mode);
|
||||
|
||||
bad_parse:
|
||||
VIR_FREE(drvName);
|
||||
VIR_FREE(drvType);
|
||||
|
||||
if (ret == -1) return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
xend_parse_sexp_desc_blockdev (virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
void *data,
|
||||
int isBlock, int cdrom, int isNoSrcCdrom,
|
||||
int hvm,
|
||||
const char *drvName, const char *drvType,
|
||||
const char *src, const char *dst,
|
||||
const char *mode)
|
||||
{
|
||||
virBuffer *buf = (virBuffer *) data;
|
||||
const char *bus = NULL;
|
||||
|
||||
if (!isNoSrcCdrom) {
|
||||
virBufferVSprintf(buf, " <disk type='%s' device='%s'>\n",
|
||||
isBlock ? "block" : "file",
|
||||
cdrom ? "cdrom" : "disk");
|
||||
if (drvType) {
|
||||
virBufferVSprintf(buf, " <driver name='%s' type='%s'/>\n", drvName, drvType);
|
||||
} else {
|
||||
virBufferVSprintf(buf, " <driver name='%s'/>\n", drvName);
|
||||
}
|
||||
if (isBlock) {
|
||||
virBufferVSprintf(buf, " <source dev='%s'/>\n", src);
|
||||
} else {
|
||||
virBufferVSprintf(buf, " <source file='%s'/>\n", src);
|
||||
}
|
||||
} else {
|
||||
/* This case is the cdrom device only */
|
||||
virBufferAddLit(buf, " <disk device='cdrom'>\n");
|
||||
}
|
||||
if (STRPREFIX(dst, "xvd") || !hvm) {
|
||||
bus = "xen";
|
||||
} else if (STRPREFIX(dst, "sd")) {
|
||||
bus = "scsi";
|
||||
} else {
|
||||
bus = "ide";
|
||||
}
|
||||
virBufferVSprintf(buf, " <target dev='%s' bus='%s'/>\n",
|
||||
dst, bus);
|
||||
|
||||
/* XXX should we force mode == r, if cdrom==1, or assume
|
||||
xend has already done this ? */
|
||||
if ((mode != NULL) && (STREQ (mode, "r")))
|
||||
virBufferAddLit(buf, " <readonly/>\n");
|
||||
else if ((mode != NULL) && (STREQ (mode, "w!")))
|
||||
virBufferAddLit(buf, " <shareable/>\n");
|
||||
virBufferAddLit(buf, " </disk>\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xend_parse_sexp_desc:
|
||||
* @conn: the connection associated with the XML
|
||||
@ -1849,164 +2064,15 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root,
|
||||
if ((tmp != NULL) && (tmp[0] != 0))
|
||||
virBufferVSprintf(&buf, " <emulator>%s</emulator>\n", tmp);
|
||||
|
||||
/* append block devices */
|
||||
if (xend_parse_sexp_blockdevs (conn, root, xendConfigVersion,
|
||||
xend_parse_sexp_desc_blockdev, &buf) == -1)
|
||||
goto error;
|
||||
|
||||
/* append network devices and framebuffer */
|
||||
for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
|
||||
node = cur->u.s.car;
|
||||
/* Normally disks are in a (device (vbd ...)) block
|
||||
but blktap disks ended up in a differently named
|
||||
(device (tap ....)) block.... */
|
||||
if (sexpr_lookup(node, "device/vbd") ||
|
||||
sexpr_lookup(node, "device/tap")) {
|
||||
char *offset;
|
||||
int isBlock = 0;
|
||||
int cdrom = 0;
|
||||
int isNoSrcCdrom = 0;
|
||||
char *drvName = NULL;
|
||||
char *drvType = NULL;
|
||||
const char *src = NULL;
|
||||
const char *dst = NULL;
|
||||
const char *mode = NULL;
|
||||
const char *bus = NULL;
|
||||
|
||||
/* Again dealing with (vbd...) vs (tap ...) differences */
|
||||
if (sexpr_lookup(node, "device/vbd")) {
|
||||
src = sexpr_node(node, "device/vbd/uname");
|
||||
dst = sexpr_node(node, "device/vbd/dev");
|
||||
mode = sexpr_node(node, "device/vbd/mode");
|
||||
} else {
|
||||
src = sexpr_node(node, "device/tap/uname");
|
||||
dst = sexpr_node(node, "device/tap/dev");
|
||||
mode = sexpr_node(node, "device/tap/mode");
|
||||
}
|
||||
|
||||
if (dst == NULL) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domain information incomplete, vbd has no dev"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (src == NULL) {
|
||||
/* There is a case without the uname to the CD-ROM device */
|
||||
offset = strchr(dst, ':');
|
||||
if (offset) {
|
||||
if (hvm && STREQ( offset , ":cdrom")) {
|
||||
isNoSrcCdrom = 1;
|
||||
}
|
||||
offset[0] = '\0';
|
||||
}
|
||||
if (!isNoSrcCdrom) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domain information incomplete, vbd has no src"));
|
||||
goto bad_parse;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNoSrcCdrom) {
|
||||
offset = strchr(src, ':');
|
||||
if (!offset) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse vbd filename, missing driver name"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(drvName, (offset-src)+1) < 0) {
|
||||
virXendError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("allocate new buffer"));
|
||||
goto bad_parse;
|
||||
}
|
||||
strncpy(drvName, src, (offset-src));
|
||||
drvName[offset-src] = '\0';
|
||||
|
||||
src = offset + 1;
|
||||
|
||||
if (STREQ(drvName, "tap")) {
|
||||
offset = strchr(src, ':');
|
||||
if (!offset) {
|
||||
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("cannot parse vbd filename, missing driver type"));
|
||||
goto bad_parse;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(drvType, (offset-src)+1)< 0) {
|
||||
virXendError(conn, VIR_ERR_NO_MEMORY,
|
||||
_("allocate new buffer"));
|
||||
goto bad_parse;
|
||||
}
|
||||
strncpy(drvType, src, (offset-src));
|
||||
drvType[offset-src] = '\0';
|
||||
src = offset + 1;
|
||||
/* Its possible to use blktap driver for block devs
|
||||
too, but kinda pointless because blkback is better,
|
||||
so we assume common case here. If blktap becomes
|
||||
omnipotent, we can revisit this, perhaps stat()'ing
|
||||
the src file in question */
|
||||
isBlock = 0;
|
||||
} else if (STREQ(drvName, "phy")) {
|
||||
isBlock = 1;
|
||||
} else if (STREQ(drvName, "file")) {
|
||||
isBlock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (STRPREFIX(dst, "ioemu:"))
|
||||
dst += 6;
|
||||
|
||||
/* New style disk config from Xen >= 3.0.3 */
|
||||
if (xendConfigVersion > 1) {
|
||||
offset = strrchr(dst, ':');
|
||||
if (offset) {
|
||||
if (STREQ(offset, ":cdrom")) {
|
||||
cdrom = 1;
|
||||
} else if (STREQ(offset, ":disk")) {
|
||||
/* The default anyway */
|
||||
} else {
|
||||
/* Unknown, lets pretend its a disk too */
|
||||
}
|
||||
offset[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNoSrcCdrom) {
|
||||
virBufferVSprintf(&buf, " <disk type='%s' device='%s'>\n",
|
||||
isBlock ? "block" : "file",
|
||||
cdrom ? "cdrom" : "disk");
|
||||
if (drvType) {
|
||||
virBufferVSprintf(&buf, " <driver name='%s' type='%s'/>\n", drvName, drvType);
|
||||
} else {
|
||||
virBufferVSprintf(&buf, " <driver name='%s'/>\n", drvName);
|
||||
}
|
||||
if (isBlock) {
|
||||
virBufferVSprintf(&buf, " <source dev='%s'/>\n", src);
|
||||
} else {
|
||||
virBufferVSprintf(&buf, " <source file='%s'/>\n", src);
|
||||
}
|
||||
} else {
|
||||
/* This case is the cdrom device only */
|
||||
virBufferAddLit(&buf, " <disk device='cdrom'>\n");
|
||||
}
|
||||
|
||||
if (STRPREFIX(dst, "xvd") || !hvm) {
|
||||
bus = "xen";
|
||||
} else if (STRPREFIX(dst, "sd")) {
|
||||
bus = "scsi";
|
||||
} else {
|
||||
bus = "ide";
|
||||
}
|
||||
virBufferVSprintf(&buf, " <target dev='%s' bus='%s'/>\n",
|
||||
dst, bus);
|
||||
|
||||
|
||||
/* XXX should we force mode == r, if cdrom==1, or assume
|
||||
xend has already done this ? */
|
||||
if ((mode != NULL) && (STREQ(mode, "r")))
|
||||
virBufferAddLit(&buf, " <readonly/>\n");
|
||||
else if ((mode != NULL) && (STREQ(mode, "w!")))
|
||||
virBufferAddLit(&buf, " <shareable/>\n");
|
||||
virBufferAddLit(&buf, " </disk>\n");
|
||||
|
||||
bad_parse:
|
||||
VIR_FREE(drvName);
|
||||
VIR_FREE(drvType);
|
||||
} else if (sexpr_lookup(node, "device/vif")) {
|
||||
if (sexpr_lookup(node, "device/vif")) {
|
||||
const char *tmp2, *model;
|
||||
tmp2 = sexpr_node(node, "device/vif/script");
|
||||
tmp = sexpr_node(node, "device/vif/bridge");
|
||||
@ -4433,5 +4499,110 @@ error:
|
||||
return (ret);
|
||||
}
|
||||
|
||||
struct check_path_data {
|
||||
const char *path;
|
||||
int ok;
|
||||
};
|
||||
|
||||
static int
|
||||
check_path (virConnectPtr conn ATTRIBUTE_UNUSED, void *vp,
|
||||
int isBlock ATTRIBUTE_UNUSED,
|
||||
int cdrom, int isNoSrcCdrom,
|
||||
int hvm ATTRIBUTE_UNUSED,
|
||||
const char *drvName ATTRIBUTE_UNUSED,
|
||||
const char *drvType ATTRIBUTE_UNUSED,
|
||||
const char *src, const char *dst ATTRIBUTE_UNUSED,
|
||||
const char *mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
struct check_path_data *data = (struct check_path_data *) vp;
|
||||
|
||||
if (!isNoSrcCdrom && !cdrom && src && STREQ (src, data->path))
|
||||
data->ok = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xenDaemonDomainBlockPeek:
|
||||
* @dom: domain object
|
||||
* @path: path to the file or device
|
||||
* @offset: offset
|
||||
* @size: size
|
||||
* @buffer: return buffer
|
||||
*
|
||||
* Returns 0 if successful, -1 if error, -2 if declined.
|
||||
*/
|
||||
int
|
||||
xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
|
||||
unsigned long long offset, size_t size,
|
||||
void *buffer)
|
||||
{
|
||||
xenUnifiedPrivatePtr priv;
|
||||
struct sexpr *root;
|
||||
struct check_path_data data;
|
||||
int fd, ret = -1;
|
||||
struct stat statbuf;
|
||||
|
||||
priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
|
||||
|
||||
if (domain->id < 0 && priv->xendConfigVersion < 3)
|
||||
return -2; /* Decline, allow XM to handle it. */
|
||||
|
||||
/* Security check: The path must correspond to a block device. */
|
||||
if (domain->id > 0)
|
||||
root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
|
||||
domain->id);
|
||||
else if (domain->id < 0)
|
||||
root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
|
||||
domain->name);
|
||||
else {
|
||||
/* This call always fails for dom0. */
|
||||
virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
|
||||
_("domainBlockPeek is not supported for dom0"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
virXendError (domain->conn, VIR_ERR_XEN_CALL, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.path = path;
|
||||
data.ok = 0;
|
||||
|
||||
if (xend_parse_sexp_blockdevs (domain->conn, root,
|
||||
priv->xendConfigVersion,
|
||||
check_path, &data) == -1)
|
||||
return -1;
|
||||
|
||||
if (!data.ok) {
|
||||
virXendError (domain->conn, VIR_ERR_INVALID_ARG,
|
||||
_("invalid path"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The path is correct, now try to open it and get its size. */
|
||||
fd = open (path, O_RDONLY);
|
||||
if (fd == -1 || fstat (fd, &statbuf) == -1) {
|
||||
virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
if (fd >= 0) close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* ! PROXY */
|
||||
#endif /* WITH_XEN */
|
||||
|
@ -244,6 +244,8 @@ virDomainPtr xenDaemonLookupByName(virConnectPtr conn, const char *domname);
|
||||
int xenDaemonDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource);
|
||||
int xenDaemonDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource);
|
||||
|
||||
int xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, void *buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -3241,4 +3241,15 @@ xenXMDomainDetachDevice(virDomainPtr domain, const char *xml) {
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
xenXMDomainBlockPeek (virDomainPtr dom,
|
||||
const char *path ATTRIBUTE_UNUSED,
|
||||
unsigned long long offset ATTRIBUTE_UNUSED,
|
||||
size_t size ATTRIBUTE_UNUSED,
|
||||
void *buffer ATTRIBUTE_UNUSED)
|
||||
{
|
||||
xenXMError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* WITH_XEN */
|
||||
|
@ -60,6 +60,7 @@ int xenXMDomainUndefine(virDomainPtr domain);
|
||||
|
||||
virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml);
|
||||
char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf);
|
||||
int xenXMDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, void *buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -15,17 +15,17 @@
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>restart</on_crash>
|
||||
<devices>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='tap' type='aio'/>
|
||||
<source file='/xen/rhel5.img'/>
|
||||
<target dev='xvda' bus='xen'/>
|
||||
</disk>
|
||||
<interface type='bridge'>
|
||||
<source bridge='xenbr0'/>
|
||||
<target dev='vif5.0'/>
|
||||
<mac address='00:16:3e:1d:06:15'/>
|
||||
<script path='vif-bridge'/>
|
||||
</interface>
|
||||
<disk type='file' device='disk'>
|
||||
<driver name='tap' type='aio'/>
|
||||
<source file='/xen/rhel5.img'/>
|
||||
<target dev='xvda' bus='xen'/>
|
||||
</disk>
|
||||
<input type='mouse' bus='xen'/>
|
||||
<graphics type='vnc' port='-1'/>
|
||||
<console type='pty'>
|
||||
|
@ -20,11 +20,6 @@
|
||||
<clock offset='utc'/>
|
||||
<devices>
|
||||
<emulator>/usr/lib/xen/bin/qemu-dm</emulator>
|
||||
<interface type='bridge'>
|
||||
<source bridge='xenbr0'/>
|
||||
<target dev='vif6.0'/>
|
||||
<mac address='00:16:3e:0a:7b:39'/>
|
||||
</interface>
|
||||
<disk type='block' device='disk'>
|
||||
<driver name='phy'/>
|
||||
<source dev='/dev/sda8'/>
|
||||
@ -34,6 +29,11 @@
|
||||
<target dev='hdc' bus='ide'/>
|
||||
<readonly/>
|
||||
</disk>
|
||||
<interface type='bridge'>
|
||||
<source bridge='xenbr0'/>
|
||||
<target dev='vif6.0'/>
|
||||
<mac address='00:16:3e:0a:7b:39'/>
|
||||
</interface>
|
||||
<input type='mouse' bus='ps2'/>
|
||||
<graphics type='vnc' port='-1'/>
|
||||
<serial type='pty'>
|
||||
|
Loading…
x
Reference in New Issue
Block a user