On Mon, Sep 21, 2020 at 10:51:16 +0300, Nikolay Shirokovskiy wrote: > Currently virDomainMigrate3 reports "this function is not supported by the > connection driver: virDomainMigrate3" if connection to destination for example > is broken. This is a bit misleading. > > This is a result of we treat errors as unsupported feature in > VIR_DRV_SUPPORTS_FEATURE macro. So let's handle errors instead. In order to > keep logic clean as before there are new helper functions > virDrvSupportsFeature/virDrvNSupportsFeature. They allow to keep if/else if > structure of feature tests. > > I guess all the other occurences of VIR_DRV_SUPPORTS_FEATURE need to be > replaced with one these new helper functions so that we detect error early and > not have issues similar to virDomainMigrate3. I'm going to fix the other > places if this RFC is approved. To be honest, I think this is quite ugly. > > --- > src/datatypes.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ > src/datatypes.h | 7 +++++ > src/libvirt-domain.c | 76 +++++++++++++++++++++++++++++++--------------------- > 3 files changed, 123 insertions(+), 30 deletions(-) > > diff --git a/src/datatypes.c b/src/datatypes.c > index 1db38c5..3fb71f4 100644 > --- a/src/datatypes.c > +++ b/src/datatypes.c > @@ -1257,3 +1257,73 @@ virAdmClientDispose(void *obj) > > virObjectUnref(clt->srv); > } > + > + > +/* > + * Tests if feature is supported by connection. If testing failed > + * due to error then function returns true as well and set @err flag > + * to true. Thus positive result should be checked for an error. > + * If @err is already set to true then no checking is done and > + * the function returns true immediately so that previous error > + * is not overwritten. > + * > + * Returns: > + * true feature is supported or testing hit error > + * false feature is not supported > + */ > +bool > +virDrvSupportsFeature(virConnectPtr conn, > + virDrvFeature feature, > + bool *err) > +{ > + int rc; > + > + if (*err) > + return true; > + > + if (!conn->driver->connectSupportsFeature) > + return false; > + > + if ((rc = conn->driver->connectSupportsFeature(conn, feature)) < 0) { > + *err = true; > + return true; > + } > + > + return rc > 0 ? true : false; > +} I would just make virDrvSupportsFeature a tiny wrapper around conn->driver->connectSupportsFeature checking conn->driver->connectSupportsFeature != NULL and that's it. It could break the if/elseif flow, but with much cleaner semantics and reduced black magic. Jirka