[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] linux-2.6.18/x86: use dynamically adjusted upper bound for contiguous regions
After years of not causing problems, the 2Mb (order 9) limit on contiguous regions' size was recently found to prevent booting of certain systems - at least the FC variant of the MPT driver can (possibly only for out-of-tree and/or post-2.6.18 versions) require allocation of a buffer quite a bit larger than 2Mb. Rather than increasing the limit on the order to 10, make the whole logic dynamic - start out with a static order and respective argument buffers large enough to allow initialization up to the point where core_initcall()-s get processed, and from then on dynamically allocate (and re-size) argument buffers on demand. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx> --- a/arch/i386/mm/hypervisor.c +++ b/arch/i386/mm/hypervisor.c @@ -191,17 +191,71 @@ void xen_set_ldt(const void *ptr, unsign } /* Protected by balloon_lock. */ -#define MAX_CONTIG_ORDER 9 /* 2MB */ -static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER]; -static unsigned long limited_frames[1<<MAX_CONTIG_ORDER]; -static multicall_entry_t cr_mcl[1<<MAX_CONTIG_ORDER]; +#define INIT_CONTIG_ORDER 6 /* 256kB */ +static unsigned int __read_mostly max_contig_order = INIT_CONTIG_ORDER; +static unsigned long __initdata init_df[1U << INIT_CONTIG_ORDER]; +static unsigned long *__read_mostly discontig_frames = init_df; +static multicall_entry_t __initdata init_mc[1U << INIT_CONTIG_ORDER]; +static multicall_entry_t *__read_mostly cr_mcl = init_mc; + +static int __init init_contig_order(void) +{ + discontig_frames = vmalloc((sizeof(*discontig_frames) + + sizeof(*cr_mcl)) << INIT_CONTIG_ORDER); + BUG_ON(!discontig_frames); + + cr_mcl = (void *)(discontig_frames + (1U << INIT_CONTIG_ORDER)); + + return 0; +} +core_initcall(init_contig_order); + +static int check_contig_order(unsigned int order) +{ +#ifdef CONFIG_64BIT + if (unlikely(order >= 32)) +#else + if (unlikely(order > BITS_PER_LONG - fls(sizeof(*cr_mcl)))) +#endif + return -ENOMEM; + + if (unlikely(order > max_contig_order)) + { + unsigned long *df = __vmalloc((sizeof(*discontig_frames) + + sizeof(*cr_mcl)) << order, + GFP_ATOMIC, PAGE_KERNEL); + unsigned long flags; + + if (!df) { + vfree(df); + return -ENOMEM; + } + balloon_lock(flags); + if (order > max_contig_order) { + void *temp = discontig_frames; + + discontig_frames = df; + cr_mcl = (void *)(df + (1U << order)); + df = temp; + + wmb(); + max_contig_order = order; + } + balloon_unlock(flags); + vfree(df); + printk(KERN_INFO + "Adjusted maximum contiguous region order to %u\n", + order); + } + + return 0; +} /* Ensure multi-page extents are contiguous in machine memory. */ int xen_create_contiguous_region( unsigned long vstart, unsigned int order, unsigned int address_bits) { - unsigned long *in_frames = discontig_frames, out_frame; - unsigned long frame, flags; + unsigned long *in_frames, out_frame, frame, flags; unsigned int i; int rc, success; struct xen_memory_exchange exchange = { @@ -226,16 +280,19 @@ int xen_create_contiguous_region( if (xen_feature(XENFEAT_auto_translated_physmap)) return 0; - if (unlikely(order > MAX_CONTIG_ORDER)) - return -ENOMEM; + rc = check_contig_order(order); + if (unlikely(rc)) + return rc; - set_xen_guest_handle(exchange.in.extent_start, in_frames); set_xen_guest_handle(exchange.out.extent_start, &out_frame); scrub_pages((void *)vstart, 1 << order); balloon_lock(flags); + in_frames = discontig_frames; + set_xen_guest_handle(exchange.in.extent_start, in_frames); + /* 1. Zap current PTEs, remembering MFNs. */ for (i = 0; i < (1U<<order); i++) { in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i); @@ -294,8 +351,7 @@ EXPORT_SYMBOL_GPL(xen_create_contiguous_ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) { - unsigned long *out_frames = discontig_frames, in_frame; - unsigned long frame, flags; + unsigned long *out_frames, in_frame, frame, flags; unsigned int i; int rc, success; struct xen_memory_exchange exchange = { @@ -314,16 +370,18 @@ void xen_destroy_contiguous_region(unsig if (xen_feature(XENFEAT_auto_translated_physmap)) return; - if (unlikely(order > MAX_CONTIG_ORDER)) + if (unlikely(order > max_contig_order)) return; set_xen_guest_handle(exchange.in.extent_start, &in_frame); - set_xen_guest_handle(exchange.out.extent_start, out_frames); scrub_pages((void *)vstart, 1 << order); balloon_lock(flags); + out_frames = discontig_frames; + set_xen_guest_handle(exchange.out.extent_start, out_frames); + /* 1. Find start MFN of contiguous extent. */ in_frame = pfn_to_mfn(__pa(vstart) >> PAGE_SHIFT); @@ -384,7 +432,7 @@ EXPORT_SYMBOL_GPL(xen_destroy_contiguous static void undo_limit_pages(struct page *pages, unsigned int order) { BUG_ON(xen_feature(XENFEAT_auto_translated_physmap)); - BUG_ON(order > MAX_CONTIG_ORDER); + BUG_ON(order > max_contig_order); xen_limit_pages_to_max_mfn(pages, order, 0); ClearPageForeign(pages); __free_pages(pages, order); @@ -393,12 +451,11 @@ static void undo_limit_pages(struct page int xen_limit_pages_to_max_mfn( struct page *pages, unsigned int order, unsigned int address_bits) { - unsigned long flags, frame; - unsigned long *in_frames = discontig_frames, *out_frames = limited_frames; + unsigned long flags, frame, *limit_map, _limit_map; + unsigned long *in_frames, *out_frames; struct page *page; unsigned int i, n, nr_mcl; int rc, success; - DECLARE_BITMAP(limit_map, 1 << MAX_CONTIG_ORDER); struct xen_memory_exchange exchange = { .in = { @@ -415,23 +472,30 @@ int xen_limit_pages_to_max_mfn( if (xen_feature(XENFEAT_auto_translated_physmap)) return 0; - if (unlikely(order > MAX_CONTIG_ORDER)) - return -ENOMEM; + if (address_bits && address_bits < PAGE_SHIFT) + return -EINVAL; + + rc = check_contig_order(order + 1); + if (unlikely(rc)) + return rc; + + if (BITS_PER_LONG >> order) { + limit_map = kmalloc(BITS_TO_LONGS(1U << order) + * sizeof(*limit_map), GFP_ATOMIC); + if (unlikely(!limit_map)) + return -ENOMEM; + } else + limit_map = &_limit_map; - if (address_bits) { - if (address_bits < PAGE_SHIFT) - return -EINVAL; + if (address_bits) bitmap_zero(limit_map, 1U << order); - } else if (order) { + else if (order) { BUILD_BUG_ON(sizeof(pages->index) != sizeof(*limit_map)); for (i = 0; i < BITS_TO_LONGS(1U << order); ++i) limit_map[i] = pages[i + 1].index; } else __set_bit(0, limit_map); - set_xen_guest_handle(exchange.in.extent_start, in_frames); - set_xen_guest_handle(exchange.out.extent_start, out_frames); - /* 0. Scrub the pages. */ for (i = 0, n = 0; i < 1U<<order ; i++) { page = &pages[i]; @@ -451,14 +515,22 @@ int xen_limit_pages_to_max_mfn( } #endif } - if (bitmap_empty(limit_map, 1U << order)) + if (bitmap_empty(limit_map, 1U << order)) { + if (limit_map != &_limit_map) + kfree(limit_map); return 0; + } if (n) kmap_flush_unused(); balloon_lock(flags); + in_frames = discontig_frames; + set_xen_guest_handle(exchange.in.extent_start, in_frames); + out_frames = in_frames + (1U << order); + set_xen_guest_handle(exchange.out.extent_start, out_frames); + /* 1. Zap current PTEs (if any), remembering MFNs. */ for (i = 0, n = 0, nr_mcl = 0; i < (1U<<order); i++) { if(!test_bit(i, limit_map)) @@ -525,10 +597,7 @@ int xen_limit_pages_to_max_mfn( balloon_unlock(flags); - if (!success) - return -ENOMEM; - - if (address_bits) { + if (success && address_bits) { if (order) { BUILD_BUG_ON(sizeof(*limit_map) != sizeof(pages->index)); for (i = 0; i < BITS_TO_LONGS(1U << order); ++i) @@ -537,7 +606,10 @@ int xen_limit_pages_to_max_mfn( SetPageForeign(pages, undo_limit_pages); } - return 0; + if (limit_map != &_limit_map) + kfree(limit_map); + + return success ? 0 : -ENOMEM; } EXPORT_SYMBOL_GPL(xen_limit_pages_to_max_mfn); Attachment:
xen-x86-max-contig-order.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |