|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 6/9] xen/common: add cache coloring allocator for domains
On Sat, Oct 22, 2022 at 5:51 PM Carlo Nonato
<carlo.nonato@xxxxxxxxxxxxxxx> wrote:
>
> From: Luca Miccio <lucmiccio@xxxxxxxxx>
>
> This commit adds a new memory page allocator that implements the cache
> coloring mechanism. The allocation algorithm follows the given domain color
> configuration and maximizes contiguity in the page selection of multiple
> subsequent requests.
>
> Pages are stored in a color-indexed array of lists, each one sorted by
> machine address, that is called the colored heap. A simple initialization
> function computes the color of any available page and inserts it in the
> corresponding list. When a domain requests a page, the allocator takes one
> from the subset of lists whose colors equals the domain configuration. It
> chooses the page with the highest machine address such that contiguous
> pages are sequentially allocated, if this is made possible by a color
> assignment which includes adjacent colors.
>
> The allocator can handle only requests with order equals to 0 since the
> single color granularity is represented in memory by one page.
>
> The buddy allocator must coexist with the colored one because the Xen heap
> isn't colored. For this reason a new Kconfig option and a command line
> parameter are added to let the user set the amount of memory reserved for
> the buddy allocator. Even when cache coloring is enabled, this memory isn't
> managed by the colored allocator.
>
> Colored heap information is dumped in the dump_heap() debug-key function.
>
> Signed-off-by: Luca Miccio <lucmiccio@xxxxxxxxx>
> Signed-off-by: Marco Solieri <marco.solieri@xxxxxxxxxxxxxxx>
> Signed-off-by: Carlo Nonato <carlo.nonato@xxxxxxxxxxxxxxx>
> ---
> v3:
> - fixed PGC_colored bits values
> - merged debug-key for dump_color_heap() with the one for dump_heap()
> - number of pages for each color in an array to easily dump color heap info
> - heap_lock in colored allocator to ensure atomicity and clarify it with a
> comment
> - added page_list_add_{next|prev} to add pages in the middle of the list
> - p2m tables use pages of same colors as domain
> - CONFIG_BUDDY_ALLOCATOR_SIZE is now an int (MiB)
> - buddy allocator reserved size is now respected as configured in Kconfig
> - removed useless functions and refactored the code
> - fixed PGC_colored flag that was removed when a page was allocated
> - merged with #7 since it would have been too small
> ---
> docs/misc/arm/cache-coloring.rst | 39 ++++-
> docs/misc/xen-command-line.pandoc | 14 ++
> xen/arch/arm/Kconfig | 12 ++
> xen/arch/arm/coloring.c | 10 ++
> xen/arch/arm/include/asm/coloring.h | 6 +
> xen/arch/arm/include/asm/mm.h | 3 +
> xen/arch/arm/p2m.c | 7 +-
> xen/common/page_alloc.c | 259 +++++++++++++++++++++++++---
> xen/include/xen/mm.h | 43 +++++
> 9 files changed, 371 insertions(+), 22 deletions(-)
>
> diff --git a/docs/misc/arm/cache-coloring.rst
> b/docs/misc/arm/cache-coloring.rst
> index dd2e851a26..0c89278aee 100644
> --- a/docs/misc/arm/cache-coloring.rst
> +++ b/docs/misc/arm/cache-coloring.rst
> @@ -16,6 +16,9 @@ In order to enable and use it, few steps are needed.
> (refer to menuconfig help for value meaning and when it should be changed).
>
> CONFIG_MAX_CACHE_COLORS=<n>
> +- If needed, change the amount of memory reserved for the buddy allocator
> either
> + from the Xen configuration file, via the CONFIG_BUDDY_ALLOCATOR_SIZE value,
> + or with the command line option. See `Colored allocator and buddy
> allocator`.
> - Assign colors to domains using the `Color selection format`_ (see
> `Coloring parameters`_ for more documentation pointers).
>
> @@ -162,6 +165,18 @@ Please refer to the relative documentation in
> Note that if no color configuration is provided for domains, they fallback to
> the default one, which corresponds simply to all available colors.
>
> +Colored allocator and buddy allocator
> +*************************************
> +
> +The colored allocator distributes pages based on color configurations of
> +domains so that each domains only gets pages of its own colors.
> +The colored allocator is meant as an alternative to the buddy allocator
> because
> +its allocation policy is by definition incompatible with the generic one.
> Since
> +the Xen heap is not colored yet, we need to support the coexistence of the
> two
> +allocators and some memory must be left for the buddy one.
> +The buddy allocator memory can be reserved from the Xen configuration file or
> +with the help of a command-line option.
> +
> Known issues and limitations
> ****************************
>
> @@ -182,7 +197,6 @@ configuration structure size used in domain creation.
> "uint16_t" is the biggest
> integer type that fit the constraint and 2^15 is the biggest power of 2 it
> can
> easily represent. This value is big enough for the generic case, though.
>
> -
> "xen,static-mem" isn't supported when coloring is enabled
> #########################################################
>
> @@ -190,3 +204,26 @@ In the domain configuration, "xen,static-mem" allows
> memory to be statically
> allocated to the domain. This isn't possibile when cache coloring is enabled,
> because that memory can't be guaranteed to be of the same colors assigned to
> that domain.
> +
> +Colored allocator can only make use of order-0 pages
> +####################################################
> +
> +The cache coloring technique relies on memory mappings and on the smallest
> +amount of memory that can be mapped to achieve the maximum number of colors
> +(cache partitions) possible. This amount is what is normally called a page
> and,
> +in Xen terminology, the order-0 page is the smallest one. The fairly simple
> +colored allocator currently implemented, makes use only of such pages.
> +It must be said that a more complex one could, in theory, adopt higher order
> +pages if the colors selection contained adjacent colors. Two subsequent
> colors,
> +for example, can be represented by an order-1 page, four colors correspond to
> +an order-2 page, etc.
> +
> +Fail to boot colored DomUs with large memory size
> +#################################################
> +
> +If the Linux kernel used for Dom0 does not contain the upstream commit
> +3941552aec1e04d63999988a057ae09a1c56ebeb and uses the hypercall buffer
> device,
> +colored DomUs with memory size larger then 127 MB cannot be created. This is
> +caused by the default limit of this buffer of 64 pages. The solution is to
> +manually apply the above patch, or to check if there is an updated version of
> +the kernel in use for Dom0 that contains this change.
> diff --git a/docs/misc/xen-command-line.pandoc
> b/docs/misc/xen-command-line.pandoc
> index 3f04414134..25a59dd6a9 100644
> --- a/docs/misc/xen-command-line.pandoc
> +++ b/docs/misc/xen-command-line.pandoc
> @@ -299,6 +299,20 @@ can be maintained with the pv-shim mechanism.
> cause Xen not to use Indirect Branch Tracking even when support is
> available in hardware.
>
> +### buddy-alloc-size (arm64)
> +> `= <size>`
> +
> +> Default: `64M`
> +
> +Amount of memory reserved for the buddy allocator when colored allocator is
> +active. This options is parsed only when cache coloring support is enabled.
> +The colored allocator is meant as an alternative to the buddy allocator,
> +because its allocation policy is by definition incompatible with the
> +generic one. Since the Xen heap systems is not colored yet, we need to
> +support the coexistence of the two allocators for now. This parameter, which
> is
> +optional and for expert only, it's used to set the amount of memory reserved
> to
> +the buddy allocator.
> +
> ### clocksource (x86)
> > `= pit | hpet | acpi | tsc`
>
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index c45a9c5917..4cfa75b2ef 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -153,6 +153,18 @@ config MAX_CACHE_COLORS
> Note that if, at any time, a color configuration with more colors
> than the
> maximum is employed, an error is produced.
>
> +config BUDDY_ALLOCATOR_SIZE
> + int "Buddy allocator reserved memory size (MiB)"
> + default "64"
> + depends on CACHE_COLORING
> + help
> + Amount of memory reserved for the buddy allocator to work alongside
> + the colored one. The colored allocator is meant as an alternative
> to the
> + buddy allocator because its allocation policy is by definition
> + incompatible with the generic one. Since the Xen heap is not
> colored yet,
> + we need to support the coexistence of the two allocators and some
> memory
> + must be left for the buddy one.
> +
> config TEE
> bool "Enable TEE mediators support (UNSUPPORTED)" if UNSUPPORTED
> default n
> diff --git a/xen/arch/arm/coloring.c b/xen/arch/arm/coloring.c
> index 685a431c3d..2cae215cd2 100644
> --- a/xen/arch/arm/coloring.c
> +++ b/xen/arch/arm/coloring.c
> @@ -322,6 +322,16 @@ void prepare_color_domain_config(struct
> xen_arch_domainconfig *config,
> config->num_colors = (uint16_t)num_colors;
> }
>
> +unsigned int page_to_color(const struct page_info *pg)
> +{
> + return addr_to_color(page_to_maddr(pg));
> +}
> +
> +unsigned int get_max_colors(void)
> +{
> + return max_colors;
> +}
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/arch/arm/include/asm/coloring.h
> b/xen/arch/arm/include/asm/coloring.h
> index 549eb408a3..0147f95968 100644
> --- a/xen/arch/arm/include/asm/coloring.h
> +++ b/xen/arch/arm/include/asm/coloring.h
> @@ -31,6 +31,8 @@
>
> #include <public/arch-arm.h>
>
> +struct page_info;
> +
> bool __init coloring_init(void);
>
> int domain_coloring_init(struct domain *d,
> @@ -41,6 +43,10 @@ void domain_dump_coloring_info(struct domain *d);
> void prepare_color_domain_config(struct xen_arch_domainconfig *config,
> const char *colors_str);
>
> +unsigned int page_to_color(const struct page_info *pg);
> +
> +unsigned int get_max_colors(void);
> +
> #else /* !CONFIG_CACHE_COLORING */
>
> static inline bool __init coloring_init(void) { return true; }
> diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
> index 68adcac9fa..e848fa4adf 100644
> --- a/xen/arch/arm/include/asm/mm.h
> +++ b/xen/arch/arm/include/asm/mm.h
> @@ -128,6 +128,9 @@ struct page_info
> #else
> #define PGC_static 0
> #endif
> +/* Page is cache colored */
> +#define _PGC_colored PG_shift(4)
> +#define PGC_colored PG_mask(1, 4)
> /* ... */
> /* Page is broken? */
> #define _PGC_broken PG_shift(7)
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 8449f97fe7..9ac7dc6216 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -661,7 +661,12 @@ static int p2m_create_table(struct p2m_domain *p2m,
> lpae_t *entry)
>
> ASSERT(!p2m_is_valid(*entry));
>
> - page = alloc_domheap_page(NULL, 0);
> + /* If cache coloring is enabled, p2m tables are allocated using the
> domain
> + * coloring configuration to prevent cache interference. */
> + if ( IS_ENABLED(CONFIG_CACHE_COLORING) )
> + page = alloc_domheap_page(p2m->domain, MEMF_no_refcount);
> + else
> + page = alloc_domheap_page(NULL, 0);
> if ( page == NULL )
> return -ENOMEM;
This diff can't be applied to the current master. I need to check
how things have changed in the meantime.
> diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
> index 62afb07bc6..fe214cd6ac 100644
> --- a/xen/common/page_alloc.c
> +++ b/xen/common/page_alloc.c
> @@ -150,6 +150,9 @@
> #define p2m_pod_offline_or_broken_hit(pg) 0
> #define p2m_pod_offline_or_broken_replace(pg) BUG_ON(pg != NULL)
> #endif
> +#ifdef CONFIG_HAS_CACHE_COLORING
> +#include <asm/coloring.h>
> +#endif
>
> #ifndef PGC_static
> #define PGC_static 0
> @@ -231,6 +234,14 @@ static bool __read_mostly scrub_debug;
> #define scrub_debug false
> #endif
>
> +/* Memory required for buddy allocator to work with colored one */
> +#ifdef CONFIG_BUDDY_ALLOCATOR_SIZE
> +static unsigned long __initdata buddy_alloc_size =
> + CONFIG_BUDDY_ALLOCATOR_SIZE << 20;
> +#else
> + static unsigned long __initdata buddy_alloc_size = 0;
> +#endif
> +
> /*
> * Bit width of the DMA heap -- used to override NUMA-node-first.
> * allocation strategy, which can otherwise exhaust low memory.
> @@ -440,7 +451,180 @@ mfn_t __init alloc_boot_pages(unsigned long nr_pfns,
> unsigned long pfn_align)
> BUG();
> }
>
> +static DEFINE_SPINLOCK(heap_lock);
>
> +/* Initialise fields which have other uses for free pages. */
> +static void init_free_page_fields(struct page_info *pg)
> +{
> + pg->u.inuse.type_info = PGT_TYPE_INFO_INITIALIZER;
> + page_set_owner(pg, NULL);
> +}
> +
> +#ifdef CONFIG_CACHE_COLORING
> +/*************************
> + * COLORED SIDE-ALLOCATOR
> + *
> + * Pages are stored by their color in separate lists. Each list defines a
> color
> + * and it is initialized during end_boot_allocator, where each page's color
> + * is calculated and the page itself is put in the correct list.
> + * After initialization there will be N lists where N is the number of
> + * available colors on the platform.
> + * The {free|alloc}_color_heap_page overwrite pg->count_info, but they do it
> in
> + * the same way as the buddy allocator corresponding functions do:
> + * protecting the access with a critical section using heap_lock.
> + */
> +typedef struct page_list_head colored_pages_t;
> +static colored_pages_t *__ro_after_init _color_heap;
> +static unsigned long *__ro_after_init free_colored_pages;
> +
> +#define color_heap(color) (&_color_heap[color])
> +
> +static void free_color_heap_page(struct page_info *pg)
> +{
> + struct page_info *pos;
> + unsigned int color = page_to_color(pg);
> + colored_pages_t *head = color_heap(color);
> +
> + spin_lock(&heap_lock);
> +
> + pg->count_info = PGC_state_free | PGC_colored;
> + page_set_owner(pg, NULL);
> + free_colored_pages[color]++;
> +
> + page_list_for_each( pos, head )
> + {
> + if ( page_to_maddr(pos) < page_to_maddr(pg) )
> + break;
> + }
> +
> + page_list_add_next(pg, pos, head);
> +
> + spin_unlock(&heap_lock);
> +}
> +
> +static struct page_info *alloc_color_heap_page(unsigned int memflags,
> + const unsigned int *colors,
> + unsigned int num_colors)
> +{
> + struct page_info *pg = NULL;
> + unsigned int i, color;
> + bool need_tlbflush = false;
> + uint32_t tlbflush_timestamp = 0;
> +
> + spin_lock(&heap_lock);
> +
> + for ( i = 0; i < num_colors; i++ )
> + {
> + struct page_info *tmp;
> +
> + if ( page_list_empty(color_heap(colors[i])) )
> + continue;
> +
> + tmp = page_list_first(color_heap(colors[i]));
> + if ( !pg || page_to_maddr(tmp) > page_to_maddr(pg) )
> + pg = tmp;
> + }
> +
> + if ( !pg )
> + {
> + spin_unlock(&heap_lock);
> + return NULL;
> + }
> +
> + pg->count_info = PGC_state_inuse | PGC_colored;
> +
> + if ( !(memflags & MEMF_no_tlbflush) )
> + accumulate_tlbflush(&need_tlbflush, pg, &tlbflush_timestamp);
> +
> + init_free_page_fields(pg);
> + flush_page_to_ram(mfn_x(page_to_mfn(pg)),
> + !(memflags & MEMF_no_icache_flush));
> +
> + color = page_to_color(pg);
> + free_colored_pages[color]--;
> + page_list_del(pg, color_heap(color));
> +
> + spin_unlock(&heap_lock);
> +
> + if ( need_tlbflush )
> + filtered_flush_tlb_mask(tlbflush_timestamp);
> +
> + return pg;
> +}
> +
> +static void __init init_color_heap_pages(struct page_info *pg,
> + unsigned long nr_pages)
> +{
> + unsigned int i;
> +
> + if ( !_color_heap )
> + {
> + unsigned int max_colors = get_max_colors();
> +
> + _color_heap = xmalloc_array(colored_pages_t, max_colors);
> + BUG_ON(!_color_heap);
> + free_colored_pages = xzalloc_array(unsigned long, max_colors);
> + BUG_ON(!free_colored_pages);
> +
> + for ( i = 0; i < max_colors; i++ )
> + INIT_PAGE_LIST_HEAD(color_heap(i));
> + }
> +
> + printk(XENLOG_DEBUG
> + "Init color heap with %lu pages starting from: %#"PRIx64"\n",
> + nr_pages, page_to_maddr(pg));
> +
> + for ( i = 0; i < nr_pages; i++ )
> + free_color_heap_page(&pg[i]);
> +}
> +
> +static struct page_info *alloc_color_domheap_page(struct domain *d,
> + unsigned int memflags)
> +{
> + struct page_info *pg;
> +
> + pg = alloc_color_heap_page(memflags, d->arch.colors, d->arch.num_colors);
> + if ( !pg )
> + return NULL;
> +
> + if ( !(memflags & MEMF_no_owner) )
> + {
> + if ( memflags & MEMF_no_refcount )
> + pg->count_info |= PGC_extra;
> + if ( assign_page(pg, 0, d, memflags) )
> + {
> + free_color_heap_page(pg);
> + return NULL;
> + }
> + }
> +
> + return pg;
> +}
> +
> +static void dump_color_heap(void)
> +{
> + unsigned int color;
> +
> + printk("Dumping coloring heap info\n");
> + for ( color = 0; color < get_max_colors(); color++ )
> + printk("Color heap[%u]: %lu pages\n", color,
> free_colored_pages[color]);
> +}
> +
> +integer_param("buddy-alloc-size", buddy_alloc_size);
> +
> +#else /* !CONFIG_CACHE_COLORING */
> +
> +static void __init init_color_heap_pages(struct page_info *pg,
> + unsigned long nr_pages) {}
> +static struct page_info *alloc_color_domheap_page(struct domain *d,
> + unsigned int memflags)
> +{
> + return NULL;
> +}
> +static void free_color_heap_page(struct page_info *pg) {}
> +static void dump_color_heap(void) {}
> +
> +#endif /* CONFIG_CACHE_COLORING */
>
> /*************************
> * BINARY BUDDY ALLOCATOR
> @@ -462,7 +646,6 @@ static unsigned long node_need_scrub[MAX_NUMNODES];
> static unsigned long *avail[MAX_NUMNODES];
> static long total_avail_pages;
>
> -static DEFINE_SPINLOCK(heap_lock);
> static long outstanding_claims; /* total outstanding claims by all domains */
>
> unsigned long domain_adjust_tot_pages(struct domain *d, long pages)
> @@ -1027,10 +1210,7 @@ static struct page_info *alloc_heap_pages(
> accumulate_tlbflush(&need_tlbflush, &pg[i],
> &tlbflush_timestamp);
>
> - /* Initialise fields which have other uses for free pages. */
> - pg[i].u.inuse.type_info = PGT_TYPE_INFO_INITIALIZER;
> - page_set_owner(&pg[i], NULL);
> -
> + init_free_page_fields(&pg[i]);
> }
>
> spin_unlock(&heap_lock);
> @@ -1926,24 +2106,49 @@ static unsigned long avail_heap_pages(
> void __init end_boot_allocator(void)
> {
> unsigned int i;
> + unsigned long buddy_pages;
>
> - /* Pages that are free now go to the domain sub-allocator. */
> - for ( i = 0; i < nr_bootmem_regions; i++ )
> + buddy_pages = PFN_DOWN(buddy_alloc_size);
> +
> + if ( !IS_ENABLED(CONFIG_CACHE_COLORING) )
> {
> - struct bootmem_region *r = &bootmem_region_list[i];
> - if ( (r->s < r->e) &&
> - (phys_to_nid(pfn_to_paddr(r->s)) == cpu_to_node(0)) )
> + /* Pages that are free now go to the domain sub-allocator. */
> + for ( i = 0; i < nr_bootmem_regions; i++ )
> {
> - init_heap_pages(mfn_to_page(_mfn(r->s)), r->e - r->s);
> - r->e = r->s;
> - break;
> + struct bootmem_region *r = &bootmem_region_list[i];
> + if ( (r->s < r->e) &&
> + (phys_to_nid(pfn_to_paddr(r->s)) == cpu_to_node(0)) )
> + {
> + init_heap_pages(mfn_to_page(_mfn(r->s)), r->e - r->s);
> + r->e = r->s;
> + break;
> + }
> }
> }
> +
> for ( i = nr_bootmem_regions; i-- > 0; )
> {
> - struct bootmem_region *r = &bootmem_region_list[i];
> + struct bootmem_region *r;
> +
> + if ( IS_ENABLED(CONFIG_CACHE_COLORING) )
> + r = &bootmem_region_list[nr_bootmem_regions - i - 1];
> + else
> + r = &bootmem_region_list[i];
> +
> + if ( buddy_pages && (r->s < r->e) )
> + {
> + unsigned long pages = MIN(r->e - r->s, buddy_pages);
> + init_heap_pages(mfn_to_page(_mfn(r->s)), pages);
> + r->s += pages;
> + buddy_pages -= pages;
> + }
> if ( r->s < r->e )
> - init_heap_pages(mfn_to_page(_mfn(r->s)), r->e - r->s);
> + {
> + if ( IS_ENABLED(CONFIG_CACHE_COLORING) )
> + init_color_heap_pages(mfn_to_page(_mfn(r->s)), r->e - r->s);
> + else
> + init_heap_pages(mfn_to_page(_mfn(r->s)), r->e - r->s);
> + }
> }
> nr_bootmem_regions = 0;
>
> @@ -2344,7 +2549,8 @@ int assign_pages(
>
> for ( i = 0; i < nr; i++ )
> {
> - ASSERT(!(pg[i].count_info & ~(PGC_extra | PGC_static)));
> + ASSERT(!(pg[i].count_info & ~(PGC_extra | PGC_static |
> + PGC_colored)));
> if ( pg[i].count_info & PGC_extra )
> extra_pages++;
> }
> @@ -2429,6 +2635,15 @@ struct page_info *alloc_domheap_pages(
>
> ASSERT_ALLOC_CONTEXT();
>
> + /* Only domains are supported for coloring */
> + if ( IS_ENABLED(CONFIG_CACHE_COLORING) && d )
> + {
> + /* Colored allocation must be done on 0 order */
> + if ( order )
> + return NULL;
> + return alloc_color_domheap_page(d, memflags);
> + }
> +
> bits = domain_clamp_alloc_bitsize(memflags & MEMF_no_owner ? NULL : d,
> bits ? : (BITS_PER_LONG+PAGE_SHIFT));
>
> @@ -2546,7 +2761,10 @@ void free_domheap_pages(struct page_info *pg, unsigned
> int order)
> scrub = 1;
> }
>
> - free_heap_pages(pg, order, scrub);
> + if ( pg->count_info & PGC_colored )
> + free_color_heap_page(pg);
> + else
> + free_heap_pages(pg, order, scrub);
> }
>
> if ( drop_dom_ref )
> @@ -2653,6 +2871,9 @@ static void cf_check dump_heap(unsigned char key)
> continue;
> printk("Node %d has %lu unscrubbed pages\n", i, node_need_scrub[i]);
> }
> +
> + if ( IS_ENABLED(CONFIG_CACHE_COLORING) )
> + dump_color_heap();
> }
>
> static __init int cf_check register_heap_trigger(void)
> @@ -2785,9 +3006,7 @@ static bool prepare_staticmem_pages(struct page_info
> *pg, unsigned long nr_mfns,
> * to PGC_state_inuse.
> */
> pg[i].count_info = PGC_static | PGC_state_inuse;
> - /* Initialise fields which have other uses for free pages. */
> - pg[i].u.inuse.type_info = PGT_TYPE_INFO_INITIALIZER;
> - page_set_owner(&pg[i], NULL);
> + init_free_page_fields(&pg[i]);
> }
>
> spin_unlock(&heap_lock);
> diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
> index a925028ab3..0d48502e75 100644
> --- a/xen/include/xen/mm.h
> +++ b/xen/include/xen/mm.h
> @@ -297,6 +297,37 @@ page_list_add_tail(struct page_info *page, struct
> page_list_head *head)
> }
> head->tail = page;
> }
> +static inline void
> +_page_list_add(struct page_info *new, struct page_info *prev,
> + struct page_info *next)
> +{
> + new->list.prev = page_to_pdx(prev);
> + new->list.next = page_to_pdx(next);
> + prev->list.next = page_to_pdx(new);
> + next->list.prev = page_to_pdx(new);
> +}
> +static inline void
> +page_list_add_next(struct page_info *new, struct page_info *prev,
> + struct page_list_head *head)
> +{
> + struct page_info *next = page_list_next(prev, head);
> +
> + if ( !next )
> + page_list_add_tail(new, head);
> + else
> + _page_list_add(new, prev, next);
> +}
> +static inline void
> +page_list_add_prev(struct page_info *new, struct page_info *next,
> + struct page_list_head *head)
> +{
> + struct page_info *prev = page_list_prev(next, head);
> +
> + if ( !prev )
> + page_list_add(new, head);
> + else
> + _page_list_add(new, prev, next);
> +}
> static inline bool_t
> __page_list_del_head(struct page_info *page, struct page_list_head *head,
> struct page_info *next, struct page_info *prev)
> @@ -449,6 +480,18 @@ page_list_add_tail(struct page_info *page, struct
> page_list_head *head)
> list_add_tail(&page->list, head);
> }
> static inline void
> +page_list_add_next(struct page_info *new, struct page_info *prev,
> + struct page_list_head *head)
> +{
> + page_list_add_tail(new, &prev->list);
> +}
> +static inline void
> +page_list_add_prev(struct page_info *new, struct page_info *next,
> + struct page_list_head *head)
> +{
> + page_list_add(new, &next->list);
> +}
> +static inline void
> page_list_del(struct page_info *page, struct page_list_head *head)
> {
> list_del(&page->list);
> --
> 2.34.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |