diff mbox

[1/2] virtio: Add backend feature testing functionnality

Message ID 1473416072-7063-2-git-send-email-maxime.coquelin@redhat.com
State New
Headers show

Commit Message

Maxime Coquelin Sept. 9, 2016, 10:14 a.m. UTC
This patch adds virtio_test_backend_feature() function to
enable checking a backend feature before the negociation
takes place.

It may be used, for example, to check whether the backend
supports VIRTIO_F_VERSION_1 before enabling modern
capabilities.

Cc: Marcel Apfelbaum <marcel@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
---
 hw/virtio/virtio.c         | 14 ++++++++++++++
 include/hw/virtio/virtio.h |  2 ++
 2 files changed, 16 insertions(+)

Comments

Cornelia Huck Sept. 9, 2016, 10:33 a.m. UTC | #1
On Fri,  9 Sep 2016 12:14:31 +0200
Maxime Coquelin <maxime.coquelin@redhat.com> wrote:

> This patch adds virtio_test_backend_feature() function to
> enable checking a backend feature before the negociation
> takes place.
> 
> It may be used, for example, to check whether the backend
> supports VIRTIO_F_VERSION_1 before enabling modern
> capabilities.
> 
> Cc: Marcel Apfelbaum <marcel@redhat.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> ---
>  hw/virtio/virtio.c         | 14 ++++++++++++++
>  include/hw/virtio/virtio.h |  2 ++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> index 74c085c..7ab91a1 100644
> --- a/hw/virtio/virtio.c
> +++ b/hw/virtio/virtio.c
> @@ -1481,6 +1481,20 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size)
>      virtio_save(VIRTIO_DEVICE(opaque), f);
>  }
> 
> +bool virtio_test_backend_feature(VirtIODevice *vdev,
> +                                 unsigned int fbit, Error **errp)
> +{
> +    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
> +    uint64_t feature;
> +
> +    virtio_add_feature(&feature, fbit);
> +
> +    assert(k->get_features != NULL);
> +    feature = k->get_features(vdev, feature, errp);
> +
> +    return virtio_has_feature(feature, fbit);
> +}
> +
>  static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
>  {
>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);

What happens if you want to test for features that depend upon each
other? The backend may support your feature, but it may withdraw the
feature bit if a dependency is not fullfilled.

You'll probably want to run validation on the whole feature set; but
that is hard if you're too early in the setup process.
Marcel Apfelbaum Sept. 9, 2016, 10:48 a.m. UTC | #2
On 09/09/2016 01:33 PM, Cornelia Huck wrote:
> On Fri,  9 Sep 2016 12:14:31 +0200
> Maxime Coquelin <maxime.coquelin@redhat.com> wrote:
>
>> This patch adds virtio_test_backend_feature() function to
>> enable checking a backend feature before the negociation
>> takes place.
>>
>> It may be used, for example, to check whether the backend
>> supports VIRTIO_F_VERSION_1 before enabling modern
>> capabilities.
>>
>> Cc: Marcel Apfelbaum <marcel@redhat.com>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Cc: qemu-stable@nongnu.org
>> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
>> ---
>>  hw/virtio/virtio.c         | 14 ++++++++++++++
>>  include/hw/virtio/virtio.h |  2 ++
>>  2 files changed, 16 insertions(+)
>>
>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>> index 74c085c..7ab91a1 100644
>> --- a/hw/virtio/virtio.c
>> +++ b/hw/virtio/virtio.c
>> @@ -1481,6 +1481,20 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size)
>>      virtio_save(VIRTIO_DEVICE(opaque), f);
>>  }
>>
>> +bool virtio_test_backend_feature(VirtIODevice *vdev,
>> +                                 unsigned int fbit, Error **errp)
>> +{
>> +    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>> +    uint64_t feature;
>> +
>> +    virtio_add_feature(&feature, fbit);
>> +
>> +    assert(k->get_features != NULL);
>> +    feature = k->get_features(vdev, feature, errp);
>> +
>> +    return virtio_has_feature(feature, fbit);
>> +}
>> +
>>  static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
>>  {
>>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>
> What happens if you want to test for features that depend upon each
> other? The backend may support your feature, but it may withdraw the
> feature bit if a dependency is not fullfilled.
>
> You'll probably want to run validation on the whole feature set; but
> that is hard if you're too early in the setup process.
>

While I agree with the feature dependency issue , would the negation be ok?
What I mean is: if the backend does not support feature X, no
matter what the depending features are, it will still not support it after the negotiation.

Changing the function to virtio_backend_unsupported_feature(x) would be better?

Thanks,
Marcel
Cornelia Huck Sept. 9, 2016, 10:55 a.m. UTC | #3
On Fri, 9 Sep 2016 13:48:00 +0300
Marcel Apfelbaum <marcel@redhat.com> wrote:

> On 09/09/2016 01:33 PM, Cornelia Huck wrote:
> > On Fri,  9 Sep 2016 12:14:31 +0200
> > Maxime Coquelin <maxime.coquelin@redhat.com> wrote:
> >
> >> This patch adds virtio_test_backend_feature() function to
> >> enable checking a backend feature before the negociation
> >> takes place.
> >>
> >> It may be used, for example, to check whether the backend
> >> supports VIRTIO_F_VERSION_1 before enabling modern
> >> capabilities.
> >>
> >> Cc: Marcel Apfelbaum <marcel@redhat.com>
> >> Cc: Michael S. Tsirkin <mst@redhat.com>
> >> Cc: qemu-stable@nongnu.org
> >> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> >> ---
> >>  hw/virtio/virtio.c         | 14 ++++++++++++++
> >>  include/hw/virtio/virtio.h |  2 ++
> >>  2 files changed, 16 insertions(+)
> >>
> >> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
> >> index 74c085c..7ab91a1 100644
> >> --- a/hw/virtio/virtio.c
> >> +++ b/hw/virtio/virtio.c
> >> @@ -1481,6 +1481,20 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size)
> >>      virtio_save(VIRTIO_DEVICE(opaque), f);
> >>  }
> >>
> >> +bool virtio_test_backend_feature(VirtIODevice *vdev,
> >> +                                 unsigned int fbit, Error **errp)
> >> +{
> >> +    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
> >> +    uint64_t feature;
> >> +
> >> +    virtio_add_feature(&feature, fbit);
> >> +
> >> +    assert(k->get_features != NULL);
> >> +    feature = k->get_features(vdev, feature, errp);
> >> +
> >> +    return virtio_has_feature(feature, fbit);
> >> +}
> >> +
> >>  static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
> >>  {
> >>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
> >
> > What happens if you want to test for features that depend upon each
> > other? The backend may support your feature, but it may withdraw the
> > feature bit if a dependency is not fullfilled.
> >
> > You'll probably want to run validation on the whole feature set; but
> > that is hard if you're too early in the setup process.
> >
> 
> While I agree with the feature dependency issue , would the negation be ok?
> What I mean is: if the backend does not support feature X, no
> matter what the depending features are, it will still not support it after the negotiation.
> 
> Changing the function to virtio_backend_unsupported_feature(x) would be better?

I think yes, although that would mean we need a new query function that
pokes through all the layers, no?
Marcel Apfelbaum Sept. 9, 2016, 11:02 a.m. UTC | #4
On 09/09/2016 01:55 PM, Cornelia Huck wrote:
> On Fri, 9 Sep 2016 13:48:00 +0300
> Marcel Apfelbaum <marcel@redhat.com> wrote:
>
>> On 09/09/2016 01:33 PM, Cornelia Huck wrote:
>>> On Fri,  9 Sep 2016 12:14:31 +0200
>>> Maxime Coquelin <maxime.coquelin@redhat.com> wrote:
>>>
>>>> This patch adds virtio_test_backend_feature() function to
>>>> enable checking a backend feature before the negociation
>>>> takes place.
>>>>
>>>> It may be used, for example, to check whether the backend
>>>> supports VIRTIO_F_VERSION_1 before enabling modern
>>>> capabilities.
>>>>
>>>> Cc: Marcel Apfelbaum <marcel@redhat.com>
>>>> Cc: Michael S. Tsirkin <mst@redhat.com>
>>>> Cc: qemu-stable@nongnu.org
>>>> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
>>>> ---
>>>>  hw/virtio/virtio.c         | 14 ++++++++++++++
>>>>  include/hw/virtio/virtio.h |  2 ++
>>>>  2 files changed, 16 insertions(+)
>>>>
>>>> diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
>>>> index 74c085c..7ab91a1 100644
>>>> --- a/hw/virtio/virtio.c
>>>> +++ b/hw/virtio/virtio.c
>>>> @@ -1481,6 +1481,20 @@ void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size)
>>>>      virtio_save(VIRTIO_DEVICE(opaque), f);
>>>>  }
>>>>
>>>> +bool virtio_test_backend_feature(VirtIODevice *vdev,
>>>> +                                 unsigned int fbit, Error **errp)
>>>> +{
>>>> +    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>>>> +    uint64_t feature;
>>>> +
>>>> +    virtio_add_feature(&feature, fbit);
>>>> +
>>>> +    assert(k->get_features != NULL);
>>>> +    feature = k->get_features(vdev, feature, errp);
>>>> +
>>>> +    return virtio_has_feature(feature, fbit);
>>>> +}
>>>> +
>>>>  static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
>>>>  {
>>>>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>>>
>>> What happens if you want to test for features that depend upon each
>>> other? The backend may support your feature, but it may withdraw the
>>> feature bit if a dependency is not fullfilled.
>>>
>>> You'll probably want to run validation on the whole feature set; but
>>> that is hard if you're too early in the setup process.
>>>
>>
>> While I agree with the feature dependency issue , would the negation be ok?
>> What I mean is: if the backend does not support feature X, no
>> matter what the depending features are, it will still not support it after the negotiation.
>>
>> Changing the function to virtio_backend_unsupported_feature(x) would be better?
>
> I think yes, although that would mean we need a new query function that
> pokes through all the layers, no?
>

I was thinking to keep the same function proposed by Maxime and change it to negate things:

/*
  * A missing feature before all negotiations finished will still be missing at the end.
  */
bool virtio_test_backend_unsupported_feature(VirtIODevice *vdev,
                                              unsigned int fbit, Error **errp)
{
     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint64_t feature;

     virtio_add_feature(&feature, fbit);

     assert(k->get_features != NULL);
     feature = k->get_features(vdev, feature, errp);

     return !virtio_has_feature(feature, fbit);
}

We only check if the feature was not there from the start.

Thanks,
Marcel
Cornelia Huck Sept. 9, 2016, 11:20 a.m. UTC | #5
On Fri, 9 Sep 2016 14:02:17 +0300
Marcel Apfelbaum <marcel@redhat.com> wrote:

> I was thinking to keep the same function proposed by Maxime and change it to negate things:
> 
> /*
>   * A missing feature before all negotiations finished will still be missing at the end.
>   */
> bool virtio_test_backend_unsupported_feature(VirtIODevice *vdev,
>                                               unsigned int fbit, Error **errp)
> {
>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>      uint64_t feature;
> 
>      virtio_add_feature(&feature, fbit);
> 
>      assert(k->get_features != NULL);
>      feature = k->get_features(vdev, feature, errp);
> 
>      return !virtio_has_feature(feature, fbit);
> }
> 
> We only check if the feature was not there from the start.

I think you'll still end up with the same problem (overindicating
unsupportedness), as you start out with an otherwise empty feature
set, causing features with dependencies to be removed. I fear that
anything starting with an incomplete feature list will have that
problem.

Maybe it would be better to limit this to the one bit we currently want
to test (VERSION_1)? We know the semantics of that one. Less general,
but also less headaches.
Maxime Coquelin Sept. 9, 2016, 11:36 a.m. UTC | #6
On 09/09/2016 01:20 PM, Cornelia Huck wrote:
> On Fri, 9 Sep 2016 14:02:17 +0300
> Marcel Apfelbaum <marcel@redhat.com> wrote:
>
>> I was thinking to keep the same function proposed by Maxime and change it to negate things:
>>
>> /*
>>   * A missing feature before all negotiations finished will still be missing at the end.
>>   */
>> bool virtio_test_backend_unsupported_feature(VirtIODevice *vdev,
>>                                               unsigned int fbit, Error **errp)
>> {
>>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>>      uint64_t feature;
>>
>>      virtio_add_feature(&feature, fbit);
>>
>>      assert(k->get_features != NULL);
>>      feature = k->get_features(vdev, feature, errp);
>>
>>      return !virtio_has_feature(feature, fbit);
>> }
>>
>> We only check if the feature was not there from the start.
>
> I think you'll still end up with the same problem (overindicating
> unsupportedness), as you start out with an otherwise empty feature
> set, causing features with dependencies to be removed. I fear that
> anything starting with an incomplete feature list will have that
> problem.
>
> Maybe it would be better to limit this to the one bit we currently want
> to test (VERSION_1)? We know the semantics of that one. Less general,
> but also less headaches.

Yes, that could be the solution.
I agree that making it too generic might create confusion
with some features.

Thanks,
Maxime
Marcel Apfelbaum Sept. 9, 2016, 11:47 a.m. UTC | #7
On 09/09/2016 02:36 PM, Maxime Coquelin wrote:
>
>
> On 09/09/2016 01:20 PM, Cornelia Huck wrote:
>> On Fri, 9 Sep 2016 14:02:17 +0300
>> Marcel Apfelbaum <marcel@redhat.com> wrote:
>>
>>> I was thinking to keep the same function proposed by Maxime and change it to negate things:
>>>
>>> /*
>>>   * A missing feature before all negotiations finished will still be missing at the end.
>>>   */
>>> bool virtio_test_backend_unsupported_feature(VirtIODevice *vdev,
>>>                                               unsigned int fbit, Error **errp)
>>> {
>>>      VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
>>>      uint64_t feature;
>>>
>>>      virtio_add_feature(&feature, fbit);
>>>
>>>      assert(k->get_features != NULL);
>>>      feature = k->get_features(vdev, feature, errp);
>>>
>>>      return !virtio_has_feature(feature, fbit);
>>> }
>>>
>>> We only check if the feature was not there from the start.
>>
>> I think you'll still end up with the same problem (overindicating
>> unsupportedness), as you start out with an otherwise empty feature
>> set, causing features with dependencies to be removed. I fear that
>> anything starting with an incomplete feature list will have that
>> problem.
>>
>> Maybe it would be better to limit this to the one bit we currently want
>> to test (VERSION_1)? We know the semantics of that one. Less general,
>> but also less headaches.
>
> Yes, that could be the solution.
> I agree that making it too generic might create confusion
> with some features.
>

Sounds good to me. Let's go with it and we'll re-think it if
we'll find other feature negotiation issues later.

Thanks,
Marcel


> Thanks,
> Maxime
>
diff mbox

Patch

diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 74c085c..7ab91a1 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1481,6 +1481,20 @@  void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size)
     virtio_save(VIRTIO_DEVICE(opaque), f);
 }
 
+bool virtio_test_backend_feature(VirtIODevice *vdev,
+                                 unsigned int fbit, Error **errp)
+{
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+    uint64_t feature;
+
+    virtio_add_feature(&feature, fbit);
+
+    assert(k->get_features != NULL);
+    feature = k->get_features(vdev, feature, errp);
+
+    return virtio_has_feature(feature, fbit);
+}
+
 static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
 {
     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index d2490c1..5fb74c8 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -235,6 +235,8 @@  int virtio_set_status(VirtIODevice *vdev, uint8_t val);
 void virtio_reset(void *opaque);
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint64_t val);
+bool virtio_test_backend_feature(VirtIODevice *vdev,
+                                 unsigned int fbit, Error **errp);
 
 /* Base devices.  */
 typedef struct VirtIOBlkConf VirtIOBlkConf;