diff mbox series

[2/8] x86/paging: fold most HAP and shadow final teardown

Message ID 8d519e00-83c6-aee9-e7ba-523aa4265e1e@suse.com (mailing list archive)
State Superseded
Headers show
Series x86/mm: address aspects noticed during XSA-410 work | expand

Commit Message

Jan Beulich Dec. 21, 2022, 1:25 p.m. UTC
HAP does a few things beyond what's common, which are left there at
least for now. Common operations, however, are moved to
paging_final_teardown(), allowing shadow_final_teardown() to go away.

While moving (and hence generalizing) the respective SHADOW_PRINTK()
drop the logging of total_pages from the 2nd instance - the value is
necessarily zero after {hap,shadow}_set_allocation().

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
The remaining parts of hap_final_teardown() could be moved as well, at
the price of a CONFIG_HVM conditional. I wasn't sure whether that was
deemed reasonable.

Comments

Andrew Cooper Dec. 21, 2022, 5:16 p.m. UTC | #1
On 21/12/2022 1:25 pm, Jan Beulich wrote:
> --- a/xen/arch/x86/mm/paging.c
> +++ b/xen/arch/x86/mm/paging.c
> @@ -842,10 +842,46 @@ int paging_teardown(struct domain *d)
>  /* Call once all of the references to the domain have gone away */
>  void paging_final_teardown(struct domain *d)
>  {
> -    if ( hap_enabled(d) )
> +    bool hap = hap_enabled(d);
> +
> +    PAGING_PRINTK("%pd final teardown starts.  Pages total = %u, free = %u, p2m = %u\n",

PAGING_PRINTK() already includes __func__, so just "%pd start: total %u,
free %u, p2m %u\n" which is shorter.

> +                  d, d->arch.paging.total_pages,
> +                  d->arch.paging.free_pages, d->arch.paging.p2m_pages);
> +
> +    if ( hap )
>          hap_final_teardown(d);
> +
> +    /*
> +     * Double-check that the domain didn't have any paging memory.
> +     * It is possible for a domain that never got domain_kill()ed
> +     * to get here with its paging allocation intact.

I know you're mostly just moving this comment, but it's misleading.

This path is used for the domain_create() error path, and there will be
a nonzero allocation for HVM guests.

I think we do want to rework this eventually - we will simplify things
massively by splitting the things can can only happen for a domain which
has run into relinquish_resources.

At a minimum, I'd suggest dropping the first sentence.  "double check"
implies it's an extraordinary case, which isn't warranted here IMO.

> +     */
> +    if ( d->arch.paging.total_pages )
> +    {
> +        if ( hap )
> +            hap_teardown(d, NULL);
> +        else
> +            shadow_teardown(d, NULL);
> +    }
> +
> +    /* It is now safe to pull down the p2m map. */
> +    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
> +
> +    /* Free any paging memory that the p2m teardown released. */

I don't think this isn't true any more.  410 also made HAP/shadow free
pages fully for a dying domain, so p2m_teardown() at this point won't
add to the free memory pool.

I think the subsequent *_set_allocation() can be dropped, and the
assertions left.

~Andrew
Jan Beulich Dec. 22, 2022, 7:51 a.m. UTC | #2
On 21.12.2022 18:16, Andrew Cooper wrote:
> On 21/12/2022 1:25 pm, Jan Beulich wrote:
>> --- a/xen/arch/x86/mm/paging.c
>> +++ b/xen/arch/x86/mm/paging.c
>> @@ -842,10 +842,46 @@ int paging_teardown(struct domain *d)
>>  /* Call once all of the references to the domain have gone away */
>>  void paging_final_teardown(struct domain *d)
>>  {
>> -    if ( hap_enabled(d) )
>> +    bool hap = hap_enabled(d);
>> +
>> +    PAGING_PRINTK("%pd final teardown starts.  Pages total = %u, free = %u, p2m = %u\n",
> 
> PAGING_PRINTK() already includes __func__, so just "%pd start: total %u,
> free %u, p2m %u\n" which is shorter.

Hmm, yes, can do.

>> +                  d, d->arch.paging.total_pages,
>> +                  d->arch.paging.free_pages, d->arch.paging.p2m_pages);
>> +
>> +    if ( hap )
>>          hap_final_teardown(d);
>> +
>> +    /*
>> +     * Double-check that the domain didn't have any paging memory.
>> +     * It is possible for a domain that never got domain_kill()ed
>> +     * to get here with its paging allocation intact.
> 
> I know you're mostly just moving this comment, but it's misleading.
> 
> This path is used for the domain_create() error path, and there will be
> a nonzero allocation for HVM guests.
> 
> I think we do want to rework this eventually - we will simplify things
> massively by splitting the things can can only happen for a domain which
> has run into relinquish_resources.
> 
> At a minimum, I'd suggest dropping the first sentence.  "double check"
> implies it's an extraordinary case, which isn't warranted here IMO.

Instead of dropping I think I would prefer to make it start "Make sure
...".

>> +     */
>> +    if ( d->arch.paging.total_pages )
>> +    {
>> +        if ( hap )
>> +            hap_teardown(d, NULL);
>> +        else
>> +            shadow_teardown(d, NULL);
>> +    }
>> +
>> +    /* It is now safe to pull down the p2m map. */
>> +    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
>> +
>> +    /* Free any paging memory that the p2m teardown released. */
> 
> I don't think this isn't true any more.  410 also made HAP/shadow free
> pages fully for a dying domain, so p2m_teardown() at this point won't
> add to the free memory pool.
> 
> I think the subsequent *_set_allocation() can be dropped, and the
> assertions left.

I agree, but if anything this will want to be a separate patch then.

Jan
Andrew Cooper Jan. 5, 2023, 5:56 p.m. UTC | #3
On 22/12/2022 7:51 am, Jan Beulich wrote:
> On 21.12.2022 18:16, Andrew Cooper wrote:
>> On 21/12/2022 1:25 pm, Jan Beulich wrote:
>>> +                  d, d->arch.paging.total_pages,
>>> +                  d->arch.paging.free_pages, d->arch.paging.p2m_pages);
>>> +
>>> +    if ( hap )
>>>          hap_final_teardown(d);
>>> +
>>> +    /*
>>> +     * Double-check that the domain didn't have any paging memory.
>>> +     * It is possible for a domain that never got domain_kill()ed
>>> +     * to get here with its paging allocation intact.
>> I know you're mostly just moving this comment, but it's misleading.
>>
>> This path is used for the domain_create() error path, and there will be
>> a nonzero allocation for HVM guests.
>>
>> I think we do want to rework this eventually - we will simplify things
>> massively by splitting the things can can only happen for a domain which
>> has run into relinquish_resources.
>>
>> At a minimum, I'd suggest dropping the first sentence.  "double check"
>> implies it's an extraordinary case, which isn't warranted here IMO.
> Instead of dropping I think I would prefer to make it start "Make sure
> ...".

That's still awkward grammar, and a bit misleading IMO.  How about
rewriting it entirely?

/* Remove remaining paging memory.  This can be nonzero on certain error
paths. */

>
>>> +     */
>>> +    if ( d->arch.paging.total_pages )
>>> +    {
>>> +        if ( hap )
>>> +            hap_teardown(d, NULL);
>>> +        else
>>> +            shadow_teardown(d, NULL);
>>> +    }
>>> +
>>> +    /* It is now safe to pull down the p2m map. */
>>> +    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
>>> +
>>> +    /* Free any paging memory that the p2m teardown released. */
>> I don't think this isn't true any more.  410 also made HAP/shadow free
>> pages fully for a dying domain, so p2m_teardown() at this point won't
>> add to the free memory pool.
>>
>> I think the subsequent *_set_allocation() can be dropped, and the
>> assertions left.
> I agree, but if anything this will want to be a separate patch then.

I'd be happy putting that in this patch, but if you don't want to
combine it, then it should be a prerequisite IMO, so we don't have a
"clean up $X" patch which is shuffling buggy code around.

~Andrew
Jan Beulich Jan. 9, 2023, 11:55 a.m. UTC | #4
On 05.01.2023 18:56, Andrew Cooper wrote:
> On 22/12/2022 7:51 am, Jan Beulich wrote:
>> On 21.12.2022 18:16, Andrew Cooper wrote:
>>> On 21/12/2022 1:25 pm, Jan Beulich wrote:
>>>> +                  d, d->arch.paging.total_pages,
>>>> +                  d->arch.paging.free_pages, d->arch.paging.p2m_pages);
>>>> +
>>>> +    if ( hap )
>>>>          hap_final_teardown(d);
>>>> +
>>>> +    /*
>>>> +     * Double-check that the domain didn't have any paging memory.
>>>> +     * It is possible for a domain that never got domain_kill()ed
>>>> +     * to get here with its paging allocation intact.
>>> I know you're mostly just moving this comment, but it's misleading.
>>>
>>> This path is used for the domain_create() error path, and there will be
>>> a nonzero allocation for HVM guests.
>>>
>>> I think we do want to rework this eventually - we will simplify things
>>> massively by splitting the things can can only happen for a domain which
>>> has run into relinquish_resources.
>>>
>>> At a minimum, I'd suggest dropping the first sentence.  "double check"
>>> implies it's an extraordinary case, which isn't warranted here IMO.
>> Instead of dropping I think I would prefer to make it start "Make sure
>> ...".
> 
> That's still awkward grammar, and a bit misleading IMO.  How about
> rewriting it entirely?
> 
> /* Remove remaining paging memory.  This can be nonzero on certain error
> paths. */

Fine with me, changed.

>>>> +     */
>>>> +    if ( d->arch.paging.total_pages )
>>>> +    {
>>>> +        if ( hap )
>>>> +            hap_teardown(d, NULL);
>>>> +        else
>>>> +            shadow_teardown(d, NULL);
>>>> +    }
>>>> +
>>>> +    /* It is now safe to pull down the p2m map. */
>>>> +    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
>>>> +
>>>> +    /* Free any paging memory that the p2m teardown released. */
>>> I don't think this isn't true any more.  410 also made HAP/shadow free
>>> pages fully for a dying domain, so p2m_teardown() at this point won't
>>> add to the free memory pool.
>>>
>>> I think the subsequent *_set_allocation() can be dropped, and the
>>> assertions left.
>> I agree, but if anything this will want to be a separate patch then.
> 
> I'd be happy putting that in this patch, but if you don't want to
> combine it, then it should be a prerequisite IMO, so we don't have a
> "clean up $X" patch which is shuffling buggy code around.

Well, doing it the other way around (as I already had it before your
reply) also has its advantages. Are you feeling very strong about the
order?

Jan
diff mbox series

Patch

--- a/xen/arch/x86/include/asm/shadow.h
+++ b/xen/arch/x86/include/asm/shadow.h
@@ -78,9 +78,6 @@  int shadow_domctl(struct domain *d,
 void shadow_vcpu_teardown(struct vcpu *v);
 void shadow_teardown(struct domain *d, bool *preempted);
 
-/* Call once all of the references to the domain have gone away */
-void shadow_final_teardown(struct domain *d);
-
 void sh_remove_shadows(struct domain *d, mfn_t gmfn, int fast, int all);
 
 /* Adjust shadows ready for a guest page to change its type. */
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -268,8 +268,8 @@  static void hap_free(struct domain *d, m
 
     /*
      * For dying domains, actually free the memory here. This way less work is
-     * left to hap_final_teardown(), which cannot easily have preemption checks
-     * added.
+     * left to paging_final_teardown(), which cannot easily have preemption
+     * checks added.
      */
     if ( unlikely(d->is_dying) )
     {
@@ -552,18 +552,6 @@  void hap_final_teardown(struct domain *d
     for (i = 0; i < MAX_NESTEDP2M; i++) {
         p2m_teardown(d->arch.nested_p2m[i], true, NULL);
     }
-
-    if ( d->arch.paging.total_pages != 0 )
-        hap_teardown(d, NULL);
-
-    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
-    /* Free any memory that the p2m teardown released */
-    paging_lock(d);
-    hap_set_allocation(d, 0, NULL);
-    ASSERT(d->arch.paging.p2m_pages == 0);
-    ASSERT(d->arch.paging.free_pages == 0);
-    ASSERT(d->arch.paging.total_pages == 0);
-    paging_unlock(d);
 }
 
 void hap_vcpu_teardown(struct vcpu *v)
--- a/xen/arch/x86/mm/paging.c
+++ b/xen/arch/x86/mm/paging.c
@@ -842,10 +842,46 @@  int paging_teardown(struct domain *d)
 /* Call once all of the references to the domain have gone away */
 void paging_final_teardown(struct domain *d)
 {
-    if ( hap_enabled(d) )
+    bool hap = hap_enabled(d);
+
+    PAGING_PRINTK("%pd final teardown starts.  Pages total = %u, free = %u, p2m = %u\n",
+                  d, d->arch.paging.total_pages,
+                  d->arch.paging.free_pages, d->arch.paging.p2m_pages);
+
+    if ( hap )
         hap_final_teardown(d);
+
+    /*
+     * Double-check that the domain didn't have any paging memory.
+     * It is possible for a domain that never got domain_kill()ed
+     * to get here with its paging allocation intact.
+     */
+    if ( d->arch.paging.total_pages )
+    {
+        if ( hap )
+            hap_teardown(d, NULL);
+        else
+            shadow_teardown(d, NULL);
+    }
+
+    /* It is now safe to pull down the p2m map. */
+    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
+
+    /* Free any paging memory that the p2m teardown released. */
+    paging_lock(d);
+
+    if ( hap )
+        hap_set_allocation(d, 0, NULL);
     else
-        shadow_final_teardown(d);
+        shadow_set_allocation(d, 0, NULL);
+
+    PAGING_PRINTK("%pd final teardown done.  Pages free = %u, p2m = %u\n",
+                  d, d->arch.paging.free_pages, d->arch.paging.p2m_pages);
+    ASSERT(!d->arch.paging.p2m_pages);
+    ASSERT(!d->arch.paging.free_pages);
+    ASSERT(!d->arch.paging.total_pages);
+
+    paging_unlock(d);
 
     p2m_final_teardown(d);
 }
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -1232,7 +1232,7 @@  void shadow_free(struct domain *d, mfn_t
 
         /*
          * For dying domains, actually free the memory here. This way less
-         * work is left to shadow_final_teardown(), which cannot easily have
+         * work is left to paging_final_teardown(), which cannot easily have
          * preemption checks added.
          */
         if ( unlikely(dying) )
@@ -2940,35 +2940,6 @@  out:
     }
 }
 
-void shadow_final_teardown(struct domain *d)
-/* Called by arch_domain_destroy(), when it's safe to pull down the p2m map. */
-{
-    SHADOW_PRINTK("dom %u final teardown starts."
-                   "  Shadow pages total = %u, free = %u, p2m=%u\n",
-                   d->domain_id, d->arch.paging.total_pages,
-                   d->arch.paging.free_pages, d->arch.paging.p2m_pages);
-
-    /* Double-check that the domain didn't have any shadow memory.
-     * It is possible for a domain that never got domain_kill()ed
-     * to get here with its shadow allocation intact. */
-    if ( d->arch.paging.total_pages != 0 )
-        shadow_teardown(d, NULL);
-
-    /* It is now safe to pull down the p2m map. */
-    p2m_teardown(p2m_get_hostp2m(d), true, NULL);
-    /* Free any shadow memory that the p2m teardown released */
-    paging_lock(d);
-    shadow_set_allocation(d, 0, NULL);
-    SHADOW_PRINTK("dom %u final teardown done."
-                   "  Shadow pages total = %u, free = %u, p2m=%u\n",
-                   d->domain_id, d->arch.paging.total_pages,
-                   d->arch.paging.free_pages, d->arch.paging.p2m_pages);
-    ASSERT(d->arch.paging.p2m_pages == 0);
-    ASSERT(d->arch.paging.free_pages == 0);
-    ASSERT(d->arch.paging.total_pages == 0);
-    paging_unlock(d);
-}
-
 static int shadow_one_bit_enable(struct domain *d, u32 mode)
 /* Turn on a single shadow mode feature */
 {