From: J.B. Joret <jb(a)linux.vnet.ibm.com>
Qemu allows to override the disk geometry in the drive specification
with cyls=,heads=,secs=[,trans=].
This patch extends the domain config and the qemu driver to allow
the specification of disk geometry with libvirt.
Signed-off-by: J.B. Joret <jb(a)linux.vnet.ibm.com>
Signed-off-by: Viktor Mihajlovski <mihajlov(a)linux.vnet.ibm.com>
---
src/conf/domain_conf.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 17 +++++++++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_command.c | 59 ++++++++++++++++++++++++++++++++++++++
4 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 4f8c57a..4b208fc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -170,6 +170,12 @@ VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
"floppy",
"lun")
+VIR_ENUM_IMPL(virDomainDiskGeometryTrans, VIR_DOMAIN_DISK_TRANS_LAST,
+ "default",
+ "none",
+ "auto",
+ "lba")
+
VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
"ide",
"fdc",
@@ -3347,6 +3353,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
char *source = NULL;
char *target = NULL;
char *protocol = NULL;
+ char *trans = NULL;
virDomainDiskHostDefPtr hosts = NULL;
int nhosts = 0;
char *bus = NULL;
@@ -3375,6 +3382,11 @@ virDomainDiskDefParseXML(virCapsPtr caps,
return NULL;
}
+ def->geometry.cylinders = 0;
+ def->geometry.heads = 0;
+ def->geometry.sectors = 0;
+ def->geometry.trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;
+
ctxt->node = node;
type = virXMLPropString(node, "type");
@@ -3484,6 +3496,40 @@ virDomainDiskDefParseXML(virCapsPtr caps,
if (target &&
STRPREFIX(target, "ioemu:"))
memmove(target, target+6, strlen(target)-5);
+ } else if (xmlStrEqual(cur->name, BAD_CAST "geometry")) {
+ if (virXPathUInt("string(./geometry/@cyls)",
+ ctxt, &def->geometry.cylinders) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid geometry settings
(cyls)"));
+ goto error;
+ }
+ if (virXPathUInt("string(./geometry/@heads)",
+ ctxt, &def->geometry.heads) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid geometry settings
(heads)"));
+ goto error;
+ }
+ if (virXPathUInt("string(./geometry/@secs)",
+ ctxt, &def->geometry.sectors) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid geometry settings
(secs)"));
+ goto error;
+ }
+ trans = virXMLPropString(cur, "trans");
+ if (trans != NULL) {
+ if (STREQ(trans, "none"))
+ def->geometry.trans = VIR_DOMAIN_DISK_TRANS_NONE;
+ else if (STREQ(trans, "auto"))
+ def->geometry.trans = VIR_DOMAIN_DISK_TRANS_AUTO;
+ else if (STREQ(trans, "lba"))
+ def->geometry.trans = VIR_DOMAIN_DISK_TRANS_LBA;
+ else {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid translation value
'%s'"),
+ trans);
+ goto error;
+ }
+ }
} else if (!driverName &&
xmlStrEqual(cur->name, BAD_CAST "driver")) {
driverName = virXMLPropString(cur, "name");
@@ -3962,6 +4008,7 @@ cleanup:
VIR_FREE(target);
VIR_FREE(source);
VIR_FREE(tray);
+ VIR_FREE(trans);
while (nhosts > 0) {
virDomainDiskHostDefFree(&hosts[nhosts - 1]);
nhosts--;
@@ -10973,6 +11020,28 @@ virDomainLeaseDefFormat(virBufferPtr buf,
return 0;
}
+static void virDomainDiskGeometryDefFormat(virBufferPtr buf,
+ virDomainDiskDefPtr def)
+{
+ const char *trans =
+ virDomainDiskGeometryTransTypeToString(def->geometry.trans);
+
+ if (def->geometry.cylinders > 0 &&
+ def->geometry.heads > 0 &&
+ def->geometry.sectors > 0) {
+ virBufferAsprintf(buf,
+ " <geometry cyls='%u' heads='%u'
secs='%u'",
+ def->geometry.cylinders,
+ def->geometry.heads,
+ def->geometry.sectors);
+
+ if (def->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
+ virBufferEscapeString(buf, " trans='%s'", trans);
+
+ virBufferAddLit(buf, "/>\n");
+ }
+}
+
static int
virDomainDiskDefFormat(virBufferPtr buf,
virDomainDiskDefPtr def,
@@ -11094,6 +11163,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
} else {
virBufferAddLit(buf, "/>\n");
}
+ virDomainDiskGeometryDefFormat(buf, def);
break;
case VIR_DOMAIN_DISK_TYPE_BLOCK:
virBufferEscapeString(buf, " <source dev='%s'",
@@ -11107,6 +11177,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
} else {
virBufferAddLit(buf, "/>\n");
}
+ virDomainDiskGeometryDefFormat(buf, def);
break;
case VIR_DOMAIN_DISK_TYPE_DIR:
virBufferEscapeString(buf, " <source
dir='%s'/>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 5e5374a..018a1f1 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -466,6 +466,15 @@ enum virDomainDiskTray {
VIR_DOMAIN_DISK_TRAY_LAST
};
+enum virDomainDiskGeometryTrans {
+ VIR_DOMAIN_DISK_TRANS_DEFAULT = 0,
+ VIR_DOMAIN_DISK_TRANS_NONE,
+ VIR_DOMAIN_DISK_TRANS_AUTO,
+ VIR_DOMAIN_DISK_TRANS_LBA,
+
+ VIR_DOMAIN_DISK_TRANS_LAST
+};
+
typedef struct _virDomainDiskHostDef virDomainDiskHostDef;
typedef virDomainDiskHostDef *virDomainDiskHostDefPtr;
struct _virDomainDiskHostDef {
@@ -575,6 +584,13 @@ struct _virDomainDiskDef {
char *mirrorFormat;
bool mirroring;
+ struct {
+ unsigned int cylinders;
+ unsigned int heads;
+ unsigned int sectors;
+ int trans;
+ } geometry;
+
virDomainBlockIoTuneInfo blkdeviotune;
char *serial;
@@ -2165,6 +2181,7 @@ VIR_ENUM_DECL(virDomainDeviceAddress)
VIR_ENUM_DECL(virDomainDeviceAddressPciMulti)
VIR_ENUM_DECL(virDomainDisk)
VIR_ENUM_DECL(virDomainDiskDevice)
+VIR_ENUM_DECL(virDomainDiskGeometryTrans)
VIR_ENUM_DECL(virDomainDiskBus)
VIR_ENUM_DECL(virDomainDiskCache)
VIR_ENUM_DECL(virDomainDiskErrorPolicy)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b173590..6b2064e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -304,6 +304,8 @@ virDomainDiskDefAssignAddress;
virDomainDiskDefForeachPath;
virDomainDiskDefFree;
virDomainDiskDeviceTypeToString;
+virDomainDiskGeometryTransTypeToString;
+virDomainDiskGeometryTransTypeFromString;
virDomainDiskErrorPolicyTypeFromString;
virDomainDiskErrorPolicyTypeToString;
virDomainDiskFindControllerModel;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ae48678..23d1aba 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -2016,6 +2016,8 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
{
virBuffer opt = VIR_BUFFER_INITIALIZER;
const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+ const char *trans =
+ virDomainDiskGeometryTransTypeToString(disk->geometry.trans);
int idx = virDiskNameToIndex(disk->dst);
int busid = -1, unitid = -1;
@@ -2218,6 +2220,24 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_FORMAT))
virBufferAsprintf(&opt, ",format=%s", disk->driverType);
+
+ /* generate geometry command string*/
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK ||
+ disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
+ if (disk->geometry.cylinders > 0 &&
+ disk->geometry.heads > 0 &&
+ disk->geometry.sectors > 0) {
+
+ virBufferAsprintf(&opt, ",cyls=%u,heads=%u,secs=%u",
+ disk->geometry.cylinders,
+ disk->geometry.heads,
+ disk->geometry.sectors);
+
+ if (disk->geometry.trans != VIR_DOMAIN_DISK_TRANS_DEFAULT)
+ virBufferEscapeString(&opt, ",trans=%s", trans);
+ }
+ }
+
if (disk->serial &&
qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_SERIAL)) {
if (qemuSafeSerialParamValue(disk->serial) < 0)
@@ -6599,6 +6619,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
int idx = -1;
int busid = -1;
int unitid = -1;
+ int trans = VIR_DOMAIN_DISK_TRANS_DEFAULT;
if ((nkeywords = qemuParseKeywords(val,
&keywords,
@@ -6803,6 +6824,44 @@ qemuParseCommandLineDisk(virCapsPtr caps,
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot parse io mode '%s'"),
values[i]);
}
+ } else if (STREQ(keywords[i], "cyls")) {
+ if (virStrToLong_ui(values[i], NULL, 10,
+ &(def->geometry.cylinders)) < 0) {
+ virDomainDiskDefFree(def);
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse cylinders value'%s'"),
+ values[i]);
+ }
+ } else if (STREQ(keywords[i], "heads")) {
+ if (virStrToLong_ui(values[i], NULL, 10,
+ &(def->geometry.heads)) < 0) {
+ virDomainDiskDefFree(def);
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse heads value'%s'"),
+ values[i]);
+ }
+ } else if (STREQ(keywords[i], "secs")) {
+ if (virStrToLong_ui(values[i], NULL, 10,
+ &(def->geometry.sectors)) < 0) {
+ virDomainDiskDefFree(def);
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse sectors value'%s'"),
+ values[i]);
+ }
+ } else if (STREQ(keywords[i], "trans")) {
+ def->geometry.trans =
+ virDomainDiskGeometryTransTypeFromString(values[i]);
+ if ((trans < VIR_DOMAIN_DISK_TRANS_DEFAULT) ||
+ (trans >= VIR_DOMAIN_DISK_TRANS_LAST)) {
+ virDomainDiskDefFree(def);
+ def = NULL;
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse translation
value'%s'"),
+ values[i]);
+ }
}
}
--
1.7.0.4