Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1645640 > unrolled thread
| Started by | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| First post | 2017-05-19 16:20 +0200 |
| Last post | 2017-05-19 16:20 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-19 16:20 +0200
[PATCH v3 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls Vitaly Kuznetsov <vkuznets@redhat.com> - 2017-05-19 16:20 +0200
| From | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| Date | 2017-05-19 16:20 +0200 |
| Subject | [PATCH v3 00/10] Hyper-V: praravirtualized remote TLB flushing and hypercall improvements |
| Message-ID | <tIQV3-3mw-3@gated-at.bofh.it> |
Changes since v2: - Rebased to the latest char-misc-next tree. - Added Acked-By and Tested-By tags. Original descriptions: Hyper-V supports hypercalls for doing local and remote TLB flushing and gives its guests hints when using hypercall is preferred. While doing hypercalls for local TLB flushes is probably not practical (and is not being suggested by modern Hyper-V versions) remote TLB flush with a hypercall brings significant improvement. To test the series I wrote a special 'TLB trasher': on a 16 vCPU guest I was creating 32 threads which were doing 100000 mmap/munmaps each on some big file. Here are the results: Before: # time ./pthread_mmap ./randfile real 3m44.994s user 0m3.829s sys 3m36.323s After: # time ./pthread_mmap ./randfile real 2m57.145s user 0m3.797s sys 2m34.812s This series brings a number of small improvements along the way: fast hypercall implementation and using it for event signaling, rep hypercalls implementation, hyperv tracing subsystem (which only traces the newly added remote TLB flush for now). Vitaly Kuznetsov (10): x86/hyper-v: include hyperv/ only when CONFIG_HYPERV is set x86/hyper-v: stash the max number of virtual/logical processor x86/hyper-v: make hv_do_hypercall() inline x86/hyper-v: fast hypercall implementation hyper-v: use fast hypercall for HVCALL_SIGNAL_EVENT x86/hyper-v: implement rep hypercalls hyper-v: globalize vp_index x86/hyper-v: use hypercall for remote TLB flush x86/hyper-v: support extended CPU ranges for TLB flush hypercalls tracing/hyper-v: trace hyperv_mmu_flush_tlb_others() MAINTAINERS | 1 + arch/x86/Kbuild | 4 +- arch/x86/hyperv/Makefile | 2 +- arch/x86/hyperv/hv_init.c | 90 ++++++------ arch/x86/hyperv/mmu.c | 270 ++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mshyperv.h | 149 +++++++++++++++++++- arch/x86/include/asm/trace/hyperv.h | 34 +++++ arch/x86/include/uapi/asm/hyperv.h | 36 +++++ arch/x86/kernel/cpu/mshyperv.c | 14 +- drivers/hv/channel_mgmt.c | 22 ++- drivers/hv/connection.c | 8 +- drivers/hv/hv.c | 9 -- drivers/hv/hyperv_vmbus.h | 11 -- drivers/hv/vmbus_drv.c | 17 --- drivers/pci/host/pci-hyperv.c | 4 +- include/linux/hyperv.h | 21 ++- 16 files changed, 568 insertions(+), 124 deletions(-) create mode 100644 arch/x86/hyperv/mmu.c create mode 100644 arch/x86/include/asm/trace/hyperv.h -- 2.9.3
[toc] | [next] | [standalone]
| From | Vitaly Kuznetsov <vkuznets@redhat.com> |
|---|---|
| Date | 2017-05-19 16:20 +0200 |
| Subject | [PATCH v3 09/10] x86/hyper-v: support extended CPU ranges for TLB flush hypercalls |
| Message-ID | <tIQV5-3mw-43@gated-at.bofh.it> |
| In reply to | #1645640 |
Hyper-V hosts may support more than 64 vCPUs, we need to use
HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this
case.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Acked-by: K. Y. Srinivasan <kys@microsoft.com>
Tested-by: Simon Xiao <sixiao@microsoft.com>
Tested-by: Srikanth Myakam <v-srm@microsoft.com>
---
arch/x86/hyperv/mmu.c | 149 ++++++++++++++++++++++++++++++++++++-
arch/x86/include/uapi/asm/hyperv.h | 10 +++
2 files changed, 157 insertions(+), 2 deletions(-)
diff --git a/arch/x86/hyperv/mmu.c b/arch/x86/hyperv/mmu.c
index e3ab9b9..c9cecb3 100644
--- a/arch/x86/hyperv/mmu.c
+++ b/arch/x86/hyperv/mmu.c
@@ -15,8 +15,57 @@ struct hv_flush_pcpu {
__u64 gva_list[];
};
+/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
+struct hv_flush_pcpu_ex {
+ __u64 address_space;
+ __u64 flags;
+ struct {
+ __u64 format;
+ __u64 valid_bank_mask;
+ __u64 bank_contents[];
+ } hv_vp_set;
+ __u64 gva_list[];
+};
+
static struct hv_flush_pcpu __percpu *pcpu_flush;
+static struct hv_flush_pcpu_ex __percpu *pcpu_flush_ex;
+
+static inline int cpumask_to_vp_set(struct hv_flush_pcpu_ex *flush,
+ const struct cpumask *cpus)
+{
+ int cur_bank, cpu, vcpu, nr_bank = 0;
+ bool has_cpus;
+
+ /*
+ * We can't be sure that translated vcpu numbers will always be
+ * in ascending order, so iterate over all possible banks and
+ * check all vcpus in it instead.
+ */
+ for (cur_bank = 0; cur_bank < ms_hyperv.max_vp_index/64; cur_bank++) {
+ has_cpus = false;
+ for_each_cpu(cpu, cpus) {
+ vcpu = hv_cpu_number_to_vp_number(cpu);
+ if (vcpu/64 != cur_bank)
+ continue;
+ if (!has_cpus) {
+ flush->hv_vp_set.valid_bank_mask |=
+ 1 << vcpu / 64;
+ flush->hv_vp_set.bank_contents[nr_bank] =
+ 1 << vcpu % 64;
+ has_cpus = true;
+ } else {
+ flush->hv_vp_set.bank_contents[nr_bank] |=
+ 1 << vcpu % 64;
+ }
+ }
+ if (has_cpus)
+ nr_bank++;
+ }
+
+ return nr_bank;
+}
+
static void hyperv_flush_tlb_others(const struct cpumask *cpus,
struct mm_struct *mm, unsigned long start,
unsigned long end)
@@ -102,16 +151,112 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,
native_flush_tlb_others(cpus, mm, start, end);
}
+static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,
+ struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ struct hv_flush_pcpu_ex *flush;
+ unsigned long cur, flags;
+ u64 status = -1ULL;
+ int nr_bank = 0, max_gvas, gva_n;
+
+ if (!pcpu_flush_ex || !hv_hypercall_pg)
+ goto do_native;
+
+ if (cpumask_empty(cpus))
+ return;
+
+ local_irq_save(flags);
+
+ flush = this_cpu_ptr(pcpu_flush_ex);
+
+ if (mm) {
+ flush->address_space = virt_to_phys(mm->pgd);
+ flush->flags = 0;
+ } else {
+ flush->address_space = 0;
+ flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
+ }
+
+ flush->hv_vp_set.valid_bank_mask = 0;
+
+ if (cpumask_equal(cpus, cpu_present_mask)) {
+ flush->hv_vp_set.format = HV_GENERIC_SET_ALL;
+ flush->flags |= HV_FLUSH_ALL_PROCESSORS;
+ } else {
+ flush->hv_vp_set.format = HV_GENERIC_SET_SPARCE_4K;
+ nr_bank = cpumask_to_vp_set(flush, cpus);
+ }
+
+ /*
+ * We can flush not more than max_gvas with one hypercall. Flush the
+ * whole address space if we were asked to do more.
+ */
+ max_gvas = (PAGE_SIZE - sizeof(*flush) - nr_bank*8) / 8;
+
+ if (end == TLB_FLUSH_ALL ||
+ (end && ((end - start)/(PAGE_SIZE*PAGE_SIZE)) > max_gvas)) {
+ if (end == TLB_FLUSH_ALL)
+ flush->flags |= HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY;
+
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
+ 0, nr_bank + 2, flush, NULL);
+ } else {
+ cur = start;
+ gva_n = nr_bank;
+ do {
+ flush->gva_list[gva_n] = cur & PAGE_MASK;
+ /*
+ * Lower 12 bits encode the number of additional
+ * pages to flush (in addition to the 'cur' page).
+ */
+ if (end >= cur + PAGE_SIZE * PAGE_SIZE)
+ flush->gva_list[gva_n] |= ~PAGE_MASK;
+ else if (end > cur)
+ flush->gva_list[gva_n] |=
+ (end - cur - 1) >> PAGE_SHIFT;
+
+ cur += PAGE_SIZE * PAGE_SIZE;
+ ++gva_n;
+
+ } while (cur < end);
+
+ status = hv_do_rep_hypercall(
+ HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX,
+ gva_n, nr_bank + 2, flush, NULL);
+ }
+
+ local_irq_restore(flags);
+
+ if (!(status & 0xffff))
+ return;
+do_native:
+ native_flush_tlb_others(cpus, mm, start, end);
+}
+
void hyperv_setup_mmu_ops(void)
{
- if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED) {
+ if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+ return;
+
+ if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED)) {
pr_info("Hyper-V: Using hypercall for remote TLB flush\n");
pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others;
+ } else {
+ pr_info("Hyper-V: Using ext hypercall for remote TLB flush\n");
+ pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others_ex;
}
}
void hyper_alloc_mmu(void)
{
- if (ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED)
+ if (!(ms_hyperv.hints & HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED))
+ return;
+
+ if (!(ms_hyperv.hints & HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED))
pcpu_flush = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
+ else
+ pcpu_flush_ex = __alloc_percpu(PAGE_SIZE, PAGE_SIZE);
}
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 3d44036..c697e20 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -152,6 +152,9 @@
*/
#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9)
+/* Recommend using the newer ExProcessorMasks interface */
+#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11)
+
/*
* Crash notification flag.
*/
@@ -242,6 +245,8 @@
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002
#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003
#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013
+#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014
#define HVCALL_POST_MESSAGE 0x005c
#define HVCALL_SIGNAL_EVENT 0x005d
@@ -263,6 +268,11 @@
#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY 0x00000004
#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT 0x00000008
+enum HV_GENERIC_SET_FORMAT {
+ HV_GENERIC_SET_SPARCE_4K,
+ HV_GENERIC_SET_ALL,
+};
+
/* Hypercall interface */
union hv_hypercall_input {
u64 as_uint64;
--
2.9.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web