diff mbox

x86/mmuext: Unify okay/rc error handling in do_mmuext_op()

Message ID 1450718160-744-1-git-send-email-andrew.cooper3@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Cooper Dec. 21, 2015, 5:16 p.m. UTC
c/s 506db90 "x86/HVM: merge HVM and PVH hypercall tables" introduced a path
whereby 'okay' was used uninitialised, with broke compilation on CentOS 7.

Splitting the error handling like this is fragile and unnecessary.  Drop the
okay variable entirely and just use rc directly, substituting rc = -EINVAL/0
for okay = 0/1.

In addition, two error messages are updated to print rc, and some stray
whitespace is dropped.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
 xen/arch/x86/mm.c | 65 +++++++++++++++++++++++++------------------------------
 1 file changed, 30 insertions(+), 35 deletions(-)

Comments

Boris Ostrovsky Dec. 21, 2015, 5:50 p.m. UTC | #1
On 12/21/2015 12:16 PM, Andrew Cooper wrote:
> c/s 506db90 "x86/HVM: merge HVM and PVH hypercall tables" introduced a path
> whereby 'okay' was used uninitialised, with broke compilation on CentOS 7.
>
> Splitting the error handling like this is fragile and unnecessary.  Drop the
> okay variable entirely and just use rc directly, substituting rc = -EINVAL/0
> for okay = 0/1.
>
> In addition, two error messages are updated to print rc, and some stray
> whitespace is dropped.
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <JBeulich@suse.com>
> CC: Boris Ostrovsky <boris.ostrovsky@oracle.com>

Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>

with a couple of style nits:

> @@ -3258,14 +3254,14 @@ long do_mmuext_op(
>   
>               break;
>           }
> -
> +
>           case MMUEXT_TLB_FLUSH_LOCAL:
>               if ( likely(d == pg_owner) )
>                   flush_tlb_local();
>               else
>                   rc = -EPERM;
>               break;
> -
> +
>           case MMUEXT_INVLPG_LOCAL:
>               if ( unlikely(d != pg_owner) )
>                   rc = -EPERM;

These look like stray changes.
Jan Beulich Dec. 22, 2015, 8:57 a.m. UTC | #2
>>> On 21.12.15 at 18:16, <andrew.cooper3@citrix.com> wrote:
> c/s 506db90 "x86/HVM: merge HVM and PVH hypercall tables" introduced a path
> whereby 'okay' was used uninitialised, with broke compilation on CentOS 7.

It appeared to be used uninitialized, but wasn't in fact (i.e. the
outcome - the value rc gets set to - didn't depend on the value
due to

        if ( unlikely(!okay) && !rc )
            rc = -EINVAL;

being equivalent to

        if ( !rc && unlikely(!okay) )
            rc = -EINVAL;

(no side effects for the expressions on either side of the &&).
I'll re-word accordingly upon committing, to not give the false
impression of there having been other than a cosmetic problem.

> Splitting the error handling like this is fragile and unnecessary.  Drop the
> okay variable entirely and just use rc directly, substituting rc = -EINVAL/0
> for okay = 0/1.
> 
> In addition, two error messages are updated to print rc, and some stray
> whitespace is dropped.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Reviewed-by: Jan Beulich <jbeulich@suse.com>
Andrew Cooper Dec. 22, 2015, 9:09 a.m. UTC | #3
On 22/12/2015 08:57, Jan Beulich wrote:
>>>> On 21.12.15 at 18:16, <andrew.cooper3@citrix.com> wrote:
>> c/s 506db90 "x86/HVM: merge HVM and PVH hypercall tables" introduced a path
>> whereby 'okay' was used uninitialised, with broke compilation on CentOS 7.
> It appeared to be used uninitialized, but wasn't in fact (i.e. the
> outcome - the value rc gets set to - didn't depend on the value
> due to
>
>         if ( unlikely(!okay) && !rc )
>             rc = -EINVAL;
>
> being equivalent to
>
>         if ( !rc && unlikely(!okay) )
>             rc = -EINVAL;
>
> (no side effects for the expressions on either side of the &&).
> I'll re-word accordingly upon committing, to not give the false
> impression of there having been other than a cosmetic problem.

There is a real problem.  Because the compiler is able to prove that
okay is genuinely read uninitialised in one case, the rules concerning
undefined behaviour permit it to do anything it wishes, including
omitting this if statement.

As far as practical problems go however, it is the build breakage which
is relevant, and it breaks because of a -Werror=maybe-uninitialised.

~Andrew
Andrew Cooper Dec. 22, 2015, 9:56 a.m. UTC | #4
On 21/12/2015 17:50, Boris Ostrovsky wrote:
> On 12/21/2015 12:16 PM, Andrew Cooper wrote:
>> c/s 506db90 "x86/HVM: merge HVM and PVH hypercall tables" introduced
>> a path
>> whereby 'okay' was used uninitialised, with broke compilation on
>> CentOS 7.
>>
>> Splitting the error handling like this is fragile and unnecessary. 
>> Drop the
>> okay variable entirely and just use rc directly, substituting rc =
>> -EINVAL/0
>> for okay = 0/1.
>>
>> In addition, two error messages are updated to print rc, and some stray
>> whitespace is dropped.
>>
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> ---
>> CC: Jan Beulich <JBeulich@suse.com>
>> CC: Boris Ostrovsky <boris.ostrovsky@oracle.com>
>
> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
>
> with a couple of style nits:
>
>> @@ -3258,14 +3254,14 @@ long do_mmuext_op(
>>                 break;
>>           }
>> -
>> +
>>           case MMUEXT_TLB_FLUSH_LOCAL:
>>               if ( likely(d == pg_owner) )
>>                   flush_tlb_local();
>>               else
>>                   rc = -EPERM;
>>               break;
>> -
>> +
>>           case MMUEXT_INVLPG_LOCAL:
>>               if ( unlikely(d != pg_owner) )
>>                   rc = -EPERM;
>
> These look like stray changes.

They are specifically the stray bits of whitespace referred to in the
commit message.

~Andrew
diff mbox

Patch

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 717546a..977b2f4 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2974,7 +2974,7 @@  long do_mmuext_op(
     struct vcpu *curr = current;
     struct domain *d = curr->domain;
     struct domain *pg_owner;
-    int okay, rc = put_old_guest_table(curr);
+    int rc = put_old_guest_table(curr);
 
     if ( unlikely(rc) )
     {
@@ -3053,7 +3053,7 @@  long do_mmuext_op(
             }
         }
 
-        okay = 1;
+        rc = 0;
 
         switch ( op.cmd )
         {
@@ -3087,33 +3087,32 @@  long do_mmuext_op(
             page = get_page_from_gfn(pg_owner, op.arg1.mfn, NULL, P2M_ALLOC);
             if ( unlikely(!page) )
             {
-                okay = 0;
+                rc = -EINVAL;
                 break;
             }
 
             rc = get_page_type_preemptible(page, type);
-            okay = !rc;
-            if ( unlikely(!okay) )
+            if ( unlikely(rc) )
             {
                 if ( rc == -EINTR )
                     rc = -ERESTART;
                 else if ( rc != -ERESTART )
-                    MEM_LOG("Error while pinning mfn %lx", page_to_mfn(page));
+                    MEM_LOG("Error %d while pinning mfn %lx",
+                            rc, page_to_mfn(page));
                 if ( page != curr->arch.old_guest_table )
                     put_page(page);
                 break;
             }
 
-            if ( (rc = xsm_memory_pin_page(XSM_HOOK, d, pg_owner, page)) != 0 )
-                okay = 0;
-            else if ( unlikely(test_and_set_bit(_PGT_pinned,
-                                                &page->u.inuse.type_info)) )
+            rc = xsm_memory_pin_page(XSM_HOOK, d, pg_owner, page);
+            if ( !rc && unlikely(test_and_set_bit(_PGT_pinned,
+                                                  &page->u.inuse.type_info)) )
             {
                 MEM_LOG("Mfn %lx already pinned", page_to_mfn(page));
-                okay = 0;
+                rc = -EINVAL;
             }
 
-            if ( unlikely(!okay) )
+            if ( unlikely(rc) )
                 goto pin_drop;
 
             /* A page is dirtied when its pin status is set. */
@@ -3150,14 +3149,14 @@  long do_mmuext_op(
             page = get_page_from_gfn(pg_owner, op.arg1.mfn, NULL, P2M_ALLOC);
             if ( unlikely(!page) )
             {
-                okay = 0;
+                rc = -EINVAL;
                 MEM_LOG("Mfn %lx bad domain", op.arg1.mfn);
                 break;
             }
 
             if ( !test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) )
             {
-                okay = 0;
+                rc = -EINVAL;
                 put_page(page);
                 MEM_LOG("Mfn %lx not pinned", op.arg1.mfn);
                 break;
@@ -3212,20 +3211,18 @@  long do_mmuext_op(
             if ( op.arg1.mfn != 0 )
             {
                 if ( paging_mode_refcounts(d) )
-                    okay = get_page_from_pagenr(op.arg1.mfn, d);
+                    rc = get_page_from_pagenr(op.arg1.mfn, d) ? 0 : -EINVAL;
                 else
-                {
                     rc = get_page_and_type_from_pagenr(
                         op.arg1.mfn, PGT_root_page_table, d, 0, 1);
-                    okay = !rc;
-                }
-                if ( unlikely(!okay) )
+
+                if ( unlikely(rc) )
                 {
                     if ( rc == -EINTR )
                         rc = -ERESTART;
                     else if ( rc != -ERESTART )
-                        MEM_LOG("Error while installing new mfn %lx",
-                                op.arg1.mfn);
+                        MEM_LOG("Error %d while installing new mfn %lx",
+                                rc, op.arg1.mfn);
                     break;
                 }
                 if ( VM_ASSIST(d, m2p_strict) && !paging_mode_refcounts(d) )
@@ -3248,7 +3245,6 @@  long do_mmuext_op(
                         /* fallthrough */
                     case -ERESTART:
                         curr->arch.old_guest_table = page;
-                        okay = 0;
                         break;
                     default:
                         BUG_ON(rc);
@@ -3258,14 +3254,14 @@  long do_mmuext_op(
 
             break;
         }
-        
+
         case MMUEXT_TLB_FLUSH_LOCAL:
             if ( likely(d == pg_owner) )
                 flush_tlb_local();
             else
                 rc = -EPERM;
             break;
-    
+
         case MMUEXT_INVLPG_LOCAL:
             if ( unlikely(d != pg_owner) )
                 rc = -EPERM;
@@ -3342,7 +3338,7 @@  long do_mmuext_op(
             else
             {
                 MEM_LOG("Non-physdev domain tried to FLUSH_CACHE_GLOBAL");
-                okay = 0;
+                rc = -EINVAL;
             }
             break;
 
@@ -3356,12 +3352,12 @@  long do_mmuext_op(
             else if ( paging_mode_external(d) )
             {
                 MEM_LOG("ignoring SET_LDT hypercall from external domain");
-                okay = 0;
+                rc = -EINVAL;
             }
             else if ( ((ptr & (PAGE_SIZE - 1)) != 0) || !__addr_ok(ptr) ||
                       (ents > 8192) )
             {
-                okay = 0;
+                rc = -EINVAL;
                 MEM_LOG("Bad args to SET_LDT: ptr=%lx, ents=%lx", ptr, ents);
             }
             else if ( (curr->arch.pv_vcpu.ldt_ents != ents) ||
@@ -3385,7 +3381,7 @@  long do_mmuext_op(
                 if ( page )
                     put_page(page);
                 MEM_LOG("Error while clearing mfn %lx", op.arg1.mfn);
-                okay = 0;
+                rc = -EINVAL;
                 break;
             }
 
@@ -3406,15 +3402,16 @@  long do_mmuext_op(
                                          P2M_ALLOC);
             if ( unlikely(!src_page) )
             {
-                okay = 0;
+                rc = -EINVAL;
                 MEM_LOG("Error while copying from mfn %lx", op.arg2.src_mfn);
                 break;
             }
 
             dst_page = get_page_from_gfn(pg_owner, op.arg1.mfn, NULL,
                                          P2M_ALLOC);
-            okay = (dst_page && get_page_type(dst_page, PGT_writable_page));
-            if ( unlikely(!okay) )
+            rc = (dst_page &&
+                  get_page_type(dst_page, PGT_writable_page)) ? 0 : -EINVAL;
+            if ( unlikely(rc) )
             {
                 put_page(src_page);
                 if ( dst_page )
@@ -3443,7 +3440,7 @@  long do_mmuext_op(
             else if ( mfn & (L1_PAGETABLE_ENTRIES-1) )
             {
                 MEM_LOG("Unaligned superpage reference mfn %lx", mfn);
-                okay = 0;
+                rc = -EINVAL;
             }
             else if ( !opt_allow_superpage )
             {
@@ -3464,7 +3461,7 @@  long do_mmuext_op(
             else if ( mfn & (L1_PAGETABLE_ENTRIES-1) )
             {
                 MEM_LOG("Unaligned superpage reference mfn %lx", mfn);
-                okay = 0;
+                rc = -EINVAL;
             }
             else if ( !opt_allow_superpage )
             {
@@ -3483,8 +3480,6 @@  long do_mmuext_op(
         }
 
  done:
-        if ( unlikely(!okay) && !rc )
-            rc = -EINVAL;
         if ( unlikely(rc) )
             break;