* [Qemu-devel] [RFC PATCH] generalize QOM path resolution
@ 2012-01-30 12:53 Paolo Bonzini
2012-01-30 13:39 ` Anthony Liguori
0 siblings, 1 reply; 5+ messages in thread
From: Paolo Bonzini @ 2012-01-30 12:53 UTC (permalink / raw)
To: qemu-devel
Right now, resolving a string to an object is not generic to QOM,
but rather it is entirely embedded in qdev (the Device class).
This embryo patch generalizes the concept adding a resolve_path
class method, and get_canonical_path instance method, to Object.
Link properties use the type to direct sets to the right resolve_path
method, while the qom-{get,set,list} commands get a class argument.
This is needed to have different namespaces for devices, host drives,
host chardevs, etc. and to make block/chardev/etc. properties be simply
links (after QOMification). That's distant, but we should get it
right before assumptions about global pathnames to pervade the code.
The patch is not even compiled, and absolutely not in shape for getting
in (but really, the only major hurdle for it is really Anthony's part 3
and pushing properties up in the hierarchy). The usual questions about
this being the right thing to do already apply though. And also: should
QOM class names be part of the ABI/API?
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/qdev.c | 34 +++++++++++++++++++++++++---------
include/qemu/object.h | 7 +++++++
qapi-schema.json | 6 +++---
qmp.c | 26 ++++++++++++++++++++++----
qom/object.c | 15 +++++++++++++++
roms/SLOF | 2 +-
roms/seabios | 2 +-
7 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/hw/qdev.c b/hw/qdev.c
index a8c24de..1b8c1cd 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -43,6 +43,8 @@ DeviceInfo *device_info_list;
static BusState *qbus_find_recursive(BusState *bus, const char *name,
const BusInfo *info);
static BusState *qbus_find(const char *path);
+static Object *device_resolve_path(const char *path, bool *ambiguous);
+static gchar *device_get_canonical_path(Object *obj);
/* Register a new device type. */
static void qdev_subclass_init(ObjectClass *klass, void *data)
@@ -51,6 +53,8 @@ static void qdev_subclass_init(ObjectClass *klass, void *data)
dc->info = data;
dc->reset = dc->info->reset;
+ dc->parent_class.resolve_path = device_resolve_path;
+ dc->parent_class.get_canonical_path = device_get_canonical_path;
/* Poison to try to detect future uses */
dc->info->reset = NULL;
@@ -1329,11 +1333,11 @@ void qdev_property_add_child(DeviceState *dev, const char *name,
static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- DeviceState **child = opaque;
+ Object **child = opaque;
gchar *path;
if (*child) {
- path = qdev_get_canonical_path(*child);
+ path = object_get_canonical_path(*child);
visit_type_str(v, &path, name, errp);
g_free(path);
} else {
@@ -1345,7 +1349,7 @@ static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- DeviceState **child = opaque;
+ Object **child = opaque;
bool ambiguous = false;
const char *type;
char *path;
@@ -1359,16 +1363,16 @@ static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
}
if (strcmp(path, "") != 0) {
- DeviceState *target;
+ Object *target;
- target = qdev_resolve_path(path, &ambiguous);
+ target = object_resolve_path(type, path, &ambiguous);
if (target) {
gchar *target_type;
target_type = g_strdup_printf("link<%s>", object_get_typename(OBJECT(target)));
if (strcmp(target_type, type) == 0) {
*child = target;
- qdev_ref(target);
+ qdev_ref(DEVICE(target));
} else {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
}
@@ -1400,10 +1404,11 @@ void qdev_property_add_link(DeviceState *dev, const char *name,
g_free(full_type);
}
-gchar *qdev_get_canonical_path(DeviceState *dev)
+gchar *device_get_canonical_path(Object *obj)
{
DeviceState *root = qdev_get_root();
char *newpath = NULL, *path = NULL;
+ DeviceState *dev = DEVICE(obj);
while (dev != root) {
DeviceProperty *prop = NULL;
@@ -1438,6 +1443,11 @@ gchar *qdev_get_canonical_path(DeviceState *dev)
return newpath;
}
+gchar *qdev_get_canonical_path(DeviceState *dev)
+{
+ return object_get_canonical_path(OBJECT(dev));
+}
+
static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
gchar **parts,
int index)
@@ -1510,7 +1520,7 @@ static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
return dev;
}
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
+Object *device_resolve_path(const char *path, bool *ambiguous)
{
bool partial_path = true;
DeviceState *dev;
@@ -1537,7 +1547,13 @@ DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
g_strfreev(parts);
- return dev;
+ return OBJECT(dev);
+}
+
+DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
+{
+ Object *obj = object_resolve_path(TYPE_DEVICE, path, ambiguous);
+ return DEVICE(obj);
}
typedef struct StringProperty
diff --git a/include/qemu/object.h b/include/qemu/object.h
index ba37850..33728e3 100644
--- a/include/qemu/object.h
+++ b/include/qemu/object.h
@@ -122,6 +122,9 @@ typedef struct InterfaceInfo InterfaceInfo;
*/
struct ObjectClass
{
+ Object *(*resolve_path)(const char *path, bool *ambiguous);
+ gchar *(*get_canonical_path)(Object *obj);
+
/*< private >*/
Type type;
};
@@ -420,6 +423,10 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *klass,
ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
const char *typename);
+Object *object_resolve_path(const char *typename, const char *path,
+ bool *ambiguous);
+gchar *object_get_canonical_path(Object *obj);
+
/**
* object_class_get_name:
* @klass: The class to obtain the QOM typename for.
diff --git a/qapi-schema.json b/qapi-schema.json
index 80debe6..a47f689 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1249,7 +1249,7 @@
# releases.
##
{ 'command': 'qom-list',
- 'data': { 'path': 'str' },
+ 'data': { '*class': 'str', 'path': 'str' },
'returns': [ 'DevicePropertyInfo' ] }
##
@@ -1287,7 +1287,7 @@
# Notes: This command is experimental and may change syntax in future releases.
##
{ 'command': 'qom-get',
- 'data': { 'path': 'str', 'property': 'str' },
+ 'data': { '*class': 'str', 'path': 'str', 'property': 'str' },
'returns': 'visitor',
'gen': 'no' }
@@ -1308,7 +1308,7 @@
# Notes: This command is experimental and may change syntax in future releases.
##
{ 'command': 'qom-set',
- 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
+ 'data': { '*class': 'str', 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' }
##
diff --git a/qmp.c b/qmp.c
index 1222b6c..a869af8 100644
--- a/qmp.c
+++ b/qmp.c
@@ -164,14 +164,20 @@ void qmp_cont(Error **errp)
vm_start();
}
-DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
+DevicePropertyInfoList *qmp_qom_list(const char *class, const char *path,
+ Error **errp)
{
+ Object *obj;
DeviceState *dev;
bool ambiguous = false;
DevicePropertyInfoList *props = NULL;
DeviceProperty *prop;
- dev = qdev_resolve_path(path, &ambiguous);
+ if (!class) {
+ class = TYPE_DEVICE;
+ }
+ obj = object_resolve_path(class, path, &ambiguous);
+ dev = DEVICE(obj);
if (dev == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
return NULL;
@@ -194,14 +200,20 @@ DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
/* FIXME: teach qapi about how to pass through Visitors */
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
{
+ const char *class = qdict_get_str(qdict, "class");
const char *path = qdict_get_str(qdict, "path");
const char *property = qdict_get_str(qdict, "property");
QObject *value = qdict_get(qdict, "value");
Error *local_err = NULL;
+ Object *obj;
QmpInputVisitor *mi;
DeviceState *dev;
- dev = qdev_resolve_path(path, NULL);
+ if (!class) {
+ class = TYPE_DEVICE;
+ }
+ obj = object_resolve_path(class, path, NULL);
+ dev = DEVICE(obj);
if (!dev) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
@@ -224,13 +236,19 @@ out:
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
{
+ const char *class = qdict_get_str(qdict, "class");
const char *path = qdict_get_str(qdict, "path");
const char *property = qdict_get_str(qdict, "property");
Error *local_err = NULL;
QmpOutputVisitor *mo;
+ Object *obj;
DeviceState *dev;
- dev = qdev_resolve_path(path, NULL);
+ if (!class) {
+ class = TYPE_DEVICE;
+ }
+ obj = object_resolve_path(class, path, NULL);
+ dev = DEVICE(obj);
if (!dev) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
diff --git a/qom/object.c b/qom/object.c
index a12895f..fd8f3f9 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -488,3 +488,18 @@ void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
}
+
+gchar *object_get_canonical_path(Object *obj)
+{
+ return obj->class->get_canonical_path(obj);
+}
+
+Object *object_resolve_path(const char *typename, const char *path,
+ bool *ambiguous)
+{
+ ObjectClass *klass = object_class_by_name(typename);
+ if (!klass->resolve_path) {
+ return NULL;
+ }
+ return klass->resolve_path(path, ambiguous);
+}
diff --git a/roms/SLOF b/roms/SLOF
index ab062ff..32e3430 160000
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit ab062ff3b37c39649f2b0d94ed607adc6f6b3c7d
+Subproject commit 32e3430c018ceb8413cb808477449d1968c42497
diff --git a/roms/seabios b/roms/seabios
index 80d11e8..8e30147 160000
--- a/roms/seabios
+++ b/roms/seabios
@@ -1 +1 @@
-Subproject commit 80d11e8577bf03e98f2eb1b0cb3a281ab2879c9e
+Subproject commit 8e301472e324b6d6496d8b4ffc66863e99d7a505
--
1.7.7.6
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] generalize QOM path resolution
2012-01-30 12:53 [Qemu-devel] [RFC PATCH] generalize QOM path resolution Paolo Bonzini
@ 2012-01-30 13:39 ` Anthony Liguori
2012-01-30 14:03 ` Paolo Bonzini
0 siblings, 1 reply; 5+ messages in thread
From: Anthony Liguori @ 2012-01-30 13:39 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel
On 01/30/2012 06:53 AM, Paolo Bonzini wrote:
> Right now, resolving a string to an object is not generic to QOM,
> but rather it is entirely embedded in qdev (the Device class).
> This embryo patch generalizes the concept adding a resolve_path
> class method, and get_canonical_path instance method, to Object.
https://github.com/aliguori/qemu/commit/c354035aa4d2e30eb4d3864c5a7d8e9ef23a7deb
This is in series 3/4 which I'm going to try to clean up enough to post today.
> Link properties use the type to direct sets to the right resolve_path
> method, while the qom-{get,set,list} commands get a class argument.
>
> This is needed to have different namespaces for devices, host drives,
> host chardevs, etc. and to make block/chardev/etc. properties be simply
> links (after QOMification).
I'm not sure I understand... There should be one global namespace and only one
global namespace.
We can maintain compatibility by giving each legacy command option it's own
directory within the tree (just like we stick -device creations into
/peripherial, -drive would have a /drive sub directory).
> That's distant, but we should get it
> right before assumptions about global pathnames to pervade the code.
>
> The patch is not even compiled, and absolutely not in shape for getting
> in (but really, the only major hurdle for it is really Anthony's part 3
> and pushing properties up in the hierarchy). The usual questions about
> this being the right thing to do already apply though. And also: should
> QOM class names be part of the ABI/API?
The view I have re: QOM ABI/API:
We provide 100% ABI compatibility with QOM. The rules to achieve that are:
1) Once a type name is used, it never has a different semantic meaning.
2) Once a property is added to a type, it never has different semantic meaning.
It's QOM property type may change, provided that the types are Visitor-compatible.
3) Types can be removed and properties can be removed.
With respect to backwards compatibility, I don't think we should support
backwards compatibility in QOM across minor releases (1.1 -> 1.2, etc.) but only
within stable releases (1.1.1 -> 1.1.2).
For an application like libvirt, this should be fine because QOM exposes enough
information about it's features that libvirt can just probe for various
interfaces (it doesn't have to make decisions based on version numbers).
>
> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> ---
> hw/qdev.c | 34 +++++++++++++++++++++++++---------
> include/qemu/object.h | 7 +++++++
> qapi-schema.json | 6 +++---
> qmp.c | 26 ++++++++++++++++++++++----
> qom/object.c | 15 +++++++++++++++
> roms/SLOF | 2 +-
> roms/seabios | 2 +-
> 7 files changed, 74 insertions(+), 18 deletions(-)
>
> diff --git a/hw/qdev.c b/hw/qdev.c
> index a8c24de..1b8c1cd 100644
> --- a/hw/qdev.c
> +++ b/hw/qdev.c
> @@ -43,6 +43,8 @@ DeviceInfo *device_info_list;
> static BusState *qbus_find_recursive(BusState *bus, const char *name,
> const BusInfo *info);
> static BusState *qbus_find(const char *path);
> +static Object *device_resolve_path(const char *path, bool *ambiguous);
> +static gchar *device_get_canonical_path(Object *obj);
>
> /* Register a new device type. */
> static void qdev_subclass_init(ObjectClass *klass, void *data)
> @@ -51,6 +53,8 @@ static void qdev_subclass_init(ObjectClass *klass, void *data)
>
> dc->info = data;
> dc->reset = dc->info->reset;
> + dc->parent_class.resolve_path = device_resolve_path;
> + dc->parent_class.get_canonical_path = device_get_canonical_path;
I definitely don't want to have multiple object graphs. The object graph should
reflect the real relationships between objects in QEMU.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] generalize QOM path resolution
2012-01-30 13:39 ` Anthony Liguori
@ 2012-01-30 14:03 ` Paolo Bonzini
2012-01-30 14:28 ` Anthony Liguori
0 siblings, 1 reply; 5+ messages in thread
From: Paolo Bonzini @ 2012-01-30 14:03 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On 01/30/2012 02:39 PM, Anthony Liguori wrote:
> On 01/30/2012 06:53 AM, Paolo Bonzini wrote:
>> Right now, resolving a string to an object is not generic to QOM,
>> but rather it is entirely embedded in qdev (the Device class).
>> This embryo patch generalizes the concept adding a resolve_path
>> class method, and get_canonical_path instance method, to Object.
>
> https://github.com/aliguori/qemu/commit/c354035aa4d2e30eb4d3864c5a7d8e9ef23a7deb
>
> This is in series 3/4 which I'm going to try to clean up enough to post
> today.
Yeah, there's many good things in there and we happen to disagree on
this one. :)
>> Link properties use the type to direct sets to the right resolve_path
>> method, while the qom-{get,set,list} commands get a class argument.
>>
>> This is needed to have different namespaces for devices, host drives,
>> host chardevs, etc. and to make block/chardev/etc. properties be simply
>> links (after QOMification).
>
> I'm not sure I understand... There should be one global namespace and
> only one global namespace.
>
> We can maintain compatibility by giving each legacy command option it's
> own directory within the tree (just like we stick -device creations into
> /peripherial, -drive would have a /drive sub directory).
I think that you're giving too much weight to the "legacy" aspect. We
should try to design things so that (while keeping good taste overall)
the legacy parts can be minimized asap and instead the QOM view of the
world starts surfacing into the upper layers---including the
command-line. Striving for perfection means that we'll be stuck forever
with large legacy pieces and no dogfooding for the cool bits.
One of the next things I want to do is to remove the legacy properties
when the normal ones do exactly the same. For property types that are
using get_generic/set_generic we can basically change the upper layers
to use get/set directly instead of parse/print. Most of these cases, in
turn, are going to become link properties to block devices or character
devices. Here are two things I absolutely would like to avoid:
1) having the legacy aspect disappear for now, only to reappear after
block or character devices are converted to QOM;
2) having to introduce legacy properties whose QOM counterpart is a link.
Once we have QOMified enough that a property can be a link, you should
be able to drop its legacy counterpart.
I see your point about having a single global namespace, but shoehorning
entirely different branches of the tree into the same namespace
introduces gratuitous incompatibilities between the qdev and the QOM
views of the world. And these are bad, because they limit the amount of
QOM dogfooding that we can do inside QEMU itself.
You are not going to have anyway a link<Object>. That makes it fine to
resolve a link<Block> and a link<Device> according to different rules.
> We provide 100% ABI compatibility with QOM. The rules to achieve that are:
>
> 1) Once a type name is used, it never has a different semantic meaning.
>
> 2) Once a property is added to a type, it never has different semantic
> meaning. It's QOM property type may change, provided that the types are
> Visitor-compatible.
>
> 3) Types can be removed and properties can be removed.
That sounds good.
Paolo
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] generalize QOM path resolution
2012-01-30 14:03 ` Paolo Bonzini
@ 2012-01-30 14:28 ` Anthony Liguori
2012-01-30 15:18 ` Paolo Bonzini
0 siblings, 1 reply; 5+ messages in thread
From: Anthony Liguori @ 2012-01-30 14:28 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel
On 01/30/2012 08:03 AM, Paolo Bonzini wrote:
> On 01/30/2012 02:39 PM, Anthony Liguori wrote:
>> On 01/30/2012 06:53 AM, Paolo Bonzini wrote:
>>> Right now, resolving a string to an object is not generic to QOM,
>>> but rather it is entirely embedded in qdev (the Device class).
>>> This embryo patch generalizes the concept adding a resolve_path
>>> class method, and get_canonical_path instance method, to Object.
>>
>> https://github.com/aliguori/qemu/commit/c354035aa4d2e30eb4d3864c5a7d8e9ef23a7deb
>>
>> This is in series 3/4 which I'm going to try to clean up enough to post
>> today.
>
> Yeah, there's many good things in there and we happen to disagree on this one. :)
>
>>> Link properties use the type to direct sets to the right resolve_path
>>> method, while the qom-{get,set,list} commands get a class argument.
>>>
>>> This is needed to have different namespaces for devices, host drives,
>>> host chardevs, etc. and to make block/chardev/etc. properties be simply
>>> links (after QOMification).
>>
>> I'm not sure I understand... There should be one global namespace and
>> only one global namespace.
>>
>> We can maintain compatibility by giving each legacy command option it's
>> own directory within the tree (just like we stick -device creations into
>> /peripherial, -drive would have a /drive sub directory).
>
> I think that you're giving too much weight to the "legacy" aspect. We should try
> to design things so that (while keeping good taste overall) the legacy parts can
> be minimized asap and instead the QOM view of the world starts surfacing into
> the upper layers---including the command-line. Striving for perfection means
> that we'll be stuck forever with large legacy pieces and no dogfooding for the
> cool bits.
>
> One of the next things I want to do is to remove the legacy properties when the
> normal ones do exactly the same. For property types that are using
> get_generic/set_generic we can basically change the upper layers to use get/set
> directly instead of parse/print. Most of these cases, in turn, are going to
> become link properties to block devices or character devices. Here are two
> things I absolutely would like to avoid:
>
> 1) having the legacy aspect disappear for now, only to reappear after block or
> character devices are converted to QOM;
>
> 2) having to introduce legacy properties whose QOM counterpart is a link.
>
> Once we have QOMified enough that a property can be a link, you should be able
> to drop its legacy counterpart.
>
> I see your point about having a single global namespace, but shoehorning
> entirely different branches of the tree into the same namespace introduces
> gratuitous incompatibilities between the qdev and the QOM views of the world.
> And these are bad, because they limit the amount of QOM dogfooding that we can
> do inside QEMU itself.
>
> You are not going to have anyway a link<Object>. That makes it fine to resolve a
> link<Block> and a link<Device> according to different rules.
I think we agreed (in IRC) that we can handle this by changing
qdev_resolve_path() to take an optional TYPE argument which will cause
qdev_resolve_path() to only succeed if the resulting object implements TYPE.
This can be used to disambiguate partial path matches such that a
link<BlockDriverState> property would only attempt to do partial path
resolutions on objects that have BlockDriverState in their parent hierarchy.
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] generalize QOM path resolution
2012-01-30 14:28 ` Anthony Liguori
@ 2012-01-30 15:18 ` Paolo Bonzini
0 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2012-01-30 15:18 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On 01/30/2012 03:28 PM, Anthony Liguori wrote:
>>
>> You are not going to have anyway a link<Object>. That makes it fine to
>> resolve a
>> link<Block> and a link<Device> according to different rules.
>
> I think we agreed (in IRC) that we can handle this by changing
> qdev_resolve_path() to take an optional TYPE argument which will cause
> qdev_resolve_path() to only succeed if the resulting object implements
> TYPE.
>
> This can be used to disambiguate partial path matches such that a
> link<BlockDriverState> property would only attempt to do partial path
> resolutions on objects that have BlockDriverState in their parent
> hierarchy.
Yes.
Paolo
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-01-30 15:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-30 12:53 [Qemu-devel] [RFC PATCH] generalize QOM path resolution Paolo Bonzini
2012-01-30 13:39 ` Anthony Liguori
2012-01-30 14:03 ` Paolo Bonzini
2012-01-30 14:28 ` Anthony Liguori
2012-01-30 15:18 ` Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).