[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] mm: introduce xvmalloc() et al and use for grant table allocations
commit 9102fcd9579fb195749e96b99b36ee14f1314a55 Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Wed Aug 14 08:47:58 2024 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Wed Aug 14 08:47:58 2024 +0200 mm: introduce xvmalloc() et al and use for grant table allocations All of the array allocations in grant_table_init() can exceed a page's worth of memory, which xmalloc()-based interfaces aren't really suitable for after boot. We also don't need any of these allocations to be physically contiguous. Introduce interfaces dynamically switching between xmalloc() et al and vmalloc() et al, based on requested size, and use them instead. All the wrappers in the new header are cloned mostly verbatim from xmalloc.h, with the sole adjustment to switch unsigned long to size_t for sizes and to unsigned int for alignments, and with the cloning of x[mz]alloc_bytes() avoided. The exception is xvmemdup(), where the const related comment on xmemdup() is actually addressed and hence dropped. While adjusting grant_table_destroy() also move ahead the clearing of the struct domain field. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Reviewed-by: Julien Grall <jgrall@xxxxxxxxxx> --- xen/common/grant_table.c | 30 ++++++++-------- xen/common/vmap.c | 88 ++++++++++++++++++++++++++++++++++++++++------ xen/include/xen/xmalloc.h | 3 ++ xen/include/xen/xvmalloc.h | 75 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 24 deletions(-) diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index ebe2d2a3ce..ab36f45ded 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -39,7 +39,7 @@ #include <xen/paging.h> #include <xen/keyhandler.h> #include <xen/radix-tree.h> -#include <xen/vmap.h> +#include <xen/xvmalloc.h> #include <xen/nospec.h> #include <xsm/xsm.h> #include <asm/flushtlb.h> @@ -1995,7 +1995,7 @@ int grant_table_init(struct domain *d, int max_grant_frames, return -EINVAL; } - if ( (gt = xzalloc(struct grant_table)) == NULL ) + if ( (gt = xvzalloc(struct grant_table)) == NULL ) return -ENOMEM; /* Simple stuff. */ @@ -2012,15 +2012,16 @@ int grant_table_init(struct domain *d, int max_grant_frames, d->grant_table = gt; /* Active grant table. */ - gt->active = xzalloc_array(struct active_grant_entry *, - max_nr_active_grant_frames(gt)); + gt->active = xvzalloc_array(struct active_grant_entry *, + max_nr_active_grant_frames(gt)); if ( gt->active == NULL ) goto out; /* Tracking of mapped foreign frames table */ if ( gt->max_maptrack_frames ) { - gt->maptrack = vzalloc(gt->max_maptrack_frames * sizeof(*gt->maptrack)); + gt->maptrack = xvzalloc_array(struct grant_mapping *, + gt->max_maptrack_frames); if ( gt->maptrack == NULL ) goto out; @@ -2028,13 +2029,13 @@ int grant_table_init(struct domain *d, int max_grant_frames, } /* Shared grant table. */ - gt->shared_raw = xzalloc_array(void *, gt->max_grant_frames); + gt->shared_raw = xvzalloc_array(void *, gt->max_grant_frames); if ( gt->shared_raw == NULL ) goto out; /* Status pages for grant table - for version 2 */ - gt->status = xzalloc_array(grant_status_t *, - grant_to_status_frames(gt->max_grant_frames)); + gt->status = xvzalloc_array(grant_status_t *, + grant_to_status_frames(gt->max_grant_frames)); if ( gt->status == NULL ) goto out; @@ -4010,23 +4011,24 @@ grant_table_destroy( if ( t == NULL ) return; + d->grant_table = NULL; + for ( i = 0; i < nr_grant_frames(t); i++ ) free_xenheap_page(t->shared_raw[i]); - xfree(t->shared_raw); + xvfree(t->shared_raw); ASSERT(!t->maptrack_limit); - vfree(t->maptrack); + xvfree(t->maptrack); for ( i = 0; i < nr_active_grant_frames(t); i++ ) free_xenheap_page(t->active[i]); - xfree(t->active); + xvfree(t->active); for ( i = 0; i < nr_status_frames(t); i++ ) free_xenheap_page(t->status[i]); - xfree(t->status); + xvfree(t->status); - xfree(t); - d->grant_table = NULL; + xvfree(t); } void grant_table_init_vcpu(struct vcpu *v) diff --git a/xen/common/vmap.c b/xen/common/vmap.c index b3b4ddf653..ced9cbf26f 100644 --- a/xen/common/vmap.c +++ b/xen/common/vmap.c @@ -7,6 +7,7 @@ #include <xen/spinlock.h> #include <xen/types.h> #include <xen/vmap.h> +#include <xen/xvmalloc.h> #include <asm/page.h> static DEFINE_SPINLOCK(vm_lock); @@ -335,28 +336,95 @@ void *vzalloc(size_t size) return p; } -void vfree(void *va) +static void _vfree(const void *va, unsigned int pages) { - unsigned int i, pages; + unsigned int i; struct page_info *pg; PAGE_LIST_HEAD(pg_list); - if ( !va ) - return; - - pages = vmap_size(va); ASSERT(pages); for ( i = 0; i < pages; i++ ) { - struct page_info *page = vmap_to_page(va + i * PAGE_SIZE); - - ASSERT(page); - page_list_add(page, &pg_list); + pg = vmap_to_page(va + i * PAGE_SIZE); + ASSERT(pg); + page_list_add(pg, &pg_list); } vunmap(va); while ( (pg = page_list_remove_head(&pg_list)) != NULL ) free_domheap_page(pg); } + +void vfree(void *va) +{ + if ( !va ) + return; + + _vfree(va, vmap_size(va)); +} + +void xvfree(void *va) +{ + unsigned int pages = vm_size(va, VMAP_DEFAULT); + + if ( pages ) + _vfree(va, pages); + else + xfree(va); +} + +void *_xvmalloc(size_t size, unsigned int align) +{ + ASSERT(align <= PAGE_SIZE); + return size <= PAGE_SIZE ? _xmalloc(size, align) : vmalloc(size); +} + +void *_xvzalloc(size_t size, unsigned int align) +{ + ASSERT(align <= PAGE_SIZE); + return size <= PAGE_SIZE ? _xzalloc(size, align) : vzalloc(size); +} + +void *_xvrealloc(void *va, size_t size, unsigned int align) +{ + size_t pages = vm_size(va, VMAP_DEFAULT); + void *ptr; + + ASSERT(align <= PAGE_SIZE); + + if ( !pages ) + { + if ( size <= PAGE_SIZE ) + return _xrealloc(va, size, align); + + ptr = vmalloc(size); + if ( ptr && va && va != ZERO_BLOCK_PTR ) + { + /* + * xmalloc-based allocations up to PAGE_SIZE don't cross page + * boundaries. Therefore, without needing to know the exact + * prior allocation size, simply copy the entire tail of the + * page containing the earlier allocation. + */ + memcpy(ptr, va, PAGE_SIZE - PAGE_OFFSET(va)); + xfree(va); + } + } + else if ( pages == PFN_UP(size) ) + ptr = va; + else + { + ptr = _xvmalloc(size, align); + if ( ptr ) + { + memcpy(ptr, va, min(size, pages << PAGE_SHIFT)); + vfree(va); + } + else if ( pages > PFN_UP(size) ) + ptr = va; + } + + return ptr; +} #endif diff --git a/xen/include/xen/xmalloc.h b/xen/include/xen/xmalloc.h index 1b88a83be8..b903fa2e26 100644 --- a/xen/include/xen/xmalloc.h +++ b/xen/include/xen/xmalloc.h @@ -7,6 +7,9 @@ /* * Xen malloc/free-style interface. + * + * NOTE: Unless physically contiguous memory space is required, the interfaces + * in xvmalloc.h are to be used in preference to the ones here. */ /* Allocate space for typed object. */ diff --git a/xen/include/xen/xvmalloc.h b/xen/include/xen/xvmalloc.h new file mode 100644 index 0000000000..ab71a1e1a7 --- /dev/null +++ b/xen/include/xen/xvmalloc.h @@ -0,0 +1,75 @@ +#ifndef XEN__XVMALLOC_H +#define XEN__XVMALLOC_H + +#include <xen/types.h> + +/* + * Xen malloc/free-style interface, as long as there's no need to have + * physically contiguous memory allocated. These should be used in preference + * to xmalloc() et al. + */ + +/* Allocate space for typed object. */ +#define xvmalloc(_type) ((_type *)_xvmalloc(sizeof(_type), __alignof__(_type))) +#define xvzalloc(_type) ((_type *)_xvzalloc(sizeof(_type), __alignof__(_type))) + +/* Allocate space for a typed object and copy an existing instance. */ +#define xvmemdup(ptr) \ +({ \ + void *p_ = _xvmalloc(sizeof(*(ptr)), __alignof__(*(ptr))); \ + if ( p_ ) \ + memcpy(p_, ptr, sizeof(*(ptr))); \ + (typeof(*(ptr)) *)p_; \ +}) + +/* Allocate space for array of typed objects. */ +#define xvmalloc_array(_type, _num) \ + ((_type *)_xvmalloc_array(sizeof(_type), __alignof__(_type), _num)) +#define xvzalloc_array(_type, _num) \ + ((_type *)_xvzalloc_array(sizeof(_type), __alignof__(_type), _num)) + +/* Allocate space for a structure with a flexible array of typed objects. */ +#define xvzalloc_flex_struct(type, field, nr) \ + ((type *)_xvzalloc(offsetof(type, field[nr]), __alignof__(type))) + +#define xvmalloc_flex_struct(type, field, nr) \ + ((type *)_xvmalloc(offsetof(type, field[nr]), __alignof__(type))) + +/* Re-allocate space for a structure with a flexible array of typed objects. */ +#define xvrealloc_flex_struct(ptr, field, nr) \ + ((typeof(ptr))_xvrealloc(ptr, offsetof(typeof(*(ptr)), field[nr]), \ + __alignof__(typeof(*(ptr))))) + +/* Free any of the above. */ +void xvfree(void *); + +/* Free an allocation, and zero the pointer to it. */ +#define XVFREE(p) do { \ + xvfree(p); \ + (p) = NULL; \ +} while ( false ) + +/* Underlying functions */ +void *_xvmalloc(size_t size, unsigned int align); +void *_xvzalloc(size_t size, unsigned int align); +void *_xvrealloc(void *ptr, size_t size, unsigned int align); + +static inline void *_xvmalloc_array( + size_t size, unsigned int align, unsigned long num) +{ + /* Check for overflow. */ + if ( size && num > UINT_MAX / size ) + return NULL; + return _xvmalloc(size * num, align); +} + +static inline void *_xvzalloc_array( + size_t size, unsigned int align, unsigned long num) +{ + /* Check for overflow. */ + if ( size && num > UINT_MAX / size ) + return NULL; + return _xvzalloc(size * num, align); +} + +#endif /* XEN__XVMALLOC_H */ -- generated by git-patchbot for /home/xen/git/xen.git#master
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |