diff mbox

[v4,03/10] IOMMU/MMU: enhance the call trees of IOMMU unmapping and mapping

Message ID 1462524880-67205-4-git-send-email-quan.xu@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Quan Xu May 6, 2016, 8:54 a.m. UTC
When IOMMU mapping is failed, we issue a best effort rollback, stopping
IOMMU mapping, unmapping the previous IOMMU maps and then reporting the
error up to the call trees. When rollback is not feasible (in early
initialization phase or trade-off of complexity) for the hardware domain,
we do things on a best effort basis, only throwing out an error message.

IOMMU unmapping should perhaps continue despite an error, in an attempt
to do best effort cleanup.

Signed-off-by: Quan Xu <quan.xu@intel.com>

CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Jun Nakajima <jun.nakajima@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
CC: George Dunlap <george.dunlap@eu.citrix.com>
---
 xen/arch/x86/mm.c               | 13 ++++++++-----
 xen/arch/x86/mm/p2m-ept.c       | 40 ++++++++++++++++++++++++++++++++--------
 xen/arch/x86/mm/p2m-pt.c        | 26 ++++++++++++++++++++++----
 xen/arch/x86/mm/p2m.c           | 11 +++++++++--
 xen/drivers/passthrough/iommu.c | 14 +++++++++++++-
 5 files changed, 84 insertions(+), 20 deletions(-)

Comments

Jan Beulich May 10, 2016, 8:44 a.m. UTC | #1
>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
> When IOMMU mapping is failed, we issue a best effort rollback, stopping
> IOMMU mapping, unmapping the previous IOMMU maps and then reporting the
> error up to the call trees. When rollback is not feasible (in early
> initialization phase or trade-off of complexity) for the hardware domain,
> we do things on a best effort basis, only throwing out an error message.
> 
> IOMMU unmapping should perhaps continue despite an error, in an attempt
> to do best effort cleanup.
> 
> Signed-off-by: Quan Xu <quan.xu@intel.com>
> 
> CC: Keir Fraser <keir@xen.org>
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Andrew Cooper <andrew.cooper3@citrix.com>
> CC: Jun Nakajima <jun.nakajima@intel.com>
> CC: Kevin Tian <kevin.tian@intel.com>
> CC: George Dunlap <george.dunlap@eu.citrix.com>
> ---

Somewhere here I continue to miss a summary on what has changed
compared to the previous version. For review especially of larger
patches (where preferably one wouldn't want to re-review the entire
thing) this is more than just a nice-to-have.

> @@ -812,17 +813,22 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
>      rc = atomic_write_ept_entry(ept_entry, new_entry, target);
>      if ( unlikely(rc) )
>          old_entry.epte = 0;
> -    else if ( p2mt != p2m_invalid &&
> -              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
> -        /* Track the highest gfn for which we have ever had a valid mapping */
> -        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
> +    else
> +    {
> +        entry_written = 1;
> +
> +        if ( p2mt != p2m_invalid &&
> +             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
> +            /* Track the highest gfn for which we have ever had a valid mapping */
> +            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
> +    }
>  
>  out:
>      if ( needs_sync )
>          ept_sync_domain(p2m);
>  
>      /* For host p2m, may need to change VT-d page table.*/
> -    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
> +    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>           need_modify_vtd_table )
>      {

I'd prefer this conditional to remain untouched, but I'll leave the
decision to the maintainers of the file.

> @@ -831,10 +837,28 @@ out:
>          {
>              if ( iommu_flags )
>                  for ( i = 0; i < (1 << order); i++ )
> -                    iommu_map_page(d, gfn + i, mfn_x(mfn) + i, iommu_flags);
> +                {
> +                    ret = iommu_map_page(d, gfn + i, mfn_x(mfn) + i, iommu_flags);
> +
> +                    if ( unlikely(ret) )
> +                    {
> +                        while ( i-- )
> +                            iommu_unmap_page(p2m->domain, gfn + i);

Loops like this are, btw., good examples of the log spam issue I've
been pointing out on an earlier patch of this series.

> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
>      mfn_t mfn_return;
>      p2m_type_t t;
>      p2m_access_t a;
> +    int rc = 0, ret;
>  
>      if ( !paging_mode_translate(p2m->domain) )
>      {
>          if ( need_iommu(p2m->domain) )
>              for ( i = 0; i < (1 << page_order); i++ )
> -                iommu_unmap_page(p2m->domain, mfn + i);
> -        return 0;
> +            {
> +               ret = iommu_unmap_page(p2m->domain, mfn + i);
> +
> +               if ( !rc )
> +                   rc = ret;
> +            }
> +
> +        return rc;
>      }

In code like this, btw., restricting the scope of "ret" to the innermost
block would help future readers see immediately that the value of
"ret" is of no further interest outside of that block.

Having reached the end of the patch, I'm missing the __must_check
additions that you said you would do in this new iteration. Is there
any reason for their absence? Did I overlook something?

Jan
George Dunlap May 10, 2016, 2:45 p.m. UTC | #2
On Tue, May 10, 2016 at 9:44 AM, Jan Beulich <JBeulich@suse.com> wrote:
>>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
>> When IOMMU mapping is failed, we issue a best effort rollback, stopping
>> IOMMU mapping, unmapping the previous IOMMU maps and then reporting the
>> error up to the call trees. When rollback is not feasible (in early
>> initialization phase or trade-off of complexity) for the hardware domain,
>> we do things on a best effort basis, only throwing out an error message.
>>
>> IOMMU unmapping should perhaps continue despite an error, in an attempt
>> to do best effort cleanup.
>>
>> Signed-off-by: Quan Xu <quan.xu@intel.com>
>>
>> CC: Keir Fraser <keir@xen.org>
>> CC: Jan Beulich <jbeulich@suse.com>
>> CC: Andrew Cooper <andrew.cooper3@citrix.com>
>> CC: Jun Nakajima <jun.nakajima@intel.com>
>> CC: Kevin Tian <kevin.tian@intel.com>
>> CC: George Dunlap <george.dunlap@eu.citrix.com>
>> ---
>
> Somewhere here I continue to miss a summary on what has changed
> compared to the previous version. For review especially of larger
> patches (where preferably one wouldn't want to re-review the entire
> thing) this is more than just a nice-to-have.
>
>> @@ -812,17 +813,22 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
>>      rc = atomic_write_ept_entry(ept_entry, new_entry, target);
>>      if ( unlikely(rc) )
>>          old_entry.epte = 0;
>> -    else if ( p2mt != p2m_invalid &&
>> -              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>> -        /* Track the highest gfn for which we have ever had a valid mapping */
>> -        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>> +    else
>> +    {
>> +        entry_written = 1;
>> +
>> +        if ( p2mt != p2m_invalid &&
>> +             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>> +            /* Track the highest gfn for which we have ever had a valid mapping */
>> +            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>> +    }
>>
>>  out:
>>      if ( needs_sync )
>>          ept_sync_domain(p2m);
>>
>>      /* For host p2m, may need to change VT-d page table.*/
>> -    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>> +    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>>           need_modify_vtd_table )
>>      {
>
> I'd prefer this conditional to remain untouched, but I'll leave the
> decision to the maintainers of the file.

Any particular reason you think it would be better untouched?

I asked for it to be changed to "entry_written", because it seemed to
me that's what was actually wanted (i.e., you're checking whether rc
== 0 to determine whether the entry was written or not).  At the
moment the checks will be identical, but if someone changed something
later, rc might be non-zero even though the entry had been written, in
which case (I think) you'd want the iommu update to happen.

It's not that big a deal to me, but I do prefer it this way (unless
I've misunderstood something).

>> --- a/xen/arch/x86/mm/p2m.c
>> +++ b/xen/arch/x86/mm/p2m.c
>> @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
>>      mfn_t mfn_return;
>>      p2m_type_t t;
>>      p2m_access_t a;
>> +    int rc = 0, ret;
>>
>>      if ( !paging_mode_translate(p2m->domain) )
>>      {
>>          if ( need_iommu(p2m->domain) )
>>              for ( i = 0; i < (1 << page_order); i++ )
>> -                iommu_unmap_page(p2m->domain, mfn + i);
>> -        return 0;
>> +            {
>> +               ret = iommu_unmap_page(p2m->domain, mfn + i);
>> +
>> +               if ( !rc )
>> +                   rc = ret;
>> +            }
>> +
>> +        return rc;
>>      }
>
> In code like this, btw., restricting the scope of "ret" to the innermost
> block would help future readers see immediately that the value of
> "ret" is of no further interest outside of that block.

I wouldn't ask for re-send just for this, but...

> Having reached the end of the patch, I'm missing the __must_check
> additions that you said you would do in this new iteration. Is there
> any reason for their absence? Did I overlook something?

If it's going to be re-sent anyway, moving the ret declaration inside
the loop might as well be done.

Other than that, it looks good to me, thanks.

 -George
George Dunlap May 10, 2016, 2:59 p.m. UTC | #3
On Tue, May 10, 2016 at 3:45 PM, George Dunlap
<George.Dunlap@eu.citrix.com> wrote:
> On Tue, May 10, 2016 at 9:44 AM, Jan Beulich <JBeulich@suse.com> wrote:
>>>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
>>> When IOMMU mapping is failed, we issue a best effort rollback, stopping
>>> IOMMU mapping, unmapping the previous IOMMU maps and then reporting the
>>> error up to the call trees. When rollback is not feasible (in early
>>> initialization phase or trade-off of complexity) for the hardware domain,
>>> we do things on a best effort basis, only throwing out an error message.
>>>
>>> IOMMU unmapping should perhaps continue despite an error, in an attempt
>>> to do best effort cleanup.
>>>
>>> Signed-off-by: Quan Xu <quan.xu@intel.com>
>>>
>>> CC: Keir Fraser <keir@xen.org>
>>> CC: Jan Beulich <jbeulich@suse.com>
>>> CC: Andrew Cooper <andrew.cooper3@citrix.com>
>>> CC: Jun Nakajima <jun.nakajima@intel.com>
>>> CC: Kevin Tian <kevin.tian@intel.com>
>>> CC: George Dunlap <george.dunlap@eu.citrix.com>
>>> ---
>>
>> Somewhere here I continue to miss a summary on what has changed
>> compared to the previous version. For review especially of larger
>> patches (where preferably one wouldn't want to re-review the entire
>> thing) this is more than just a nice-to-have.
>>
>>> @@ -812,17 +813,22 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
>>>      rc = atomic_write_ept_entry(ept_entry, new_entry, target);
>>>      if ( unlikely(rc) )
>>>          old_entry.epte = 0;
>>> -    else if ( p2mt != p2m_invalid &&
>>> -              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>>> -        /* Track the highest gfn for which we have ever had a valid mapping */
>>> -        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>>> +    else
>>> +    {
>>> +        entry_written = 1;
>>> +
>>> +        if ( p2mt != p2m_invalid &&
>>> +             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>>> +            /* Track the highest gfn for which we have ever had a valid mapping */
>>> +            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>>> +    }
>>>
>>>  out:
>>>      if ( needs_sync )
>>>          ept_sync_domain(p2m);
>>>
>>>      /* For host p2m, may need to change VT-d page table.*/
>>> -    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>>> +    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>>>           need_modify_vtd_table )
>>>      {
>>
>> I'd prefer this conditional to remain untouched, but I'll leave the
>> decision to the maintainers of the file.
>
> Any particular reason you think it would be better untouched?
>
> I asked for it to be changed to "entry_written", because it seemed to
> me that's what was actually wanted (i.e., you're checking whether rc
> == 0 to determine whether the entry was written or not).  At the
> moment the checks will be identical, but if someone changed something
> later, rc might be non-zero even though the entry had been written, in
> which case (I think) you'd want the iommu update to happen.
>
> It's not that big a deal to me, but I do prefer it this way (unless
> I've misunderstood something).

See the discussion on patch 8 regarding why I now think Jan is probably right.

 -George
Jan Beulich May 10, 2016, 3:02 p.m. UTC | #4
>>> On 10.05.16 at 16:45, <George.Dunlap@eu.citrix.com> wrote:
> On Tue, May 10, 2016 at 9:44 AM, Jan Beulich <JBeulich@suse.com> wrote:
>>>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
>>> @@ -812,17 +813,22 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
>>>      rc = atomic_write_ept_entry(ept_entry, new_entry, target);
>>>      if ( unlikely(rc) )
>>>          old_entry.epte = 0;
>>> -    else if ( p2mt != p2m_invalid &&
>>> -              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>>> -        /* Track the highest gfn for which we have ever had a valid mapping */
>>> -        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>>> +    else
>>> +    {
>>> +        entry_written = 1;
>>> +
>>> +        if ( p2mt != p2m_invalid &&
>>> +             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
>>> +            /* Track the highest gfn for which we have ever had a valid mapping */
>>> +            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
>>> +    }
>>>
>>>  out:
>>>      if ( needs_sync )
>>>          ept_sync_domain(p2m);
>>>
>>>      /* For host p2m, may need to change VT-d page table.*/
>>> -    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>>> +    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&
>>>           need_modify_vtd_table )
>>>      {
>>
>> I'd prefer this conditional to remain untouched, but I'll leave the
>> decision to the maintainers of the file.
> 
> Any particular reason you think it would be better untouched?

IMO it's misleading here, and appropriate only in the other place
(where the altp2m-s get updated).

> I asked for it to be changed to "entry_written", because it seemed to
> me that's what was actually wanted (i.e., you're checking whether rc
> == 0 to determine whether the entry was written or not).  At the
> moment the checks will be identical, but if someone changed something
> later, rc might be non-zero even though the entry had been written, in
> which case (I think) you'd want the iommu update to happen.
> 
> It's not that big a deal to me, but I do prefer it this way (unless
> I've misunderstood something).
> 
>>> --- a/xen/arch/x86/mm/p2m.c
>>> +++ b/xen/arch/x86/mm/p2m.c
>>> @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
>>>      mfn_t mfn_return;
>>>      p2m_type_t t;
>>>      p2m_access_t a;
>>> +    int rc = 0, ret;
>>>
>>>      if ( !paging_mode_translate(p2m->domain) )
>>>      {
>>>          if ( need_iommu(p2m->domain) )
>>>              for ( i = 0; i < (1 << page_order); i++ )
>>> -                iommu_unmap_page(p2m->domain, mfn + i);
>>> -        return 0;
>>> +            {
>>> +               ret = iommu_unmap_page(p2m->domain, mfn + i);
>>> +
>>> +               if ( !rc )
>>> +                   rc = ret;
>>> +            }
>>> +
>>> +        return rc;
>>>      }
>>
>> In code like this, btw., restricting the scope of "ret" to the innermost
>> block would help future readers see immediately that the value of
>> "ret" is of no further interest outside of that block.
> 
> I wouldn't ask for re-send just for this, but...

I agree, and I meant to express this with the "btw".

Jan

>> Having reached the end of the patch, I'm missing the __must_check
>> additions that you said you would do in this new iteration. Is there
>> any reason for their absence? Did I overlook something?
> 
> If it's going to be re-sent anyway, moving the ret declaration inside
> the loop might as well be done.
> 
> Other than that, it looks good to me, thanks.
> 
>  -George
Quan Xu May 11, 2016, 2:26 a.m. UTC | #5
On May 10, 2016 11:00 PM, George Dunlap <George.Dunlap@eu.citrix.com> wrote:
> On Tue, May 10, 2016 at 3:45 PM, George Dunlap

> <George.Dunlap@eu.citrix.com> wrote:

> > On Tue, May 10, 2016 at 9:44 AM, Jan Beulich <JBeulich@suse.com> wrote:

> >>>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:

> >>> When IOMMU mapping is failed, we issue a best effort rollback,

> >>> stopping IOMMU mapping, unmapping the previous IOMMU maps and

> then

> >>> reporting the error up to the call trees. When rollback is not

> >>> feasible (in early initialization phase or trade-off of complexity)

> >>> for the hardware domain, we do things on a best effort basis, only

> throwing out an error message.

> >>>

> >>> IOMMU unmapping should perhaps continue despite an error, in an

> >>> attempt to do best effort cleanup.

> >>>

> >>> Signed-off-by: Quan Xu <quan.xu@intel.com>

> >>>

> >>> CC: Keir Fraser <keir@xen.org>

> >>> CC: Jan Beulich <jbeulich@suse.com>

> >>> CC: Andrew Cooper <andrew.cooper3@citrix.com>

> >>> CC: Jun Nakajima <jun.nakajima@intel.com>

> >>> CC: Kevin Tian <kevin.tian@intel.com>

> >>> CC: George Dunlap <george.dunlap@eu.citrix.com>

> >>> ---

> >>

> >> Somewhere here I continue to miss a summary on what has changed

> >> compared to the previous version. For review especially of larger

> >> patches (where preferably one wouldn't want to re-review the entire

> >> thing) this is more than just a nice-to-have.

> >>

> >>> @@ -812,17 +813,22 @@ ept_set_entry(struct p2m_domain *p2m,

> unsigned long gfn, mfn_t mfn,

> >>>      rc = atomic_write_ept_entry(ept_entry, new_entry, target);

> >>>      if ( unlikely(rc) )

> >>>          old_entry.epte = 0;

> >>> -    else if ( p2mt != p2m_invalid &&

> >>> -              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )

> >>> -        /* Track the highest gfn for which we have ever had a valid mapping

> */

> >>> -        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;

> >>> +    else

> >>> +    {

> >>> +        entry_written = 1;

> >>> +

> >>> +        if ( p2mt != p2m_invalid &&

> >>> +             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )

> >>> +            /* Track the highest gfn for which we have ever had a valid

> mapping */

> >>> +            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;

> >>> +    }

> >>>

> >>>  out:

> >>>      if ( needs_sync )

> >>>          ept_sync_domain(p2m);

> >>>

> >>>      /* For host p2m, may need to change VT-d page table.*/

> >>> -    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&

> >>> +    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&

> >>>           need_modify_vtd_table )

> >>>      {

> >>

> >> I'd prefer this conditional to remain untouched, but I'll leave the

> >> decision to the maintainers of the file.

> >

> > Any particular reason you think it would be better untouched?

> >

> > I asked for it to be changed to "entry_written", because it seemed to

> > me that's what was actually wanted (i.e., you're checking whether rc

> > == 0 to determine whether the entry was written or not).  At the

> > moment the checks will be identical, but if someone changed something

> > later, rc might be non-zero even though the entry had been written, in

> > which case (I think) you'd want the iommu update to happen.

> >

> > It's not that big a deal to me, but I do prefer it this way (unless

> > I've misunderstood something).

> 

> See the discussion on patch 8 regarding why I now think Jan is probably right.

> 


Agreed. Thanks for your careful checking.

Check it again --
1. then I am no need to check 'rc' as below:

      if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
           need_modify_vtd_table )
     {
+                        if ( !rc ) 
+                            rc = ret;
...

+                    if ( !rc && unlikely(ret) )
+                        rc = ret;
     }


2.  leave the below as is:

-    if ( rc == 0 && p2m_is_hostp2m(p2m) )
+    if ( entry_written && p2m_is_hostp2m(p2m) )

Quan
Quan Xu May 11, 2016, 2:29 a.m. UTC | #6
On May 10, 2016 10:45 PM, George Dunlap <George.Dunlap@eu.citrix.com> wrote:
> On Tue, May 10, 2016 at 9:44 AM, Jan Beulich <JBeulich@suse.com> wrote:

> >>>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:

> >> When IOMMU mapping is failed, we issue a best effort rollback,

> >> stopping IOMMU mapping, unmapping the previous IOMMU maps and

> then

> >> reporting the error up to the call trees. When rollback is not

> >> feasible (in early initialization phase or trade-off of complexity)

> >> for the hardware domain, we do things on a best effort basis, only

> throwing out an error message.

> >>

> >> IOMMU unmapping should perhaps continue despite an error, in an

> >> attempt to do best effort cleanup.

> >>

> >> --- a/xen/arch/x86/mm/p2m.c

> >> +++ b/xen/arch/x86/mm/p2m.c

> >> @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m,

> unsigned long gfn, unsigned long mfn,

> >>      mfn_t mfn_return;

> >>      p2m_type_t t;

> >>      p2m_access_t a;

> >> +    int rc = 0, ret;

> >>

> >>      if ( !paging_mode_translate(p2m->domain) )

> >>      {

> >>          if ( need_iommu(p2m->domain) )

> >>              for ( i = 0; i < (1 << page_order); i++ )

> >> -                iommu_unmap_page(p2m->domain, mfn + i);

> >> -        return 0;

> >> +            {

> >> +               ret = iommu_unmap_page(p2m->domain, mfn + i);

> >> +

> >> +               if ( !rc )

> >> +                   rc = ret;

> >> +            }

> >> +

> >> +        return rc;

> >>      }

> >

> > In code like this, btw., restricting the scope of "ret" to the

> > innermost block would help future readers see immediately that the

> > value of "ret" is of no further interest outside of that block.

> 

> I wouldn't ask for re-send just for this, but...

> 

> > Having reached the end of the patch, I'm missing the __must_check

> > additions that you said you would do in this new iteration. Is there

> > any reason for their absence? Did I overlook something?

> 

> If it's going to be re-sent anyway, moving the ret declaration inside the loop

> might as well be done.

> 

> Other than that, it looks good to me, thanks.

> 



I'll fix and re-send it in next v5.

Quan
Quan Xu May 11, 2016, 3:39 a.m. UTC | #7
On May 10, 2016 4:44 PM, Jan Beulich <JBeulich@suse.com> wrote:
> >>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
> > --- a/xen/arch/x86/mm/p2m.c
> > +++ b/xen/arch/x86/mm/p2m.c
> > @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m,
> unsigned long gfn, unsigned long mfn,
> >      mfn_t mfn_return;
> >      p2m_type_t t;
> >      p2m_access_t a;
> > +    int rc = 0, ret;
> >
> >      if ( !paging_mode_translate(p2m->domain) )
> >      {
> >          if ( need_iommu(p2m->domain) )
> >              for ( i = 0; i < (1 << page_order); i++ )
> > -                iommu_unmap_page(p2m->domain, mfn + i);
> > -        return 0;
> > +            {
> > +               ret = iommu_unmap_page(p2m->domain, mfn + i);
> > +
> > +               if ( !rc )
> > +                   rc = ret;
> > +            }
> > +
> > +        return rc;
> >      }
> 
> In code like this, btw., restricting the scope of "ret" to the innermost block
> would help future readers see immediately that the value of "ret" is of no
> further interest outside of that block.
> 
> Having reached the end of the patch, I'm missing the __must_check additions
> that you said you would do in this new iteration. Is there any reason for their
> absence? Did I overlook something?
> 

Sorry, I did overlook something.
Checked the v2/v3 replies again, I still can't find it.
I only add the __must_check annotation for these functions you point out.
Do I need to add the __must_check annotation for these  functions (but not void function) in this patch?

Quan
Jan Beulich May 11, 2016, 7:02 a.m. UTC | #8
>>> On 11.05.16 at 05:39, <quan.xu@intel.com> wrote:
> On May 10, 2016 4:44 PM, Jan Beulich <JBeulich@suse.com> wrote:
>> >>> On 06.05.16 at 10:54, <quan.xu@intel.com> wrote:
>> > --- a/xen/arch/x86/mm/p2m.c
>> > +++ b/xen/arch/x86/mm/p2m.c
>> > @@ -638,13 +638,20 @@ p2m_remove_page(struct p2m_domain *p2m,
>> unsigned long gfn, unsigned long mfn,
>> >      mfn_t mfn_return;
>> >      p2m_type_t t;
>> >      p2m_access_t a;
>> > +    int rc = 0, ret;
>> >
>> >      if ( !paging_mode_translate(p2m->domain) )
>> >      {
>> >          if ( need_iommu(p2m->domain) )
>> >              for ( i = 0; i < (1 << page_order); i++ )
>> > -                iommu_unmap_page(p2m->domain, mfn + i);
>> > -        return 0;
>> > +            {
>> > +               ret = iommu_unmap_page(p2m->domain, mfn + i);
>> > +
>> > +               if ( !rc )
>> > +                   rc = ret;
>> > +            }
>> > +
>> > +        return rc;
>> >      }
>> 
>> In code like this, btw., restricting the scope of "ret" to the innermost 
> block
>> would help future readers see immediately that the value of "ret" is of no
>> further interest outside of that block.
>> 
>> Having reached the end of the patch, I'm missing the __must_check additions
>> that you said you would do in this new iteration. Is there any reason for 
> their
>> absence? Did I overlook something?
>> 
> 
> Sorry, I did overlook something.
> Checked the v2/v3 replies again, I still can't find it.
> I only add the __must_check annotation for these functions you point out.

Okay, that's the problem then: When we discussed this originally
(in abstract terms) I had clearly said that all involved functions
should become __must_check ones to make sure all cases get
caught where so far error returns got ignored. And on that basis
(as well as on the common grounds that I try to avoid repeating
the same comment over and over when reviewing a patch or a
series of patches) you should have determined yourself the full
set of functions needing the annotation. The rule of thumb is: If
a function calls a __must_check one and doesn't itself consume
the return value, it should also obtain __must_check.

> Do I need to add the __must_check annotation for these  functions (but not 
> void function) in this patch?

IOW - yes. And you'll need to apply the same consideration to
most (all?) other patches in this series.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 2bb920b..14b54a9 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2467,7 +2467,7 @@  static int __get_page_type(struct page_info *page, unsigned long type,
                            int preemptible)
 {
     unsigned long nx, x, y = page->u.inuse.type_info;
-    int rc = 0;
+    int rc = 0, ret = 0;
 
     ASSERT(!(type & ~(PGT_type_mask | PGT_pae_xen_l2)));
 
@@ -2578,11 +2578,11 @@  static int __get_page_type(struct page_info *page, unsigned long type,
         if ( d && is_pv_domain(d) && unlikely(need_iommu(d)) )
         {
             if ( (x & PGT_type_mask) == PGT_writable_page )
-                iommu_unmap_page(d, mfn_to_gmfn(d, page_to_mfn(page)));
+                ret = iommu_unmap_page(d, mfn_to_gmfn(d, page_to_mfn(page)));
             else if ( type == PGT_writable_page )
-                iommu_map_page(d, mfn_to_gmfn(d, page_to_mfn(page)),
-                               page_to_mfn(page),
-                               IOMMUF_readable|IOMMUF_writable);
+                ret = iommu_map_page(d, mfn_to_gmfn(d, page_to_mfn(page)),
+                                     page_to_mfn(page),
+                                     IOMMUF_readable|IOMMUF_writable);
         }
     }
 
@@ -2599,6 +2599,9 @@  static int __get_page_type(struct page_info *page, unsigned long type,
     if ( (x & PGT_partial) && !(nx & PGT_partial) )
         put_page(page);
 
+    if ( !rc )
+        rc = ret;
+
     return rc;
 }
 
diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index 1ed5b47..814cb72 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -667,6 +667,7 @@  ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
     unsigned long gfn_remainder = gfn;
     unsigned int i, target = order / EPT_TABLE_ORDER;
     int ret, rc = 0;
+    bool_t entry_written = 0;
     bool_t direct_mmio = (p2mt == p2m_mmio_direct);
     uint8_t ipat = 0;
     bool_t need_modify_vtd_table = 1;
@@ -812,17 +813,22 @@  ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
     rc = atomic_write_ept_entry(ept_entry, new_entry, target);
     if ( unlikely(rc) )
         old_entry.epte = 0;
-    else if ( p2mt != p2m_invalid &&
-              (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
-        /* Track the highest gfn for which we have ever had a valid mapping */
-        p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
+    else
+    {
+        entry_written = 1;
+
+        if ( p2mt != p2m_invalid &&
+             (gfn + (1UL << order) - 1 > p2m->max_mapped_pfn) )
+            /* Track the highest gfn for which we have ever had a valid mapping */
+            p2m->max_mapped_pfn = gfn + (1UL << order) - 1;
+    }
 
 out:
     if ( needs_sync )
         ept_sync_domain(p2m);
 
     /* For host p2m, may need to change VT-d page table.*/
-    if ( rc == 0 && p2m_is_hostp2m(p2m) && need_iommu(d) &&
+    if ( entry_written && p2m_is_hostp2m(p2m) && need_iommu(d) &&
          need_modify_vtd_table )
     {
         if ( iommu_hap_pt_share )
@@ -831,10 +837,28 @@  out:
         {
             if ( iommu_flags )
                 for ( i = 0; i < (1 << order); i++ )
-                    iommu_map_page(d, gfn + i, mfn_x(mfn) + i, iommu_flags);
+                {
+                    ret = iommu_map_page(d, gfn + i, mfn_x(mfn) + i, iommu_flags);
+
+                    if ( unlikely(ret) )
+                    {
+                        while ( i-- )
+                            iommu_unmap_page(p2m->domain, gfn + i);
+
+                        if ( !rc )
+                            rc = ret;
+
+                        break;
+                    }
+                }
             else
                 for ( i = 0; i < (1 << order); i++ )
-                    iommu_unmap_page(d, gfn + i);
+                {
+                    ret = iommu_unmap_page(d, gfn + i);
+
+                    if ( !rc )
+                        rc = ret;
+                }
         }
     }
 
@@ -847,7 +871,7 @@  out:
     if ( is_epte_present(&old_entry) )
         ept_free_entry(p2m, &old_entry, target);
 
-    if ( rc == 0 && p2m_is_hostp2m(p2m) )
+    if ( entry_written && p2m_is_hostp2m(p2m) )
         p2m_altp2m_propagate_change(d, _gfn(gfn), mfn, order, p2mt, p2ma);
 
     return rc;
diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c
index 3d80612..5426f92 100644
--- a/xen/arch/x86/mm/p2m-pt.c
+++ b/xen/arch/x86/mm/p2m-pt.c
@@ -498,7 +498,7 @@  p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
     l1_pgentry_t intermediate_entry = l1e_empty();
     l2_pgentry_t l2e_content;
     l3_pgentry_t l3e_content;
-    int rc;
+    int rc, ret;
     unsigned int iommu_pte_flags = p2m_get_iommu_flags(p2mt);
     /*
      * old_mfn and iommu_old_flags control possible flush/update needs on the
@@ -680,11 +680,29 @@  p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
         }
         else if ( iommu_pte_flags )
             for ( i = 0; i < (1UL << page_order); i++ )
-                iommu_map_page(p2m->domain, gfn + i, mfn_x(mfn) + i,
-                               iommu_pte_flags);
+            {
+                ret = iommu_map_page(p2m->domain, gfn + i, mfn_x(mfn) + i,
+                                    iommu_pte_flags);
+
+                if ( unlikely(ret) )
+                {
+                    while ( i-- )
+                        iommu_unmap_page(p2m->domain, gfn + i);
+
+                    if ( !rc )
+                        rc = ret;
+
+                    break;
+                }
+            }
         else
             for ( i = 0; i < (1UL << page_order); i++ )
-                iommu_unmap_page(p2m->domain, gfn + i);
+            {
+                ret = iommu_unmap_page(p2m->domain, gfn + i);
+
+                if ( !rc )
+                    rc = ret;
+            }
     }
 
     /*
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 94eabf6..cb77ef2 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -638,13 +638,20 @@  p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
     mfn_t mfn_return;
     p2m_type_t t;
     p2m_access_t a;
+    int rc = 0, ret;
 
     if ( !paging_mode_translate(p2m->domain) )
     {
         if ( need_iommu(p2m->domain) )
             for ( i = 0; i < (1 << page_order); i++ )
-                iommu_unmap_page(p2m->domain, mfn + i);
-        return 0;
+            {
+               ret = iommu_unmap_page(p2m->domain, mfn + i);
+
+               if ( !rc )
+                   rc = ret;
+            }
+
+        return rc;
     }
 
     ASSERT(gfn_locked_by_me(p2m, gfn));
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 09560c0..cca4cf3 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -171,6 +171,8 @@  void __hwdom_init iommu_hwdom_init(struct domain *d)
     {
         struct page_info *page;
         unsigned int i = 0;
+        int ret, rc = 0;
+
         page_list_for_each ( page, &d->page_list )
         {
             unsigned long mfn = page_to_mfn(page);
@@ -181,10 +183,20 @@  void __hwdom_init iommu_hwdom_init(struct domain *d)
                  ((page->u.inuse.type_info & PGT_type_mask)
                   == PGT_writable_page) )
                 mapping |= IOMMUF_writable;
-            hd->platform_ops->map_page(d, gfn, mfn, mapping);
+
+            ret = hd->platform_ops->map_page(d, gfn, mfn, mapping);
+
+            if ( unlikely(ret) )
+                rc = ret;
+
             if ( !(i++ & 0xfffff) )
                 process_pending_softirqs();
         }
+
+        if ( rc )
+            printk(XENLOG_WARNING
+                   "iommu_hwdom_init: IOMMU mapping failed for dom%d.",
+                   d->domain_id);
     }
 
     return hd->platform_ops->hwdom_init(d);