diff mbox

[v2,kvmtool,07/10] vfio-pci: add MSI-X support

Message ID ca4c2d0f-883b-379f-27bd-d86a436870d2@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jean-Philippe Brucker Aug. 2, 2017, 3:18 p.m. UTC
On 01/08/17 17:04, Punit Agrawal wrote:
[...]
> I think I've figured out what's going wrong. pci_for_each_cap is defined
> as - 
> 
> #define pci_for_each_cap(pos, cap, hdr)                         \
>         for ((pos) = (hdr)->capabilities & ~3;                  \
>              (cap) = (void *)(hdr) + (pos), (pos) != 0;         \
>              (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
> 
> Here cap is being assigned before the pos != 0 check. So in the last
> iteration through the loop, cap will point to the start of the PCI
> header - which is then used to set "last->next = pos".

Ah right, sorry about that. How about moving the pos check in front? Does
the following work for you?

Comments

Punit Agrawal Aug. 3, 2017, 10:25 a.m. UTC | #1
Jean-Philippe Brucker <jean-philippe.brucker@arm.com> writes:

> On 01/08/17 17:04, Punit Agrawal wrote:
> [...]
>> I think I've figured out what's going wrong. pci_for_each_cap is defined
>> as - 
>> 
>> #define pci_for_each_cap(pos, cap, hdr)                         \
>>         for ((pos) = (hdr)->capabilities & ~3;                  \
>>              (cap) = (void *)(hdr) + (pos), (pos) != 0;         \
>>              (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
>> 
>> Here cap is being assigned before the pos != 0 check. So in the last
>> iteration through the loop, cap will point to the start of the PCI
>> header - which is then used to set "last->next = pos".
>
> Ah right, sorry about that. How about moving the pos check in front? Does
> the following work for you?
>
> diff --git a/include/kvm/pci.h b/include/kvm/pci.h
> index c5fc8254..37a65956 100644
> --- a/include/kvm/pci.h
> +++ b/include/kvm/pci.h
> @@ -142,9 +142,9 @@ struct pci_device_header {
>  	enum irq_type	irq_type;
>  };
>  
> -#define pci_for_each_cap(pos, cap, hdr)				\
> -	for ((pos) = (hdr)->capabilities & ~3;			\
> -	     (cap) = (void *)(hdr) + (pos), (pos) != 0;		\
> +#define pci_for_each_cap(pos, cap, hdr)					\
> +	for ((pos) = (hdr)->capabilities & ~3;				\
> +	     (pos) != 0 && ({ (cap) = (void *)(hdr) + (pos); 1; });	\
>  	     (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
>  
>  int pci__init(struct kvm *kvm);

The compiler throws a warning with the above change and fails to compile
(as all warnings are treated as error by kvmtool build) -

vfio/pci.c: In function ‘vfio_pci_setup_device’:
vfio/pci.c:511:14: error: ‘last’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
   last->next = pos;
   ~~~~~~~~~~~^~~~~
vfio/pci.c:507:23: note: ‘last’ was declared here
   struct pci_cap_hdr *last;
                       ^~~~
Jean-Philippe Brucker Aug. 3, 2017, 10:53 a.m. UTC | #2
On 03/08/17 11:25, Punit Agrawal wrote:
> Jean-Philippe Brucker <jean-philippe.brucker@arm.com> writes:
> 
>> On 01/08/17 17:04, Punit Agrawal wrote:
>> [...]
>>> I think I've figured out what's going wrong. pci_for_each_cap is defined
>>> as - 
>>>
>>> #define pci_for_each_cap(pos, cap, hdr)                         \
>>>         for ((pos) = (hdr)->capabilities & ~3;                  \
>>>              (cap) = (void *)(hdr) + (pos), (pos) != 0;         \
>>>              (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
>>>
>>> Here cap is being assigned before the pos != 0 check. So in the last
>>> iteration through the loop, cap will point to the start of the PCI
>>> header - which is then used to set "last->next = pos".
>>
>> Ah right, sorry about that. How about moving the pos check in front? Does
>> the following work for you?
>>
>> diff --git a/include/kvm/pci.h b/include/kvm/pci.h
>> index c5fc8254..37a65956 100644
>> --- a/include/kvm/pci.h
>> +++ b/include/kvm/pci.h
>> @@ -142,9 +142,9 @@ struct pci_device_header {
>>  	enum irq_type	irq_type;
>>  };
>>  
>> -#define pci_for_each_cap(pos, cap, hdr)				\
>> -	for ((pos) = (hdr)->capabilities & ~3;			\
>> -	     (cap) = (void *)(hdr) + (pos), (pos) != 0;		\
>> +#define pci_for_each_cap(pos, cap, hdr)					\
>> +	for ((pos) = (hdr)->capabilities & ~3;				\
>> +	     (pos) != 0 && ({ (cap) = (void *)(hdr) + (pos); 1; });	\
>>  	     (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
>>  
>>  int pci__init(struct kvm *kvm);
> 
> The compiler throws a warning with the above change and fails to compile
> (as all warnings are treated as error by kvmtool build) -
> 
> vfio/pci.c: In function ‘vfio_pci_setup_device’:
> vfio/pci.c:511:14: error: ‘last’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
>    last->next = pos;
>    ~~~~~~~~~~~^~~~~
> vfio/pci.c:507:23: note: ‘last’ was declared here
>    struct pci_cap_hdr *last;
>                        ^~~~
 Ok fair enough. In practice this wouldn't happen, as there is at least
one capability in the chain when we get there (the compiler might get
confused by the "& ~3" masking, which doesn't matter for our virtual
values). But the specialization you proposed to get the last capability
should be fine, I'll go with that in the next version.

Thanks,
Jean
diff mbox

Patch

diff --git a/include/kvm/pci.h b/include/kvm/pci.h
index c5fc8254..37a65956 100644
--- a/include/kvm/pci.h
+++ b/include/kvm/pci.h
@@ -142,9 +142,9 @@  struct pci_device_header {
 	enum irq_type	irq_type;
 };
 
-#define pci_for_each_cap(pos, cap, hdr)				\
-	for ((pos) = (hdr)->capabilities & ~3;			\
-	     (cap) = (void *)(hdr) + (pos), (pos) != 0;		\
+#define pci_for_each_cap(pos, cap, hdr)					\
+	for ((pos) = (hdr)->capabilities & ~3;				\
+	     (pos) != 0 && ({ (cap) = (void *)(hdr) + (pos); 1; });	\
 	     (pos) = ((struct pci_cap_hdr *)(cap))->next & ~3)
 
 int pci__init(struct kvm *kvm);