diff mbox series

[5/9] xen: introduce assign_pages_nr

Message ID 20210607024318.3988467-6-penny.zheng@arm.com (mailing list archive)
State Superseded
Headers show
Series Domain on Static Allocation | expand

Commit Message

Penny Zheng June 7, 2021, 2:43 a.m. UTC
Introduce new interface assign_pages_nr to deal with when page number is
not in a power-of-two, which will save the trouble each time user needs
to split the size in a power of 2 to use assign_pages.

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
---
changes v2:
- introduce new interface assign_pages_nr
---
 xen/common/page_alloc.c | 26 +++++++++++++++++---------
 xen/include/xen/mm.h    | 10 ++++++++--
 2 files changed, 25 insertions(+), 11 deletions(-)

Comments

Jan Beulich June 10, 2021, 9:49 a.m. UTC | #1
On 07.06.2021 04:43, Penny Zheng wrote:
> Introduce new interface assign_pages_nr to deal with when page number is
> not in a power-of-two, which will save the trouble each time user needs
> to split the size in a power of 2 to use assign_pages.

First of all I still don't see why in this one special case it is a
meaningful burden to do the count-to-order conversion in the caller you
mean to add, and hence why we really need this new function (to keep it
simple, you could even have the caller not break down to arbitrary
power-of-2 chunks, but simply iterate over all individual [order-0]
pages). The more that I'm not happy with the chosen name, despite it
having been suggested during v1 review. _If_ we needed two functions,
imo they ought to be named assign_page() (dealing with a single page of
the given order) and assign_pages(). Backporting confusion could be
helped by altering the order of parameters, such that the compiler
would point out that adjustments at call sites are needed.

Irrespective of this a few remarks on the code change itself:

> --- a/xen/common/page_alloc.c
> +++ b/xen/common/page_alloc.c
> @@ -2301,14 +2301,14 @@ void init_domheap_pages(paddr_t ps, paddr_t pe)
>  }
>  
>  
> -int assign_pages(
> +int assign_pages_nr(
>      struct domain *d,
>      struct page_info *pg,
> -    unsigned int order,
> +    unsigned int nr_pfns,

Even leaving the naming aspect of "pfns" aside, I can't see why this
can't be simply "nr" (of appropriate type, see next remark).

>      unsigned int memflags)
>  {
>      int rc = 0;
> -    unsigned long i;
> +    unsigned int i;

This is not an acceptable type change, at least not as long as it's not
justified at all in the description. While both Arm and x86 will be
fine this way, the code here is supposed to be generic, and hence would
better remain generally correct.

> --- a/xen/include/xen/mm.h
> +++ b/xen/include/xen/mm.h
> @@ -131,12 +131,18 @@ int query_page_offline(mfn_t mfn, uint32_t *status);
>  
>  void heap_init_late(void);
>  
> -int assign_pages(
> +int assign_pages_nr(
>      struct domain *d,
>      struct page_info *pg,
> -    unsigned int order,
> +    unsigned int nr_pfns,
>      unsigned int memflags);
>  
> + int assign_pages(
> +     struct domain *d,
> +     struct page_info *pg,
> +     unsigned int order,
> +     unsigned int memflags);

Bogus extra leading space on all lines of this addition.

Jan
Julien Grall June 30, 2021, 6:29 p.m. UTC | #2
Hi,

On 10/06/2021 10:49, Jan Beulich wrote:
> On 07.06.2021 04:43, Penny Zheng wrote:
>> Introduce new interface assign_pages_nr to deal with when page number is
>> not in a power-of-two, which will save the trouble each time user needs
>> to split the size in a power of 2 to use assign_pages.
> 
> First of all I still don't see why in this one special case it is a
> meaningful burden to do the count-to-order conversion in the caller you
> mean to add,

This sort of works for one caller. However, I would expect some more 
user in the future (we use it for Live-Update).

> and hence why we really need this new function (to keep it
> simple, you could even have the caller not break down to arbitrary
> power-of-2 chunks, but simply iterate over all individual [order-0]
> pages).

The function assign_pages() will always use 1U << order (and sadly 1 << 
order). So we would end up to convert the count in multiple order for 
then directly converting back to a number. To me, this sounds rather 
pointless...

There are also a slight benefits to call assign_pages() a single time 
during boot because it will reduce the number of time we need to 
lock/unlock d->page_alloc_lock.

> The more that I'm not happy with the chosen name, despite it
> having been suggested during v1 review. _If_ we needed two functions,
> imo they ought to be named assign_page() (dealing with a single page of
> the given order) and assign_pages(). Backporting confusion could be
> helped by altering the order of parameters, such that the compiler
> would point out that adjustments at call sites are needed.
> 
> Irrespective of this a few remarks on the code change itself:
> 
>> --- a/xen/common/page_alloc.c
>> +++ b/xen/common/page_alloc.c
>> @@ -2301,14 +2301,14 @@ void init_domheap_pages(paddr_t ps, paddr_t pe)
>>   }
>>   
>>   
>> -int assign_pages(
>> +int assign_pages_nr(
>>       struct domain *d,
>>       struct page_info *pg,
>> -    unsigned int order,
>> +    unsigned int nr_pfns,
> 
> Even leaving the naming aspect of "pfns" aside, I can't see why this
> can't be simply "nr" (of appropriate type, see next remark).
> 
>>       unsigned int memflags)
>>   {
>>       int rc = 0;
>> -    unsigned long i;
>> +    unsigned int i;
> 
> This is not an acceptable type change, at least not as long as it's not
> justified at all in the description. While both Arm and x86 will be
> fine this way, the code here is supposed to be generic, and hence would
> better remain generally correct.

I would like to point out the code is already not correct as we are 
using 1U << order or worse 1 << order :).

Cheers,
Jan Beulich July 1, 2021, 8:26 a.m. UTC | #3
On 30.06.2021 20:29, Julien Grall wrote:
> On 10/06/2021 10:49, Jan Beulich wrote:
>> On 07.06.2021 04:43, Penny Zheng wrote:
>>> Introduce new interface assign_pages_nr to deal with when page number is
>>> not in a power-of-two, which will save the trouble each time user needs
>>> to split the size in a power of 2 to use assign_pages.
>>
>> First of all I still don't see why in this one special case it is a
>> meaningful burden to do the count-to-order conversion in the caller you
>> mean to add,
> 
> This sort of works for one caller. However, I would expect some more 
> user in the future (we use it for Live-Update).
> 
>> and hence why we really need this new function (to keep it
>> simple, you could even have the caller not break down to arbitrary
>> power-of-2 chunks, but simply iterate over all individual [order-0]
>> pages).
> 
> The function assign_pages() will always use 1U << order (and sadly 1 << 
> order). So we would end up to convert the count in multiple order for 
> then directly converting back to a number. To me, this sounds rather 
> pointless...
> 
> There are also a slight benefits to call assign_pages() a single time 
> during boot because it will reduce the number of time we need to 
> lock/unlock d->page_alloc_lock.

Well, all of this is why I did add ...

>> The more that I'm not happy with the chosen name, despite it
>> having been suggested during v1 review. _If_ we needed two functions,
>> imo they ought to be named assign_page() (dealing with a single page of
>> the given order) and assign_pages(). Backporting confusion could be
>> helped by altering the order of parameters, such that the compiler
>> would point out that adjustments at call sites are needed.

... this. Not sure whether you not commenting on it means you agree
with the proposal.

>>> --- a/xen/common/page_alloc.c
>>> +++ b/xen/common/page_alloc.c
>>> @@ -2301,14 +2301,14 @@ void init_domheap_pages(paddr_t ps, paddr_t pe)
>>>   }
>>>   
>>>   
>>> -int assign_pages(
>>> +int assign_pages_nr(
>>>       struct domain *d,
>>>       struct page_info *pg,
>>> -    unsigned int order,
>>> +    unsigned int nr_pfns,
>>
>> Even leaving the naming aspect of "pfns" aside, I can't see why this
>> can't be simply "nr" (of appropriate type, see next remark).
>>
>>>       unsigned int memflags)
>>>   {
>>>       int rc = 0;
>>> -    unsigned long i;
>>> +    unsigned int i;
>>
>> This is not an acceptable type change, at least not as long as it's not
>> justified at all in the description. While both Arm and x86 will be
>> fine this way, the code here is supposed to be generic, and hence would
>> better remain generally correct.
> 
> I would like to point out the code is already not correct as we are 
> using 1U << order or worse 1 << order :).

Indeed there are improvements (towards being consistent) to be made. But
this is not an excuse to make things worse here. At least one of the two
loops already properly uses 1ul; sadly that's only debugging code. And
of course something like domain_tot_pages() (and the underlying field)
dealing with "unsigned int" doesn't help consistency either. As it stands
we're limiting ourselves to 8Tb VMs, as it seems, and for no good reason.

Jan
Julien Grall July 1, 2021, 9:24 a.m. UTC | #4
Hi Jan,

On 01/07/2021 09:26, Jan Beulich wrote:
> On 30.06.2021 20:29, Julien Grall wrote:
>> On 10/06/2021 10:49, Jan Beulich wrote:
>>> On 07.06.2021 04:43, Penny Zheng wrote:
>>>> Introduce new interface assign_pages_nr to deal with when page number is
>>>> not in a power-of-two, which will save the trouble each time user needs
>>>> to split the size in a power of 2 to use assign_pages.
>>>
>>> First of all I still don't see why in this one special case it is a
>>> meaningful burden to do the count-to-order conversion in the caller you
>>> mean to add,
>>
>> This sort of works for one caller. However, I would expect some more
>> user in the future (we use it for Live-Update).
>>
>>> and hence why we really need this new function (to keep it
>>> simple, you could even have the caller not break down to arbitrary
>>> power-of-2 chunks, but simply iterate over all individual [order-0]
>>> pages).
>>
>> The function assign_pages() will always use 1U << order (and sadly 1 <<
>> order). So we would end up to convert the count in multiple order for
>> then directly converting back to a number. To me, this sounds rather
>> pointless...
>>
>> There are also a slight benefits to call assign_pages() a single time
>> during boot because it will reduce the number of time we need to
>> lock/unlock d->page_alloc_lock.
> 
> Well, all of this is why I did add ...
> 
>>> The more that I'm not happy with the chosen name, despite it
>>> having been suggested during v1 review. _If_ we needed two functions,
>>> imo they ought to be named assign_page() (dealing with a single page of
>>> the given order) and assign_pages(). Backporting confusion could be
>>> helped by altering the order of parameters, such that the compiler
>>> would point out that adjustments at call sites are needed.
> 
> ... this. 

Oh, it wasn't entirely clear whether you were objecting of offering the 
possibility to pass a number of pages rather than an order.

> Not sure whether you not commenting on it means you agree
> with the proposal.

Yes I am happy with your proposal.

> 
>>>> --- a/xen/common/page_alloc.c
>>>> +++ b/xen/common/page_alloc.c
>>>> @@ -2301,14 +2301,14 @@ void init_domheap_pages(paddr_t ps, paddr_t pe)
>>>>    }
>>>>    
>>>>    
>>>> -int assign_pages(
>>>> +int assign_pages_nr(
>>>>        struct domain *d,
>>>>        struct page_info *pg,
>>>> -    unsigned int order,
>>>> +    unsigned int nr_pfns,
>>>
>>> Even leaving the naming aspect of "pfns" aside, I can't see why this
>>> can't be simply "nr" (of appropriate type, see next remark).
>>>
>>>>        unsigned int memflags)
>>>>    {
>>>>        int rc = 0;
>>>> -    unsigned long i;
>>>> +    unsigned int i;
>>>
>>> This is not an acceptable type change, at least not as long as it's not
>>> justified at all in the description. While both Arm and x86 will be
>>> fine this way, the code here is supposed to be generic, and hence would
>>> better remain generally correct.
>>
>> I would like to point out the code is already not correct as we are
>> using 1U << order or worse 1 << order :).
> 
> Indeed there are improvements (towards being consistent) to be made. But
> this is not an excuse to make things worse here. At least one of the two
> loops already properly uses 1ul; sadly that's only debugging code. And
> of course something like domain_tot_pages() (and the underlying field)
> dealing with "unsigned int" doesn't help consistency either. As it stands
> we're limiting ourselves to 8Tb VMs, as it seems, and for no good reason.

I actually have a patch in my queue that hardens assign_pages(). I will 
aim to send it later today.

Cheers,
Jan Beulich July 1, 2021, 10:13 a.m. UTC | #5
On 01.07.2021 11:24, Julien Grall wrote:
> On 01/07/2021 09:26, Jan Beulich wrote:
>> On 30.06.2021 20:29, Julien Grall wrote:
>>> On 10/06/2021 10:49, Jan Beulich wrote:
>>>> On 07.06.2021 04:43, Penny Zheng wrote:
>>>>> Introduce new interface assign_pages_nr to deal with when page number is
>>>>> not in a power-of-two, which will save the trouble each time user needs
>>>>> to split the size in a power of 2 to use assign_pages.
>>>>
>>>> First of all I still don't see why in this one special case it is a
>>>> meaningful burden to do the count-to-order conversion in the caller you
>>>> mean to add,
>>>
>>> This sort of works for one caller. However, I would expect some more
>>> user in the future (we use it for Live-Update).
>>>
>>>> and hence why we really need this new function (to keep it
>>>> simple, you could even have the caller not break down to arbitrary
>>>> power-of-2 chunks, but simply iterate over all individual [order-0]
>>>> pages).
>>>
>>> The function assign_pages() will always use 1U << order (and sadly 1 <<
>>> order). So we would end up to convert the count in multiple order for
>>> then directly converting back to a number. To me, this sounds rather
>>> pointless...
>>>
>>> There are also a slight benefits to call assign_pages() a single time
>>> during boot because it will reduce the number of time we need to
>>> lock/unlock d->page_alloc_lock.
>>
>> Well, all of this is why I did add ...
>>
>>>> The more that I'm not happy with the chosen name, despite it
>>>> having been suggested during v1 review. _If_ we needed two functions,
>>>> imo they ought to be named assign_page() (dealing with a single page of
>>>> the given order) and assign_pages(). Backporting confusion could be
>>>> helped by altering the order of parameters, such that the compiler
>>>> would point out that adjustments at call sites are needed.
>>
>> ... this. 
> 
> Oh, it wasn't entirely clear whether you were objecting of offering the 
> possibility to pass a number of pages rather than an order.

Easily understood: I indeed we trying to express my preference to stick
to what we have, but trying to suggest a variant that I think I could
live with.

Jan
diff mbox series

Patch

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 8c00262c04..e244d2e52e 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2301,14 +2301,14 @@  void init_domheap_pages(paddr_t ps, paddr_t pe)
 }
 
 
-int assign_pages(
+int assign_pages_nr(
     struct domain *d,
     struct page_info *pg,
-    unsigned int order,
+    unsigned int nr_pfns,
     unsigned int memflags)
 {
     int rc = 0;
-    unsigned long i;
+    unsigned int i;
 
     spin_lock(&d->page_alloc_lock);
 
@@ -2324,7 +2324,7 @@  int assign_pages(
     {
         unsigned int extra_pages = 0;
 
-        for ( i = 0; i < (1ul << order); i++ )
+        for ( i = 0; i < nr_pfns; i++ )
         {
             ASSERT(!(pg[i].count_info & ~PGC_extra));
             if ( pg[i].count_info & PGC_extra )
@@ -2333,18 +2333,18 @@  int assign_pages(
 
         ASSERT(!extra_pages ||
                ((memflags & MEMF_no_refcount) &&
-                extra_pages == 1u << order));
+                extra_pages == nr_pfns));
     }
 #endif
 
     if ( pg[0].count_info & PGC_extra )
     {
-        d->extra_pages += 1u << order;
+        d->extra_pages += nr_pfns;
         memflags &= ~MEMF_no_refcount;
     }
     else if ( !(memflags & MEMF_no_refcount) )
     {
-        unsigned int tot_pages = domain_tot_pages(d) + (1 << order);
+        unsigned int tot_pages = domain_tot_pages(d) + nr_pfns;
 
         if ( unlikely(tot_pages > d->max_pages) )
         {
@@ -2356,10 +2356,10 @@  int assign_pages(
     }
 
     if ( !(memflags & MEMF_no_refcount) &&
-         unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
+         unlikely(domain_adjust_tot_pages(d, nr_pfns) == nr_pfns) )
         get_knownalive_domain(d);
 
-    for ( i = 0; i < (1 << order); i++ )
+    for ( i = 0; i < nr_pfns; i++ )
     {
         ASSERT(page_get_owner(&pg[i]) == NULL);
         page_set_owner(&pg[i], d);
@@ -2374,6 +2374,14 @@  int assign_pages(
     return rc;
 }
 
+int assign_pages(
+    struct domain *d,
+    struct page_info *pg,
+    unsigned int order,
+    unsigned int memflags)
+{
+    return assign_pages_nr(d, pg, (1U << order), memflags);
+}
 
 struct page_info *alloc_domheap_pages(
     struct domain *d, unsigned int order, unsigned int memflags)
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index df25e55966..25d970e857 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -131,12 +131,18 @@  int query_page_offline(mfn_t mfn, uint32_t *status);
 
 void heap_init_late(void);
 
-int assign_pages(
+int assign_pages_nr(
     struct domain *d,
     struct page_info *pg,
-    unsigned int order,
+    unsigned int nr_pfns,
     unsigned int memflags);
 
+ int assign_pages(
+     struct domain *d,
+     struct page_info *pg,
+     unsigned int order,
+     unsigned int memflags);
+
 /* Dump info to serial console */
 void arch_dump_shared_mem_info(void);