Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE
xen.24553
libxc.sr.superpage.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libxc.sr.superpage.patch of Package xen.24553
tools/libxc: use superpages during restore of HVM guest bsc#1035231 - migration of HVM domU does not use superpages on destination dom0 bsc#1055695 - XEN: 11SP4 and 12SP3 HVM guests can not be restored During creating of a HVM domU meminit_hvm() tries to map superpages. After save/restore or migration this mapping is lost, everything is allocated in single pages. This causes a performance degradition after migration. Add neccessary code to preallocate a superpage for the chunk of pfns that is received. In case a pfn was not populated on the sending side it must be freed on the receiving side to avoid over-allocation. The existing code for x86_pv is moved unmodified into its own file. Index: xen-4.13.1-testing/tools/libxc/xc_dom_x86.c =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_dom_x86.c +++ xen-4.13.1-testing/tools/libxc/xc_dom_x86.c @@ -45,11 +45,6 @@ #define SUPERPAGE_BATCH_SIZE 512 -#define SUPERPAGE_2MB_SHIFT 9 -#define SUPERPAGE_2MB_NR_PFNS (1UL << SUPERPAGE_2MB_SHIFT) -#define SUPERPAGE_1GB_SHIFT 18 -#define SUPERPAGE_1GB_NR_PFNS (1UL << SUPERPAGE_1GB_SHIFT) - #define X86_CR0_PE 0x01 #define X86_CR0_ET 0x10 Index: xen-4.13.1-testing/tools/libxc/xc_private.h =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_private.h +++ xen-4.13.1-testing/tools/libxc/xc_private.h @@ -71,6 +71,11 @@ struct iovec { #define DECLARE_FLASK_OP struct xen_flask_op op #define DECLARE_PLATFORM_OP struct xen_platform_op platform_op +#define SUPERPAGE_2MB_SHIFT 9 +#define SUPERPAGE_2MB_NR_PFNS (1UL << SUPERPAGE_2MB_SHIFT) +#define SUPERPAGE_1GB_SHIFT 18 +#define SUPERPAGE_1GB_NR_PFNS (1UL << SUPERPAGE_1GB_SHIFT) + #undef PAGE_SHIFT #undef PAGE_SIZE #undef PAGE_MASK Index: xen-4.13.1-testing/tools/libxc/xc_sr_common.c =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_sr_common.c +++ xen-4.13.1-testing/tools/libxc/xc_sr_common.c @@ -156,6 +156,47 @@ static void __attribute__((unused)) buil } /* + * Expand the tracking structures as needed. + * To avoid realloc()ing too excessively, the size increased to the nearest power + * of two large enough to contain the required number of bits. + */ +bool _xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits) +{ + if (bits > bm->bits) + { + size_t new_max; + size_t old_sz, new_sz; + void *p; + + /* Round up to the nearest power of two larger than bit, less 1. */ + new_max = bits; + new_max |= new_max >> 1; + new_max |= new_max >> 2; + new_max |= new_max >> 4; + new_max |= new_max >> 8; + new_max |= new_max >> 16; +#ifdef __x86_64__ + new_max |= new_max >> 32; +#endif + + old_sz = bitmap_size(bm->bits + 1); + new_sz = bitmap_size(new_max + 1); + p = realloc(bm->p, new_sz); + if (!p) + return false; + + if (bm->p) + memset(p + old_sz, 0, new_sz - old_sz); + else + memset(p, 0, new_sz); + + bm->p = p; + bm->bits = new_max; + } + return true; +} + +/* * Local variables: * mode: C * c-file-style: "BSD" Index: xen-4.13.1-testing/tools/libxc/xc_sr_common.h =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_sr_common.h +++ xen-4.13.1-testing/tools/libxc/xc_sr_common.h @@ -140,6 +140,16 @@ struct xc_sr_restore_ops int (*setup)(struct xc_sr_context *ctx); /** + * Populate PFNs + * + * Given a set of pfns, obtain memory from Xen to fill the physmap for the + * unpopulated subset. + */ + int (*populate_pfns)(struct xc_sr_context *ctx, unsigned count, + const xen_pfn_t *original_pfns, const uint32_t *types); + + + /** * Process an individual record from the stream. The caller shall take * care of processing common records (e.g. END, PAGE_DATA). * @@ -172,6 +182,12 @@ struct xc_sr_x86_pv_restore_vcpu size_t basicsz, extdsz, xsavesz, msrsz; }; +struct xc_sr_bitmap +{ + void *p; + unsigned long bits; +}; + struct xc_sr_context { xc_interface *xch; @@ -216,6 +232,8 @@ struct xc_sr_context int send_back_fd; unsigned long p2m_size; + unsigned long max_pages; + unsigned long tot_pages; xc_hypercall_buffer_t dirty_bitmap_hbuf; /* From Image Header. */ @@ -253,8 +271,7 @@ struct xc_sr_context uint32_t xenstore_domid, console_domid; /* Bitmap of currently populated PFNs during restore. */ - unsigned long *populated_pfns; - xen_pfn_t max_populated_pfn; + struct xc_sr_bitmap populated_pfns; /* Sender has invoked verify mode on the stream. */ bool verify; @@ -329,6 +346,12 @@ struct xc_sr_context /* HVM context blob. */ void *context; size_t contextsz; + + /* Bitmap of currently allocated PFNs during restore. */ + struct xc_sr_bitmap attempted_1g; + struct xc_sr_bitmap attempted_2m; + struct xc_sr_bitmap allocated_pfns; + xen_pfn_t idx1G_prev, idx2M_prev; } restore; }; } x86_hvm; @@ -341,6 +364,69 @@ extern struct xc_sr_save_ops save_ops_x8 extern struct xc_sr_restore_ops restore_ops_x86_pv; extern struct xc_sr_restore_ops restore_ops_x86_hvm; +extern bool _xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits); + +static inline bool xc_sr_bitmap_resize(struct xc_sr_bitmap *bm, unsigned long bits) +{ + if (bits > bm->bits) + return _xc_sr_bitmap_resize(bm, bits); + return true; +} + +static inline void xc_sr_bitmap_free(struct xc_sr_bitmap *bm) +{ + free(bm->p); + bm->p = NULL; +} + +static inline bool xc_sr_set_bit(unsigned long bit, struct xc_sr_bitmap *bm) +{ + if (!xc_sr_bitmap_resize(bm, bit)) + return false; + + set_bit(bit, bm->p); + return true; +} + +static inline bool xc_sr_test_bit(unsigned long bit, struct xc_sr_bitmap *bm) +{ + if (bit > bm->bits) + return false; + return !!test_bit(bit, bm->p); +} + +static inline bool xc_sr_test_and_clear_bit(unsigned long bit, struct xc_sr_bitmap *bm) +{ + if (bit > bm->bits) + return false; + return !!test_and_clear_bit(bit, bm->p); +} + +static inline bool xc_sr_test_and_set_bit(unsigned long bit, struct xc_sr_bitmap *bm) +{ + if (bit > bm->bits) + return false; + return !!test_and_set_bit(bit, bm->p); +} + +static inline bool pfn_is_populated(struct xc_sr_context *ctx, xen_pfn_t pfn) +{ + return xc_sr_test_bit(pfn, &ctx->restore.populated_pfns); +} + +static inline int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn) +{ + xc_interface *xch = ctx->xch; + + if ( !xc_sr_set_bit(pfn, &ctx->restore.populated_pfns) ) + { + ERROR("Failed to realloc populated_pfns bitmap"); + errno = ENOMEM; + return -1; + } + return 0; +} + struct xc_sr_record { uint32_t type; @@ -389,14 +475,6 @@ static inline int write_record(struct xc */ int read_record(struct xc_sr_context *ctx, int fd, struct xc_sr_record *rec); -/* - * This would ideally be private in restore.c, but is needed by - * x86_pv_localise_page() if we receive pagetables frames ahead of the - * contents of the frames they point at. - */ -int populate_pfns(struct xc_sr_context *ctx, unsigned count, - const xen_pfn_t *original_pfns, const uint32_t *types); - #endif /* * Local variables: Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore.c =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore.c +++ xen-4.13.1-testing/tools/libxc/xc_sr_restore.c @@ -69,132 +69,6 @@ static int read_headers(struct xc_sr_con } /* - * Is a pfn populated? - */ -static bool pfn_is_populated(const struct xc_sr_context *ctx, xen_pfn_t pfn) -{ - if ( pfn > ctx->restore.max_populated_pfn ) - return false; - return test_bit(pfn, ctx->restore.populated_pfns); -} - -/* - * Set a pfn as populated, expanding the tracking structures if needed. To - * avoid realloc()ing too excessively, the size increased to the nearest power - * of two large enough to contain the required pfn. - */ -static int pfn_set_populated(struct xc_sr_context *ctx, xen_pfn_t pfn) -{ - xc_interface *xch = ctx->xch; - - if ( pfn > ctx->restore.max_populated_pfn ) - { - xen_pfn_t new_max; - size_t old_sz, new_sz; - unsigned long *p; - - /* Round up to the nearest power of two larger than pfn, less 1. */ - new_max = pfn; - new_max |= new_max >> 1; - new_max |= new_max >> 2; - new_max |= new_max >> 4; - new_max |= new_max >> 8; - new_max |= new_max >> 16; -#ifdef __x86_64__ - new_max |= new_max >> 32; -#endif - - old_sz = bitmap_size(ctx->restore.max_populated_pfn + 1); - new_sz = bitmap_size(new_max + 1); - p = realloc(ctx->restore.populated_pfns, new_sz); - if ( !p ) - { - ERROR("Failed to realloc populated bitmap"); - errno = ENOMEM; - return -1; - } - - memset((uint8_t *)p + old_sz, 0x00, new_sz - old_sz); - - ctx->restore.populated_pfns = p; - ctx->restore.max_populated_pfn = new_max; - } - - assert(!test_bit(pfn, ctx->restore.populated_pfns)); - set_bit(pfn, ctx->restore.populated_pfns); - - return 0; -} - -/* - * Given a set of pfns, obtain memory from Xen to fill the physmap for the - * unpopulated subset. If types is NULL, no page type checking is performed - * and all unpopulated pfns are populated. - */ -int populate_pfns(struct xc_sr_context *ctx, unsigned count, - const xen_pfn_t *original_pfns, const uint32_t *types) -{ - xc_interface *xch = ctx->xch; - xen_pfn_t *mfns = malloc(count * sizeof(*mfns)), - *pfns = malloc(count * sizeof(*pfns)); - unsigned i, nr_pfns = 0; - int rc = -1; - - if ( !mfns || !pfns ) - { - ERROR("Failed to allocate %zu bytes for populating the physmap", - 2 * count * sizeof(*mfns)); - goto err; - } - - for ( i = 0; i < count; ++i ) - { - if ( (!types || (types && - (types[i] != XEN_DOMCTL_PFINFO_XTAB && - types[i] != XEN_DOMCTL_PFINFO_BROKEN))) && - !pfn_is_populated(ctx, original_pfns[i]) ) - { - rc = pfn_set_populated(ctx, original_pfns[i]); - if ( rc ) - goto err; - pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i]; - ++nr_pfns; - } - } - - if ( nr_pfns ) - { - rc = xc_domain_populate_physmap_exact( - xch, ctx->domid, nr_pfns, 0, 0, mfns); - if ( rc ) - { - PERROR("Failed to populate physmap"); - goto err; - } - - for ( i = 0; i < nr_pfns; ++i ) - { - if ( mfns[i] == INVALID_MFN ) - { - ERROR("Populate physmap failed for pfn %u", i); - rc = -1; - goto err; - } - - ctx->restore.ops.set_gfn(ctx, pfns[i], mfns[i]); - } - } - - rc = 0; - - err: - free(pfns); - free(mfns); - - return rc; -} - -/* * Given a list of pfns, their types, and a block of page data from the * stream, populate and record their types, map the relevant subset and copy * the data into the guest. @@ -219,7 +93,7 @@ static int process_page_data(struct xc_s goto err; } - rc = populate_pfns(ctx, count, pfns, types); + rc = ctx->restore.ops.populate_pfns(ctx, count, pfns, types); if ( rc ) { ERROR("Failed to populate pfns for batch of %u pages", count); @@ -684,10 +558,8 @@ static int setup(struct xc_sr_context *c if ( rc ) goto err; - ctx->restore.max_populated_pfn = (32 * 1024 / 4) - 1; - ctx->restore.populated_pfns = bitmap_alloc( - ctx->restore.max_populated_pfn + 1); - if ( !ctx->restore.populated_pfns ) + rc = !xc_sr_bitmap_resize(&ctx->restore.populated_pfns, 32 * 1024 / 4); + if ( rc ) { ERROR("Unable to allocate memory for populated_pfns bitmap"); rc = -1; @@ -722,7 +594,7 @@ static void cleanup(struct xc_sr_context xc_hypercall_buffer_free_pages(xch, dirty_bitmap, NRPAGES(bitmap_size(ctx->restore.p2m_size))); free(ctx->restore.buffered_records); - free(ctx->restore.populated_pfns); + xc_sr_bitmap_free(&ctx->restore.populated_pfns); if ( ctx->restore.ops.cleanup(ctx) ) PERROR("Failed to clean up"); } @@ -886,7 +758,12 @@ int xc_domain_restore(xc_interface *xch, return -1; } + /* See xc_domain_getinfo */ + ctx.restore.max_pages = ctx.dominfo.max_memkb >> (PAGE_SHIFT-10); + ctx.restore.tot_pages = ctx.dominfo.nr_pages; ctx.restore.p2m_size = nr_pfns; + DPRINTF("dom %u p2m_size %lx max_pages %lx", + ctx.domid, ctx.restore.p2m_size, ctx.restore.max_pages); if ( ctx.dominfo.hvm ) { Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_hvm.c =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore_x86_hvm.c +++ xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_hvm.c @@ -135,6 +135,8 @@ static int x86_hvm_localise_page(struct static int x86_hvm_setup(struct xc_sr_context *ctx) { xc_interface *xch = ctx->xch; + struct xc_sr_bitmap *bm; + unsigned long bits; if ( ctx->restore.guest_type != DHDR_TYPE_X86_HVM ) { @@ -158,7 +160,41 @@ static int x86_hvm_setup(struct xc_sr_co } #endif + bm = &ctx->x86_hvm.restore.attempted_1g; + bits = (ctx->restore.p2m_size >> SUPERPAGE_1GB_SHIFT) + 1; + if ( xc_sr_bitmap_resize(bm, bits) == false ) + goto out; + + bm = &ctx->x86_hvm.restore.attempted_2m; + bits = (ctx->restore.p2m_size >> SUPERPAGE_2MB_SHIFT) + 1; + if ( xc_sr_bitmap_resize(bm, bits) == false ) + goto out; + + bm = &ctx->x86_hvm.restore.allocated_pfns; + bits = ctx->restore.p2m_size + 1; + if ( xc_sr_bitmap_resize(bm, bits) == false ) + goto out; + + /* No superpage in 1st 2MB due to VGA hole */ +#define LAPIC_BASE_ADDRESS 0xfee00000u +#define ACPI_INFO_PHYSICAL_ADDRESS 0xfc000000u +#define LAPIC_BASE_PFN (LAPIC_BASE_ADDRESS >> XC_PAGE_SHIFT) +#define ACPI_INFO_PFN (ACPI_INFO_PHYSICAL_ADDRESS >> XC_PAGE_SHIFT) + bm = &ctx->x86_hvm.restore.attempted_1g; + xc_sr_set_bit(0, bm); + xc_sr_set_bit(LAPIC_BASE_PFN >> SUPERPAGE_1GB_SHIFT, bm); + xc_sr_set_bit(ACPI_INFO_PFN >> SUPERPAGE_1GB_SHIFT, bm); + + bm = &ctx->x86_hvm.restore.attempted_2m; + xc_sr_set_bit(0, bm); + xc_sr_set_bit(LAPIC_BASE_PFN >> SUPERPAGE_2MB_SHIFT, bm); + xc_sr_set_bit(ACPI_INFO_PFN >> SUPERPAGE_2MB_SHIFT, bm); + return 0; + +out: + ERROR("Unable to allocate memory for pfn bitmaps"); + return -1; } /* @@ -233,10 +269,325 @@ static int x86_hvm_stream_complete(struc static int x86_hvm_cleanup(struct xc_sr_context *ctx) { free(ctx->x86_hvm.restore.context); + xc_sr_bitmap_free(&ctx->x86_hvm.restore.attempted_1g); + xc_sr_bitmap_free(&ctx->x86_hvm.restore.attempted_2m); + xc_sr_bitmap_free(&ctx->x86_hvm.restore.allocated_pfns); + + return 0; +} + +/* + * Set a pfn as allocated, expanding the tracking structures if needed. + */ +static int pfn_set_allocated(struct xc_sr_context *ctx, xen_pfn_t pfn) +{ + xc_interface *xch = ctx->xch; + if ( !xc_sr_set_bit(pfn, &ctx->x86_hvm.restore.allocated_pfns) ) + { + ERROR("Failed to realloc allocated_pfns bitmap"); + errno = ENOMEM; + return -1; + } return 0; } +struct x86_hvm_sp { + xen_pfn_t pfn; + xen_pfn_t base_pfn; + unsigned long index; + unsigned long count; +}; + +/* + * Try to allocate a 1GB page for this pfn, but avoid Over-allocation. + * If this succeeds, mark the range of 2MB pages as busy. + */ +static bool x86_hvm_alloc_1g(struct xc_sr_context *ctx, struct x86_hvm_sp *sp) +{ + xc_interface *xch = ctx->xch; + struct xc_sr_bitmap *bm; + unsigned int order, shift; + int i, done; + xen_pfn_t extent; + + bm = &ctx->x86_hvm.restore.attempted_1g; + + /* Only one attempt to avoid overlapping allocation */ + if ( xc_sr_test_and_set_bit(sp->index, bm) ) + return false; + + order = SUPERPAGE_1GB_SHIFT; + sp->count = 1ULL << order; + + /* Allocate only if there is room for another superpage */ + if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages ) + return false; + + extent = sp->base_pfn = (sp->pfn >> order) << order; + done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent); + if ( done < 0 ) { + PERROR("populate_physmap failed."); + return false; + } + if ( done == 0 ) + return false; + + DPRINTF("1G base_pfn %" PRI_xen_pfn "\n", sp->base_pfn); + + /* Mark all 2MB pages as done to avoid overlapping allocation */ + bm = &ctx->x86_hvm.restore.attempted_2m; + shift = SUPERPAGE_1GB_SHIFT - SUPERPAGE_2MB_SHIFT; + for ( i = 0; i < (sp->count >> shift); i++ ) + xc_sr_set_bit((sp->base_pfn >> SUPERPAGE_2MB_SHIFT) + i, bm); + + return true; +} + +/* Allocate a 2MB page if x86_hvm_alloc_1g failed, avoid Over-allocation. */ +static bool x86_hvm_alloc_2m(struct xc_sr_context *ctx, struct x86_hvm_sp *sp) +{ + xc_interface *xch = ctx->xch; + struct xc_sr_bitmap *bm; + unsigned int order; + int done; + xen_pfn_t extent; + + bm = &ctx->x86_hvm.restore.attempted_2m; + + /* Only one attempt to avoid overlapping allocation */ + if ( xc_sr_test_and_set_bit(sp->index, bm) ) + return false; + + order = SUPERPAGE_2MB_SHIFT; + sp->count = 1ULL << order; + + /* Allocate only if there is room for another superpage */ + if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages ) + return false; + + extent = sp->base_pfn = (sp->pfn >> order) << order; + done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent); + if ( done < 0 ) { + PERROR("populate_physmap failed."); + return false; + } + if ( done == 0 ) + return false; + + DPRINTF("2M base_pfn %" PRI_xen_pfn "\n", sp->base_pfn); + return true; +} + +/* Allocate a single page if x86_hvm_alloc_2m failed. */ +static bool x86_hvm_alloc_4k(struct xc_sr_context *ctx, struct x86_hvm_sp *sp) +{ + xc_interface *xch = ctx->xch; + unsigned int order; + int done; + xen_pfn_t extent; + + order = 0; + sp->count = 1ULL << order; + + /* Allocate only if there is room for another page */ + if ( ctx->restore.tot_pages + sp->count > ctx->restore.max_pages ) + return false; + + extent = sp->base_pfn = (sp->pfn >> order) << order; + done = xc_domain_populate_physmap(xch, ctx->domid, 1, order, 0, &extent); + if ( done < 0 ) { + PERROR("populate_physmap failed."); + return false; + } + if ( done == 0 ) + return false; + + DPRINTF("4K base_pfn %" PRI_xen_pfn "\n", sp->base_pfn); + return true; +} +/* + * Attempt to allocate a superpage where the pfn resides. + */ +static int x86_hvm_allocate_pfn(struct xc_sr_context *ctx, xen_pfn_t pfn) +{ + xc_interface *xch = ctx->xch; + bool success; + int rc = -1; + unsigned long idx_1g, idx_2m; + struct x86_hvm_sp sp = { + .pfn = pfn + }; + + if ( xc_sr_test_bit(pfn, &ctx->x86_hvm.restore.allocated_pfns) ) + return 0; + + idx_1g = pfn >> SUPERPAGE_1GB_SHIFT; + idx_2m = pfn >> SUPERPAGE_2MB_SHIFT; + if ( !xc_sr_bitmap_resize(&ctx->x86_hvm.restore.attempted_1g, idx_1g) ) + { + PERROR("Failed to realloc attempted_1g"); + return -1; + } + if ( !xc_sr_bitmap_resize(&ctx->x86_hvm.restore.attempted_2m, idx_2m) ) + { + PERROR("Failed to realloc attempted_2m"); + return -1; + } + + sp.index = idx_1g; + success = x86_hvm_alloc_1g(ctx, &sp); + + if ( success == false ) { + sp.index = idx_2m; + success = x86_hvm_alloc_2m(ctx, &sp); + } + + if ( success == false ) { + sp.index = 0; + success = x86_hvm_alloc_4k(ctx, &sp); + } + + if ( success == true ) { + do { + sp.count--; + ctx->restore.tot_pages++; + rc = pfn_set_allocated(ctx, sp.base_pfn + sp.count); + if ( rc ) + break; + } while ( sp.count ); + } + return rc; +} + +static bool x86_hvm_punch_hole(struct xc_sr_context *ctx, xen_pfn_t max_pfn) +{ + xc_interface *xch = ctx->xch; + struct xc_sr_bitmap *bm; + xen_pfn_t _pfn, pfn, min_pfn; + uint32_t domid, freed = 0, order; + int rc = -1; + + /* + * Scan the entire superpage because several batches will fit into + * a superpage, and it is unknown which pfn triggered the allocation. + */ + order = SUPERPAGE_1GB_SHIFT; + pfn = min_pfn = (max_pfn >> order) << order; + + while ( pfn <= max_pfn ) + { + bm = &ctx->x86_hvm.restore.allocated_pfns; + if ( !xc_sr_bitmap_resize(bm, pfn) ) + { + PERROR("Failed to realloc allocated_pfns %" PRI_xen_pfn, pfn); + return false; + } + if ( !pfn_is_populated(ctx, pfn) && + xc_sr_test_and_clear_bit(pfn, bm) ) { + domid = ctx->domid; + _pfn = pfn; + rc = xc_domain_decrease_reservation_exact(xch, domid, 1, 0, &_pfn); + if ( rc ) + { + PERROR("Failed to release pfn %" PRI_xen_pfn, pfn); + return false; + } + ctx->restore.tot_pages--; + freed++; + } + pfn++; + } + if ( freed ) + DPRINTF("freed %u between %" PRI_xen_pfn " %" PRI_xen_pfn "\n", + freed, min_pfn, max_pfn); + return true; +} + +/* + * Try to allocate superpages. + * This works without memory map only if the pfns arrive in incremental order. + */ +static int x86_hvm_populate_pfns(struct xc_sr_context *ctx, unsigned count, + const xen_pfn_t *original_pfns, + const uint32_t *types) +{ + xc_interface *xch = ctx->xch; + xen_pfn_t pfn, min_pfn = original_pfns[0], max_pfn = original_pfns[0]; + xen_pfn_t idx1G, idx2M; + unsigned i, order; + int rc = -1; + + /* Loop once over the array to show statistics */ + for ( i = 0; i < count; ++i ) + { + if ( original_pfns[i] < min_pfn ) + min_pfn = original_pfns[i]; + if ( original_pfns[i] > max_pfn ) + max_pfn = original_pfns[i]; + } + DPRINTF("batch of %u pfns between %" PRI_xen_pfn " %" PRI_xen_pfn "\n", + count, min_pfn, max_pfn); + + for ( i = 0; i < count; ++i ) + { + pfn = original_pfns[i]; + idx1G = pfn >> SUPERPAGE_1GB_SHIFT; + idx2M = pfn >> SUPERPAGE_2MB_SHIFT; + + /* + * If this pfn is in another 2MB superpage it is required to punch holes + * to release memory, starting from the 1GB boundary up to the highest + * pfn within the previous 2MB superpage. + */ + if ( ctx->x86_hvm.restore.idx1G_prev == idx1G && + ctx->x86_hvm.restore.idx2M_prev == idx2M ) + { + /* Same 2MB superpage, nothing to do */ + ; + } else { + /* + * If this next pfn is within another 1GB or 2MB superpage it is + * required to scan the entire previous superpage because there + * might be holes between the last pfn and the end of the superpage. + */ + if ( ctx->x86_hvm.restore.idx1G_prev != idx1G ) + { + order = SUPERPAGE_1GB_SHIFT; + max_pfn = ((ctx->x86_hvm.restore.idx1G_prev + 1) << order) - 1; + } + else + { + order = SUPERPAGE_2MB_SHIFT; + max_pfn = ((ctx->x86_hvm.restore.idx2M_prev + 1) << order) - 1; + } + + if ( x86_hvm_punch_hole(ctx, max_pfn) == false ) + goto err; + } + + if ( (types[i] != XEN_DOMCTL_PFINFO_XTAB && + types[i] != XEN_DOMCTL_PFINFO_BROKEN) && + !pfn_is_populated(ctx, pfn) ) + { + rc = x86_hvm_allocate_pfn(ctx, pfn); + if ( rc ) + goto err; + rc = pfn_set_populated(ctx, pfn); + if ( rc ) + goto err; + } + ctx->x86_hvm.restore.idx1G_prev = idx1G; + ctx->x86_hvm.restore.idx2M_prev = idx2M; + } + + rc = 0; + + err: + return rc; +} + + struct xc_sr_restore_ops restore_ops_x86_hvm = { .pfn_is_valid = x86_hvm_pfn_is_valid, @@ -245,6 +596,7 @@ struct xc_sr_restore_ops restore_ops_x86 .set_page_type = x86_hvm_set_page_type, .localise_page = x86_hvm_localise_page, .setup = x86_hvm_setup, + .populate_pfns = x86_hvm_populate_pfns, .process_record = x86_hvm_process_record, .stream_complete = x86_hvm_stream_complete, .cleanup = x86_hvm_cleanup, Index: xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_pv.c =================================================================== --- xen-4.13.1-testing.orig/tools/libxc/xc_sr_restore_x86_pv.c +++ xen-4.13.1-testing/tools/libxc/xc_sr_restore_x86_pv.c @@ -960,6 +960,75 @@ static void x86_pv_set_gfn(struct xc_sr_ } /* + * Given a set of pfns, obtain memory from Xen to fill the physmap for the + * unpopulated subset. If types is NULL, no page type checking is performed + * and all unpopulated pfns are populated. + */ +static int x86_pv_populate_pfns(struct xc_sr_context *ctx, unsigned count, + const xen_pfn_t *original_pfns, + const uint32_t *types) +{ + xc_interface *xch = ctx->xch; + xen_pfn_t *mfns = malloc(count * sizeof(*mfns)), + *pfns = malloc(count * sizeof(*pfns)); + unsigned i, nr_pfns = 0; + int rc = -1; + + if ( !mfns || !pfns ) + { + ERROR("Failed to allocate %zu bytes for populating the physmap", + 2 * count * sizeof(*mfns)); + goto err; + } + + for ( i = 0; i < count; ++i ) + { + if ( (!types || (types && + (types[i] != XEN_DOMCTL_PFINFO_XTAB && + types[i] != XEN_DOMCTL_PFINFO_BROKEN))) && + !pfn_is_populated(ctx, original_pfns[i]) ) + { + rc = pfn_set_populated(ctx, original_pfns[i]); + if ( rc ) + goto err; + pfns[nr_pfns] = mfns[nr_pfns] = original_pfns[i]; + ++nr_pfns; + } + } + + if ( nr_pfns ) + { + rc = xc_domain_populate_physmap_exact( + xch, ctx->domid, nr_pfns, 0, 0, mfns); + if ( rc ) + { + PERROR("Failed to populate physmap"); + goto err; + } + + for ( i = 0; i < nr_pfns; ++i ) + { + if ( mfns[i] == INVALID_MFN ) + { + ERROR("Populate physmap failed for pfn %u", i); + rc = -1; + goto err; + } + + ctx->restore.ops.set_gfn(ctx, pfns[i], mfns[i]); + } + } + + rc = 0; + + err: + free(pfns); + free(mfns); + + return rc; +} + +/* * restore_ops function. Convert pfns back to mfns in pagetables. Possibly * needs to populate new frames if a PTE is found referring to a frame which * hasn't yet been seen from PAGE_DATA records. @@ -1003,7 +1072,7 @@ static int x86_pv_localise_page(struct x } } - if ( to_populate && populate_pfns(ctx, to_populate, pfns, NULL) ) + if ( to_populate && x86_pv_populate_pfns(ctx, to_populate, pfns, NULL) ) return -1; for ( i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); ++i ) @@ -1183,6 +1252,7 @@ struct xc_sr_restore_ops restore_ops_x86 .set_gfn = x86_pv_set_gfn, .localise_page = x86_pv_localise_page, .setup = x86_pv_setup, + .populate_pfns = x86_pv_populate_pfns, .process_record = x86_pv_process_record, .stream_complete = x86_pv_stream_complete, .cleanup = x86_pv_cleanup,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor