aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2015-03-11 10:49:57 -0400
committerDavid Vrabel <david.vrabel@citrix.com>2015-03-16 10:49:15 -0400
commit4e8c0c8c4bf3a5b5c98046e146ab3884bf7a7d0e (patch)
treee2da5980fd405c7109a342b13f0a2a1214f94b61 /arch/x86/xen
parent628c28eefd6f2cef03b212081b466ae43fd093a3 (diff)
xen/privcmd: improve performance of MMAPBATCH_V2
Make the IOCTL_PRIVCMD_MMAPBATCH_V2 (and older V1 version) map multiple frames at a time rather than one at a time, despite the pages being non-consecutive GFNs. xen_remap_foreign_mfn_array() is added which maps an array of GFNs (instead of a consecutive range of GFNs). Since per-frame errors are returned in an array, privcmd must set the MMAPBATCH_V1 error bits as part of the "report errors" phase, after all the frames are mapped. Migrate times are significantly improved (when using a PV toolstack domain). For example, for an idle 12 GiB PV guest: Before After real 0m38.179s 0m26.868s user 0m15.096s 0m13.652s sys 0m28.988s 0m18.732s Signed-off-by: David Vrabel <david.vrabel@citrix.com> Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/mmu.c101
1 files changed, 82 insertions, 19 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 3d536a56ddf1..29b3be230ede 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2439,7 +2439,8 @@ void __init xen_hvm_init_mmu_ops(void)
2439#define REMAP_BATCH_SIZE 16 2439#define REMAP_BATCH_SIZE 16
2440 2440
2441struct remap_data { 2441struct remap_data {
2442 unsigned long mfn; 2442 xen_pfn_t *mfn;
2443 bool contiguous;
2443 pgprot_t prot; 2444 pgprot_t prot;
2444 struct mmu_update *mmu_update; 2445 struct mmu_update *mmu_update;
2445}; 2446};
@@ -2448,7 +2449,14 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
2448 unsigned long addr, void *data) 2449 unsigned long addr, void *data)
2449{ 2450{
2450 struct remap_data *rmd = data; 2451 struct remap_data *rmd = data;
2451 pte_t pte = pte_mkspecial(mfn_pte(rmd->mfn++, rmd->prot)); 2452 pte_t pte = pte_mkspecial(mfn_pte(*rmd->mfn, rmd->prot));
2453
2454 /* If we have a contigious range, just update the mfn itself,
2455 else update pointer to be "next mfn". */
2456 if (rmd->contiguous)
2457 (*rmd->mfn)++;
2458 else
2459 rmd->mfn++;
2452 2460
2453 rmd->mmu_update->ptr = virt_to_machine(ptep).maddr; 2461 rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
2454 rmd->mmu_update->val = pte_val_ma(pte); 2462 rmd->mmu_update->val = pte_val_ma(pte);
@@ -2457,26 +2465,26 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
2457 return 0; 2465 return 0;
2458} 2466}
2459 2467
2460int xen_remap_domain_mfn_range(struct vm_area_struct *vma, 2468static int do_remap_mfn(struct vm_area_struct *vma,
2461 unsigned long addr, 2469 unsigned long addr,
2462 xen_pfn_t mfn, int nr, 2470 xen_pfn_t *mfn, int nr,
2463 pgprot_t prot, unsigned domid, 2471 int *err_ptr, pgprot_t prot,
2464 struct page **pages) 2472 unsigned domid,
2465 2473 struct page **pages)
2466{ 2474{
2475 int err = 0;
2467 struct remap_data rmd; 2476 struct remap_data rmd;
2468 struct mmu_update mmu_update[REMAP_BATCH_SIZE]; 2477 struct mmu_update mmu_update[REMAP_BATCH_SIZE];
2469 int batch;
2470 unsigned long range; 2478 unsigned long range;
2471 int err = 0; 2479 int mapped = 0;
2472 2480
2473 BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); 2481 BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
2474 2482
2475 if (xen_feature(XENFEAT_auto_translated_physmap)) { 2483 if (xen_feature(XENFEAT_auto_translated_physmap)) {
2476#ifdef CONFIG_XEN_PVH 2484#ifdef CONFIG_XEN_PVH
2477 /* We need to update the local page tables and the xen HAP */ 2485 /* We need to update the local page tables and the xen HAP */
2478 return xen_xlate_remap_gfn_range(vma, addr, mfn, nr, prot, 2486 return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr,
2479 domid, pages); 2487 prot, domid, pages);
2480#else 2488#else
2481 return -EINVAL; 2489 return -EINVAL;
2482#endif 2490#endif
@@ -2484,9 +2492,15 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
2484 2492
2485 rmd.mfn = mfn; 2493 rmd.mfn = mfn;
2486 rmd.prot = prot; 2494 rmd.prot = prot;
2495 /* We use the err_ptr to indicate if there we are doing a contigious
2496 * mapping or a discontigious mapping. */
2497 rmd.contiguous = !err_ptr;
2487 2498
2488 while (nr) { 2499 while (nr) {
2489 batch = min(REMAP_BATCH_SIZE, nr); 2500 int index = 0;
2501 int done = 0;
2502 int batch = min(REMAP_BATCH_SIZE, nr);
2503 int batch_left = batch;
2490 range = (unsigned long)batch << PAGE_SHIFT; 2504 range = (unsigned long)batch << PAGE_SHIFT;
2491 2505
2492 rmd.mmu_update = mmu_update; 2506 rmd.mmu_update = mmu_update;
@@ -2495,23 +2509,72 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
2495 if (err) 2509 if (err)
2496 goto out; 2510 goto out;
2497 2511
2498 err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid); 2512 /* We record the error for each page that gives an error, but
2499 if (err < 0) 2513 * continue mapping until the whole set is done */
2500 goto out; 2514 do {
2515 int i;
2516
2517 err = HYPERVISOR_mmu_update(&mmu_update[index],
2518 batch_left, &done, domid);
2519
2520 /*
2521 * @err_ptr may be the same buffer as @mfn, so
2522 * only clear it after each chunk of @mfn is
2523 * used.
2524 */
2525 if (err_ptr) {
2526 for (i = index; i < index + done; i++)
2527 err_ptr[i] = 0;
2528 }
2529 if (err < 0) {
2530 if (!err_ptr)
2531 goto out;
2532 err_ptr[i] = err;
2533 done++; /* Skip failed frame. */
2534 } else
2535 mapped += done;
2536 batch_left -= done;
2537 index += done;
2538 } while (batch_left);
2501 2539
2502 nr -= batch; 2540 nr -= batch;
2503 addr += range; 2541 addr += range;
2542 if (err_ptr)
2543 err_ptr += batch;
2504 } 2544 }
2505
2506 err = 0;
2507out: 2545out:
2508 2546
2509 xen_flush_tlb_all(); 2547 xen_flush_tlb_all();
2510 2548
2511 return err; 2549 return err < 0 ? err : mapped;
2550}
2551
2552int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
2553 unsigned long addr,
2554 xen_pfn_t mfn, int nr,
2555 pgprot_t prot, unsigned domid,
2556 struct page **pages)
2557{
2558 return do_remap_mfn(vma, addr, &mfn, nr, NULL, prot, domid, pages);
2512} 2559}
2513EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); 2560EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
2514 2561
2562int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
2563 unsigned long addr,
2564 xen_pfn_t *mfn, int nr,
2565 int *err_ptr, pgprot_t prot,
2566 unsigned domid, struct page **pages)
2567{
2568 /* We BUG_ON because it's a programmer error to pass a NULL err_ptr,
2569 * and the consequences later is quite hard to detect what the actual
2570 * cause of "wrong memory was mapped in".
2571 */
2572 BUG_ON(err_ptr == NULL);
2573 return do_remap_mfn(vma, addr, mfn, nr, err_ptr, prot, domid, pages);
2574}
2575EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array);
2576
2577
2515/* Returns: 0 success */ 2578/* Returns: 0 success */
2516int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, 2579int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
2517 int numpgs, struct page **pages) 2580 int numpgs, struct page **pages)