diff options
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_64.S | 3 | ||||
| -rw-r--r-- | arch/x86/xen/enlighten.c | 20 | ||||
| -rw-r--r-- | drivers/xen/Makefile | 2 | ||||
| -rw-r--r-- | drivers/xen/preempt.c | 44 | ||||
| -rw-r--r-- | drivers/xen/privcmd.c | 2 | ||||
| -rw-r--r-- | drivers/xen/xen-scsiback.c | 14 | ||||
| -rw-r--r-- | include/xen/xen-ops.h | 26 |
8 files changed, 104 insertions, 10 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 000d4199b03e..31e2d5bf3e38 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S | |||
| @@ -982,6 +982,9 @@ ENTRY(xen_hypervisor_callback) | |||
| 982 | ENTRY(xen_do_upcall) | 982 | ENTRY(xen_do_upcall) |
| 983 | 1: mov %esp, %eax | 983 | 1: mov %esp, %eax |
| 984 | call xen_evtchn_do_upcall | 984 | call xen_evtchn_do_upcall |
| 985 | #ifndef CONFIG_PREEMPT | ||
| 986 | call xen_maybe_preempt_hcall | ||
| 987 | #endif | ||
| 985 | jmp ret_from_intr | 988 | jmp ret_from_intr |
| 986 | CFI_ENDPROC | 989 | CFI_ENDPROC |
| 987 | ENDPROC(xen_hypervisor_callback) | 990 | ENDPROC(xen_hypervisor_callback) |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index db13655c3a2a..10074ad9ebf8 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
| @@ -1208,6 +1208,9 @@ ENTRY(xen_do_hypervisor_callback) # do_hypervisor_callback(struct *pt_regs) | |||
| 1208 | popq %rsp | 1208 | popq %rsp |
| 1209 | CFI_DEF_CFA_REGISTER rsp | 1209 | CFI_DEF_CFA_REGISTER rsp |
| 1210 | decl PER_CPU_VAR(irq_count) | 1210 | decl PER_CPU_VAR(irq_count) |
| 1211 | #ifndef CONFIG_PREEMPT | ||
| 1212 | call xen_maybe_preempt_hcall | ||
| 1213 | #endif | ||
| 1211 | jmp error_exit | 1214 | jmp error_exit |
| 1212 | CFI_ENDPROC | 1215 | CFI_ENDPROC |
| 1213 | END(xen_do_hypervisor_callback) | 1216 | END(xen_do_hypervisor_callback) |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bd8b8459c3d0..5240f563076d 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -1070,6 +1070,23 @@ static inline void xen_write_cr8(unsigned long val) | |||
| 1070 | BUG_ON(val); | 1070 | BUG_ON(val); |
| 1071 | } | 1071 | } |
| 1072 | #endif | 1072 | #endif |
| 1073 | |||
| 1074 | static u64 xen_read_msr_safe(unsigned int msr, int *err) | ||
| 1075 | { | ||
| 1076 | u64 val; | ||
| 1077 | |||
| 1078 | val = native_read_msr_safe(msr, err); | ||
| 1079 | switch (msr) { | ||
| 1080 | case MSR_IA32_APICBASE: | ||
| 1081 | #ifdef CONFIG_X86_X2APIC | ||
| 1082 | if (!(cpuid_ecx(1) & (1 << (X86_FEATURE_X2APIC & 31)))) | ||
| 1083 | #endif | ||
| 1084 | val &= ~X2APIC_ENABLE; | ||
| 1085 | break; | ||
| 1086 | } | ||
| 1087 | return val; | ||
| 1088 | } | ||
| 1089 | |||
| 1073 | static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) | 1090 | static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) |
| 1074 | { | 1091 | { |
| 1075 | int ret; | 1092 | int ret; |
| @@ -1240,7 +1257,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { | |||
| 1240 | 1257 | ||
| 1241 | .wbinvd = native_wbinvd, | 1258 | .wbinvd = native_wbinvd, |
| 1242 | 1259 | ||
| 1243 | .read_msr = native_read_msr_safe, | 1260 | .read_msr = xen_read_msr_safe, |
| 1244 | .write_msr = xen_write_msr_safe, | 1261 | .write_msr = xen_write_msr_safe, |
| 1245 | 1262 | ||
| 1246 | .read_tsc = native_read_tsc, | 1263 | .read_tsc = native_read_tsc, |
| @@ -1741,6 +1758,7 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
| 1741 | #ifdef CONFIG_X86_32 | 1758 | #ifdef CONFIG_X86_32 |
| 1742 | i386_start_kernel(); | 1759 | i386_start_kernel(); |
| 1743 | #else | 1760 | #else |
| 1761 | cr4_init_shadow(); /* 32b kernel does this in i386_start_kernel() */ | ||
| 1744 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); | 1762 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); |
| 1745 | #endif | 1763 | #endif |
| 1746 | } | 1764 | } |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 2140398a2a8c..2ccd3592d41f 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
| @@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),) | |||
| 2 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o | 2 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o |
| 3 | endif | 3 | endif |
| 4 | obj-$(CONFIG_X86) += fallback.o | 4 | obj-$(CONFIG_X86) += fallback.o |
| 5 | obj-y += grant-table.o features.o balloon.o manage.o | 5 | obj-y += grant-table.o features.o balloon.o manage.o preempt.o |
| 6 | obj-y += events/ | 6 | obj-y += events/ |
| 7 | obj-y += xenbus/ | 7 | obj-y += xenbus/ |
| 8 | 8 | ||
diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c new file mode 100644 index 000000000000..a1800c150839 --- /dev/null +++ b/drivers/xen/preempt.c | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Preemptible hypercalls | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Citrix Systems R&D ltd. | ||
| 5 | * | ||
| 6 | * This source code is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation; either version 2 of the | ||
| 9 | * License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/sched.h> | ||
| 13 | #include <xen/xen-ops.h> | ||
| 14 | |||
| 15 | #ifndef CONFIG_PREEMPT | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Some hypercalls issued by the toolstack can take many 10s of | ||
| 19 | * seconds. Allow tasks running hypercalls via the privcmd driver to | ||
| 20 | * be voluntarily preempted even if full kernel preemption is | ||
| 21 | * disabled. | ||
| 22 | * | ||
| 23 | * Such preemptible hypercalls are bracketed by | ||
| 24 | * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end() | ||
| 25 | * calls. | ||
| 26 | */ | ||
| 27 | |||
| 28 | DEFINE_PER_CPU(bool, xen_in_preemptible_hcall); | ||
| 29 | EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall); | ||
| 30 | |||
| 31 | asmlinkage __visible void xen_maybe_preempt_hcall(void) | ||
| 32 | { | ||
| 33 | if (unlikely(__this_cpu_read(xen_in_preemptible_hcall) | ||
| 34 | && should_resched())) { | ||
| 35 | /* | ||
| 36 | * Clear flag as we may be rescheduled on a different | ||
| 37 | * cpu. | ||
| 38 | */ | ||
| 39 | __this_cpu_write(xen_in_preemptible_hcall, false); | ||
| 40 | _cond_resched(); | ||
| 41 | __this_cpu_write(xen_in_preemptible_hcall, true); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | #endif /* CONFIG_PREEMPT */ | ||
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 569a13b9e856..59ac71c4a043 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
| @@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata) | |||
| 56 | if (copy_from_user(&hypercall, udata, sizeof(hypercall))) | 56 | if (copy_from_user(&hypercall, udata, sizeof(hypercall))) |
| 57 | return -EFAULT; | 57 | return -EFAULT; |
| 58 | 58 | ||
| 59 | xen_preemptible_hcall_begin(); | ||
| 59 | ret = privcmd_call(hypercall.op, | 60 | ret = privcmd_call(hypercall.op, |
| 60 | hypercall.arg[0], hypercall.arg[1], | 61 | hypercall.arg[0], hypercall.arg[1], |
| 61 | hypercall.arg[2], hypercall.arg[3], | 62 | hypercall.arg[2], hypercall.arg[3], |
| 62 | hypercall.arg[4]); | 63 | hypercall.arg[4]); |
| 64 | xen_preemptible_hcall_end(); | ||
| 63 | 65 | ||
| 64 | return ret; | 66 | return ret; |
| 65 | } | 67 | } |
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 61653a03a8f5..9faca6a60bb0 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c | |||
| @@ -709,12 +709,11 @@ static int prepare_pending_reqs(struct vscsibk_info *info, | |||
| 709 | static int scsiback_do_cmd_fn(struct vscsibk_info *info) | 709 | static int scsiback_do_cmd_fn(struct vscsibk_info *info) |
| 710 | { | 710 | { |
| 711 | struct vscsiif_back_ring *ring = &info->ring; | 711 | struct vscsiif_back_ring *ring = &info->ring; |
| 712 | struct vscsiif_request *ring_req; | 712 | struct vscsiif_request ring_req; |
| 713 | struct vscsibk_pend *pending_req; | 713 | struct vscsibk_pend *pending_req; |
| 714 | RING_IDX rc, rp; | 714 | RING_IDX rc, rp; |
| 715 | int err, more_to_do; | 715 | int err, more_to_do; |
| 716 | uint32_t result; | 716 | uint32_t result; |
| 717 | uint8_t act; | ||
| 718 | 717 | ||
| 719 | rc = ring->req_cons; | 718 | rc = ring->req_cons; |
| 720 | rp = ring->sring->req_prod; | 719 | rp = ring->sring->req_prod; |
| @@ -735,11 +734,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
| 735 | if (!pending_req) | 734 | if (!pending_req) |
| 736 | return 1; | 735 | return 1; |
| 737 | 736 | ||
| 738 | ring_req = RING_GET_REQUEST(ring, rc); | 737 | ring_req = *RING_GET_REQUEST(ring, rc); |
| 739 | ring->req_cons = ++rc; | 738 | ring->req_cons = ++rc; |
| 740 | 739 | ||
| 741 | act = ring_req->act; | 740 | err = prepare_pending_reqs(info, &ring_req, pending_req); |
| 742 | err = prepare_pending_reqs(info, ring_req, pending_req); | ||
| 743 | if (err) { | 741 | if (err) { |
| 744 | switch (err) { | 742 | switch (err) { |
| 745 | case -ENODEV: | 743 | case -ENODEV: |
| @@ -755,9 +753,9 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
| 755 | return 1; | 753 | return 1; |
| 756 | } | 754 | } |
| 757 | 755 | ||
| 758 | switch (act) { | 756 | switch (ring_req.act) { |
| 759 | case VSCSIIF_ACT_SCSI_CDB: | 757 | case VSCSIIF_ACT_SCSI_CDB: |
| 760 | if (scsiback_gnttab_data_map(ring_req, pending_req)) { | 758 | if (scsiback_gnttab_data_map(&ring_req, pending_req)) { |
| 761 | scsiback_fast_flush_area(pending_req); | 759 | scsiback_fast_flush_area(pending_req); |
| 762 | scsiback_do_resp_with_sense(NULL, | 760 | scsiback_do_resp_with_sense(NULL, |
| 763 | DRIVER_ERROR << 24, 0, pending_req); | 761 | DRIVER_ERROR << 24, 0, pending_req); |
| @@ -768,7 +766,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
| 768 | break; | 766 | break; |
| 769 | case VSCSIIF_ACT_SCSI_ABORT: | 767 | case VSCSIIF_ACT_SCSI_ABORT: |
| 770 | scsiback_device_action(pending_req, TMR_ABORT_TASK, | 768 | scsiback_device_action(pending_req, TMR_ABORT_TASK, |
| 771 | ring_req->ref_rqid); | 769 | ring_req.ref_rqid); |
| 772 | break; | 770 | break; |
| 773 | case VSCSIIF_ACT_SCSI_RESET: | 771 | case VSCSIIF_ACT_SCSI_RESET: |
| 774 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); | 772 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 7491ee5d8164..83338210ee04 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
| @@ -46,4 +46,30 @@ static inline efi_system_table_t __init *xen_efi_probe(void) | |||
| 46 | } | 46 | } |
| 47 | #endif | 47 | #endif |
| 48 | 48 | ||
| 49 | #ifdef CONFIG_PREEMPT | ||
| 50 | |||
| 51 | static inline void xen_preemptible_hcall_begin(void) | ||
| 52 | { | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline void xen_preemptible_hcall_end(void) | ||
| 56 | { | ||
| 57 | } | ||
| 58 | |||
| 59 | #else | ||
| 60 | |||
| 61 | DECLARE_PER_CPU(bool, xen_in_preemptible_hcall); | ||
| 62 | |||
| 63 | static inline void xen_preemptible_hcall_begin(void) | ||
| 64 | { | ||
| 65 | __this_cpu_write(xen_in_preemptible_hcall, true); | ||
| 66 | } | ||
| 67 | |||
| 68 | static inline void xen_preemptible_hcall_end(void) | ||
| 69 | { | ||
| 70 | __this_cpu_write(xen_in_preemptible_hcall, false); | ||
| 71 | } | ||
| 72 | |||
| 73 | #endif /* CONFIG_PREEMPT */ | ||
| 74 | |||
| 49 | #endif /* INCLUDE_XEN_OPS_H */ | 75 | #endif /* INCLUDE_XEN_OPS_H */ |
