aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@linux.vnet.ibm.com>2012-03-14 15:57:05 +0000
committerKevin Wolf <kwolf@redhat.com>2012-04-05 14:54:40 +0200
commit02fda01c3024463e561820afb0ba09daba4014d9 (patch)
tree3b59b67aabe14e8b6757ba9d2bb8bb1129fdec81
parent41453412ca16ff1871ed2bd6ee83cb9a5c734823 (diff)
downloadqemu-02fda01c3024463e561820afb0ba09daba4014d9.zip
qemu-02fda01c3024463e561820afb0ba09daba4014d9.tar.gz
qemu-02fda01c3024463e561820afb0ba09daba4014d9.tar.bz2
qdev: add blocksize property type
Storage interfaces like virtio-blk can be configured with block size information so that the guest can take advantage of efficient I/O request sizes. According to the SCSI Block Commands (SBC) standard a device's block size is "almost always greater than one byte and may be a multiple of 512 bytes". QEMU currently has a 512 byte minimum block size because the block layer functions work at that granularity. Furthermore, the block size should be a power of 2 because QEMU calculates bitmasks from the value. Introduce a "blocksize" property type so devices can enforce these constraints on block size values. If the constraints are relaxed in the future then this property can be updated. Introduce the new PropertyValueNotPowerOf2 QError so QMP clients know exactly why a block size value was rejected. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
-rw-r--r--hw/qdev-properties.c46
-rw-r--r--hw/qdev.h3
-rw-r--r--qerror.c5
-rw-r--r--qerror.h4
4 files changed, 58 insertions, 0 deletions
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index bff9152..98dd06a 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -877,6 +877,52 @@ PropertyInfo qdev_prop_pci_devfn = {
.max = 0xFFFFFFFFULL,
};
+/* --- blocksize --- */
+
+static void set_blocksize(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ int16_t *ptr = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ int64_t value;
+
+ if (dev->state != DEV_STATE_CREATED) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ return;
+ }
+
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ if (value < prop->info->min || value > prop->info->max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+ dev->id?:"", name, value, prop->info->min,
+ prop->info->max);
+ return;
+ }
+
+ /* We rely on power-of-2 blocksizes for bitmasks */
+ if ((value & (value - 1)) != 0) {
+ error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+ dev->id?:"", name, value);
+ return;
+ }
+
+ *ptr = value;
+}
+
+PropertyInfo qdev_prop_blocksize = {
+ .name = "blocksize",
+ .get = get_int16,
+ .set = set_blocksize,
+ .min = 512,
+ .max = 65024,
+};
+
/* --- public helpers --- */
static Property *qdev_prop_walk(Property *props, const char *name)
diff --git a/hw/qdev.h b/hw/qdev.h
index a8df42f..1c10960 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -223,6 +223,7 @@ extern PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan;
extern PropertyInfo qdev_prop_pci_devfn;
+extern PropertyInfo qdev_prop_blocksize;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \
@@ -284,6 +285,8 @@ extern PropertyInfo qdev_prop_pci_devfn;
#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
LostTickPolicy)
+#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
+ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
#define DEFINE_PROP_END_OF_LIST() \
{}
diff --git a/qerror.c b/qerror.c
index 1f565fc..96fbe71 100644
--- a/qerror.c
+++ b/qerror.c
@@ -241,6 +241,11 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Property '%(device).%(property)' can't find value '%(value)'",
},
{
+ .error_fmt = QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+ .desc = "Property '%(device).%(property)' doesn't take "
+ "value '%(value)', it's not a power of 2",
+ },
+ {
.error_fmt = QERR_PROPERTY_VALUE_OUT_OF_RANGE,
.desc = "Property '%(device).%(property)' doesn't take "
"value %(value) (minimum: %(min), maximum: %(max))",
diff --git a/qerror.h b/qerror.h
index e16f9c2..5c23c1f 100644
--- a/qerror.h
+++ b/qerror.h
@@ -202,6 +202,10 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_PROPERTY_VALUE_NOT_FOUND \
"{ 'class': 'PropertyValueNotFound', 'data': { 'device': %s, 'property': %s, 'value': %s } }"
+#define QERR_PROPERTY_VALUE_NOT_POWER_OF_2 \
+ "{ 'class': 'PropertyValueNotPowerOf2', 'data': { " \
+ "'device': %s, 'property': %s, 'value': %"PRId64" } }"
+
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"