|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 2/2] xen/arm: vpl011: Fix domain_vpl011_init error path
Hi Julien,
On 22/03/2023 17:19, Julien Grall wrote:
>
>
> Hi Michal,
>
> On 22/03/2023 10:29, Michal Orzel wrote:
>> When vgic_reserve_virq() fails and backend is in domain, we should also
>> free the allocated event channel.
>>
>> When backend is in Xen and call to xzalloc() returns NULL, there is no
>> need to call xfree(). This should be done instead on an error path
>> from vgic_reserve_virq().
>
> Most likely this was implemented this way to avoid a double "if (
> vpl011->backend_in_domain)". TBH, I am not very thrilled with this
> approach. Could we instead consider to use domain_pl011_deinit()? (A
> couple of tweak would be necessary to use it)
I think we could. More about it later.
>
>> Also, take the opportunity to return -ENOMEM
>> instead of -EINVAL when memory allocation fails.
>>
>> Fixes: 1ee1e4b0d1ff ("xen/arm: Allow vpl011 to be used by DomU")
>> Signed-off-by: Michal Orzel <michal.orzel@xxxxxxx>
>> ---
>> xen/arch/arm/vpl011.c | 11 +++++++----
>> 1 file changed, 7 insertions(+), 4 deletions(-)
>>
>> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
>> index 541ec962f189..df29a65ad365 100644
>> --- a/xen/arch/arm/vpl011.c
>> +++ b/xen/arch/arm/vpl011.c
>> @@ -696,8 +696,8 @@ int domain_vpl011_init(struct domain *d, struct
>> vpl011_init_info *info)
>> vpl011->backend.xen = xzalloc(struct vpl011_xen_backend);
>> if ( vpl011->backend.xen == NULL )
>> {
>> - rc = -EINVAL;
>> - goto out1;
>> + rc = -ENOMEM;
>> + goto out;
>> }
>> }
>>
>> @@ -720,12 +720,15 @@ int domain_vpl011_init(struct domain *d, struct
>> vpl011_init_info *info)
>> out2:
>> vgic_free_virq(d, vpl011->virq);
>>
>> + if ( vpl011->backend_in_domain )
>> + free_xen_event_channel(d, vpl011->evtchn);
>> + else
>> + xfree(vpl011->backend.xen);
>
> There is another bug here (unrelated to your change). You want to use
> XFREE() to avoid an extra free in domain_pl011_deinit(). Can you look at it?
Strictly speaking this is not a bug. Memory allocation can only happen if
backend is in Xen.
This means, that if vpl011 init fails, we will call free only once
(domain_vpl011_deinit
will not be called on this path i.e. we will invoke panic after construct_domU).
Of course, we could switch to XFREE just for sanity.
>
>> +
>> out1:
>> if ( vpl011->backend_in_domain )
>> destroy_ring_for_helper(&vpl011->backend.dom.ring_buf,
>> vpl011->backend.dom.ring_page);
>> - else
>> - xfree(vpl011->backend.xen);
>>
>> out:
>> return rc;
>
Solution to reuse domain_pl011_deinit would be as follows:
vgic_free_virq(d, vpl011->virq);
out1:
- if ( vpl011->backend_in_domain )
- destroy_ring_for_helper(&vpl011->backend.dom.ring_buf,
- vpl011->backend.dom.ring_page);
- else
- xfree(vpl011->backend.xen);
+ domain_vpl011_deinit(d);
out:
return rc;
@@ -737,12 +733,15 @@ void domain_vpl011_deinit(struct domain *d)
if ( vpl011->backend_in_domain )
{
- if ( !vpl011->backend.dom.ring_buf )
- return;
+ if ( vpl011->backend.dom.ring_buf )
+ destroy_ring_for_helper(&vpl011->backend.dom.ring_buf,
+ vpl011->backend.dom.ring_page);
- free_xen_event_channel(d, vpl011->evtchn);
- destroy_ring_for_helper(&vpl011->backend.dom.ring_buf,
- vpl011->backend.dom.ring_page);
+ if ( vpl011->evtchn )
+ {
+ free_xen_event_channel(d, vpl011->evtchn);
+ vpl011->evtchn = 0;
+ }
}
else
xfree(vpl011->backend.xen);
However there is one problem with guarding free_xen_event_channel to be called
only once.
Even without allocating event channel, vpl011->evtchn is 0 by default. So doing:
if ( is_port_valid(vpl011->evtchn) )
free_xen_event_channel(d, vpl011->evtchn);
would not help us as evtchn 0 is always there. So in my proposal I'm assuming
(I think correctly)
that vpl011->evtchn cannot be 0 after successful evtchn allocation because 0 is
"reserved".
But I might be wrong in which case I'm clueless how to do the proper check.
~Michal
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |