History

KVM: s390: migrate vcpu interrupt state

This patch adds support to migrate vcpu interrupts. Two new vcpu ioctls are added which get/set the complete status of pending interrupts in one go. The ioctls are marked as available with the new capability KVM_CAP_S390_IRQ_STATE. We can not use a ONEREG, as the number of pending local interrupts is not constant and depends on the number of CPUs. To retrieve the interrupt state we add an ioctl KVM_S390_GET_IRQ_STATE. Its input parameter is a pointer to a struct kvm_s390_irq_state which has a buffer and length. For all currently pending interrupts, we copy a struct kvm_s390_irq into the buffer and pass it to userspace. To store interrupt state into a buffer provided by userspace, we add an ioctl KVM_S390_SET_IRQ_STATE. It passes a struct kvm_s390_irq_state into the kernel and injects all interrupts contained in the buffer.

Jens Freimann committed 11 years ago

Commit 816c7661 parent 79e87a15 files · +252 −0Browse files

Unified · Split

5 files
  1. Documentation/virtual/kvm/api.txt +61 −0
  2. arch/s390/kvm/interrupt.c +140 −0
  3. arch/s390/kvm/kvm-s390.c +36 −0
  4. arch/s390/kvm/kvm-s390.h +4 −0
  5. include/uapi/linux/kvm.h +11 −0
Documentation/virtual/kvm/api.txt+61−0
@@ -2875,6 +2875,67 @@ KVM_S390_MCHK - machine check interrupt; parameters in .mchk · 2874 unmodified lines
28752875
28762876 Note that the vcpu ioctl is asynchronous to vcpu execution.
28772877
2878+4.94 KVM_S390_GET_IRQ_STATE
2879+
2880+Capability: KVM_CAP_S390_IRQ_STATE
2881+Architectures: s390
2882+Type: vcpu ioctl
2883+Parameters: struct kvm_s390_irq_state (out)
2884+Returns: >= number of bytes copied into buffer,
2885+ -EINVAL if buffer size is 0,
2886+ -ENOBUFS if buffer size is too small to fit all pending interrupts,
2887+ -EFAULT if the buffer address was invalid
2888+
2889+This ioctl allows userspace to retrieve the complete state of all currently
2890+pending interrupts in a single buffer. Use cases include migration
2891+and introspection. The parameter structure contains the address of a
2892+userspace buffer and its length:
2893+
2894+struct kvm_s390_irq_state {
2895+ __u64 buf;
2896+ __u32 flags;
2897+ __u32 len;
2898+ __u32 reserved[4];
2899+};
2900+
2901+Userspace passes in the above struct and for each pending interrupt a
2902+struct kvm_s390_irq is copied to the provided buffer.
2903+
2904+If -ENOBUFS is returned the buffer provided was too small and userspace
2905+may retry with a bigger buffer.
2906+
2907+4.95 KVM_S390_SET_IRQ_STATE
2908+
2909+Capability: KVM_CAP_S390_IRQ_STATE
2910+Architectures: s390
2911+Type: vcpu ioctl
2912+Parameters: struct kvm_s390_irq_state (in)
2913+Returns: 0 on success,
2914+ -EFAULT if the buffer address was invalid,
2915+ -EINVAL for an invalid buffer length (see below),
2916+ -EBUSY if there were already interrupts pending,
2917+ errors occurring when actually injecting the
2918+ interrupt. See KVM_S390_IRQ.
2919+
2920+This ioctl allows userspace to set the complete state of all cpu-local
2921+interrupts currently pending for the vcpu. It is intended for restoring
2922+interrupt state after a migration. The input parameter is a userspace buffer
2923+containing a struct kvm_s390_irq_state:
2924+
2925+struct kvm_s390_irq_state {
2926+ __u64 buf;
2927+ __u32 len;
2928+ __u32 pad;
2929+};
2930+
2931+The userspace memory referenced by buf contains a struct kvm_s390_irq
2932+for each interrupt to be injected into the guest.
2933+If one of the interrupts could not be injected for some reason the
2934+ioctl aborts.
2935+
2936+len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
2937+and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
2938+which is the maximum number of possibly pending cpu-local interrupts.
28782939
28792940 5. The kvm_run structure
28802941 ------------------------
arch/s390/kvm/interrupt.c+140−0
@@ -2123,3 +2123,143 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, · 2122 unmodified lines
21232123 {
21242124 return -EINVAL;
21252125 }
2126+
2127+int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len)
2128+{
2129+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
2130+ struct kvm_s390_irq *buf;
2131+ int r = 0;
2132+ int n;
2133+
2134+ buf = vmalloc(len);
2135+ if (!buf)
2136+ return -ENOMEM;
2137+
2138+ if (copy_from_user((void *) buf, irqstate, len)) {
2139+ r = -EFAULT;
2140+ goto out_free;
2141+ }
2142+
2143+ /*
2144+ * Don't allow setting the interrupt state
2145+ * when there are already interrupts pending
2146+ */
2147+ spin_lock(&li->lock);
2148+ if (li->pending_irqs) {
2149+ r = -EBUSY;
2150+ goto out_unlock;
2151+ }
2152+
2153+ for (n = 0; n < len / sizeof(*buf); n++) {
2154+ r = do_inject_vcpu(vcpu, &buf[n]);
2155+ if (r)
2156+ break;
2157+ }
2158+
2159+out_unlock:
2160+ spin_unlock(&li->lock);
2161+out_free:
2162+ vfree(buf);
2163+
2164+ return r;
2165+}
2166+
2167+static void store_local_irq(struct kvm_s390_local_interrupt *li,
2168+ struct kvm_s390_irq *irq,
2169+ unsigned long irq_type)
2170+{
2171+ switch (irq_type) {
2172+ case IRQ_PEND_MCHK_EX:
2173+ case IRQ_PEND_MCHK_REP:
2174+ irq->type = KVM_S390_MCHK;
2175+ irq->u.mchk = li->irq.mchk;
2176+ break;
2177+ case IRQ_PEND_PROG:
2178+ irq->type = KVM_S390_PROGRAM_INT;
2179+ irq->u.pgm = li->irq.pgm;
2180+ break;
2181+ case IRQ_PEND_PFAULT_INIT:
2182+ irq->type = KVM_S390_INT_PFAULT_INIT;
2183+ irq->u.ext = li->irq.ext;
2184+ break;
2185+ case IRQ_PEND_EXT_EXTERNAL:
2186+ irq->type = KVM_S390_INT_EXTERNAL_CALL;
2187+ irq->u.extcall = li->irq.extcall;
2188+ break;
2189+ case IRQ_PEND_EXT_CLOCK_COMP:
2190+ irq->type = KVM_S390_INT_CLOCK_COMP;
2191+ break;
2192+ case IRQ_PEND_EXT_CPU_TIMER:
2193+ irq->type = KVM_S390_INT_CPU_TIMER;
2194+ break;
2195+ case IRQ_PEND_SIGP_STOP:
2196+ irq->type = KVM_S390_SIGP_STOP;
2197+ irq->u.stop = li->irq.stop;
2198+ break;
2199+ case IRQ_PEND_RESTART:
2200+ irq->type = KVM_S390_RESTART;
2201+ break;
2202+ case IRQ_PEND_SET_PREFIX:
2203+ irq->type = KVM_S390_SIGP_SET_PREFIX;
2204+ irq->u.prefix = li->irq.prefix;
2205+ break;
2206+ }
2207+}
2208+
2209+int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
2210+{
2211+ uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
2212+ unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)];
2213+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
2214+ unsigned long pending_irqs;
2215+ struct kvm_s390_irq irq;
2216+ unsigned long irq_type;
2217+ int cpuaddr;
2218+ int n = 0;
2219+
2220+ spin_lock(&li->lock);
2221+ pending_irqs = li->pending_irqs;
2222+ memcpy(&sigp_emerg_pending, &li->sigp_emerg_pending,
2223+ sizeof(sigp_emerg_pending));
2224+ spin_unlock(&li->lock);
2225+
2226+ for_each_set_bit(irq_type, &pending_irqs, IRQ_PEND_COUNT) {
2227+ memset(&irq, 0, sizeof(irq));
2228+ if (irq_type == IRQ_PEND_EXT_EMERGENCY)
2229+ continue;
2230+ if (n + sizeof(irq) > len)
2231+ return -ENOBUFS;
2232+ store_local_irq(&vcpu->arch.local_int, &irq, irq_type);
2233+ if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2234+ return -EFAULT;
2235+ n += sizeof(irq);
2236+ }
2237+
2238+ if (test_bit(IRQ_PEND_EXT_EMERGENCY, &pending_irqs)) {
2239+ for_each_set_bit(cpuaddr, sigp_emerg_pending, KVM_MAX_VCPUS) {
2240+ memset(&irq, 0, sizeof(irq));
2241+ if (n + sizeof(irq) > len)
2242+ return -ENOBUFS;
2243+ irq.type = KVM_S390_INT_EMERGENCY;
2244+ irq.u.emerg.code = cpuaddr;
2245+ if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2246+ return -EFAULT;
2247+ n += sizeof(irq);
2248+ }
2249+ }
2250+
2251+ if ((sigp_ctrl & SIGP_CTRL_C) &&
2252+ (atomic_read(&vcpu->arch.sie_block->cpuflags) &
2253+ CPUSTAT_ECALL_PEND)) {
2254+ if (n + sizeof(irq) > len)
2255+ return -ENOBUFS;
2256+ memset(&irq, 0, sizeof(irq));
2257+ irq.type = KVM_S390_INT_EXTERNAL_CALL;
2258+ irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK;
2259+ if (copy_to_user(&buf[n], &irq, sizeof(irq)))
2260+ return -EFAULT;
2261+ n += sizeof(irq);
2262+ }
2263+
2264+ return n;
2265+}
arch/s390/kvm/kvm-s390.c+36−0
@@ -41,6 +41,9 @@ · 40 unmodified lines
4141 #include "trace-s390.h"
4242
4343 #define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */
44+#define LOCAL_IRQS 32
45+#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
46+ (KVM_MAX_VCPUS + LOCAL_IRQS))
4447
4548 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
4649
@@ -181,6 +184,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 134 unmodified lines
181184 case KVM_CAP_S390_USER_SIGP:
182185 case KVM_CAP_S390_USER_STSI:
183186 case KVM_CAP_S390_SKEYS:
187+ case KVM_CAP_S390_IRQ_STATE:
184188 r = 1;
185189 break;
186190 case KVM_CAP_S390_MEM_OP:
@@ -2500,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 2313 unmodified lines
25002504 r = -EFAULT;
25012505 break;
25022506 }
2507+ case KVM_S390_SET_IRQ_STATE: {
2508+ struct kvm_s390_irq_state irq_state;
2509+
2510+ r = -EFAULT;
2511+ if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
2512+ break;
2513+ if (irq_state.len > VCPU_IRQS_MAX_BUF ||
2514+ irq_state.len == 0 ||
2515+ irq_state.len % sizeof(struct kvm_s390_irq) > 0) {
2516+ r = -EINVAL;
2517+ break;
2518+ }
2519+ r = kvm_s390_set_irq_state(vcpu,
2520+ (void __user *) irq_state.buf,
2521+ irq_state.len);
2522+ break;
2523+ }
2524+ case KVM_S390_GET_IRQ_STATE: {
2525+ struct kvm_s390_irq_state irq_state;
2526+
2527+ r = -EFAULT;
2528+ if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
2529+ break;
2530+ if (irq_state.len == 0) {
2531+ r = -EINVAL;
2532+ break;
2533+ }
2534+ r = kvm_s390_get_irq_state(vcpu,
2535+ (__u8 __user *) irq_state.buf,
2536+ irq_state.len);
2537+ break;
2538+ }
25032539 default:
25042540 r = -ENOTTY;
25052541 }
arch/s390/kvm/kvm-s390.h+4−0
@@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu); · 271 unmodified lines
272272 extern struct kvm_device_ops kvm_flic_ops;
273273 int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu);
274274 void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu);
275+int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu,
276+ void __user *buf, int len);
277+int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu,
278+ __u8 __user *buf, int len);
275279
276280 /* implemented in guestdbg.c */
277281 void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu);
include/uapi/linux/kvm.h+11−0
@@ -558,6 +558,13 @@ struct kvm_s390_irq { · 557 unmodified lines
558558 } u;
559559 };
560560
561+struct kvm_s390_irq_state {
562+ __u64 buf;
563+ __u32 flags;
564+ __u32 len;
565+ __u32 reserved[4];
566+};
567+
561568 /* for KVM_SET_GUEST_DEBUG */
562569
563570 #define KVM_GUESTDBG_ENABLE 0x00000001
@@ -803,6 +810,7 @@ struct kvm_ppc_smmu_info { · 239 unmodified lines
803810 #define KVM_CAP_S390_USER_STSI 109
804811 #define KVM_CAP_S390_SKEYS 110
805812 #define KVM_CAP_S390_INJECT_IRQ 113
813+#define KVM_CAP_S390_IRQ_STATE 114
806814
807815 #ifdef KVM_CAP_IRQ_ROUTING
808816
@@ -1185,6 +1193,9 @@ struct kvm_s390_ucas_mapping { · 376 unmodified lines
11851193 #define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys)
11861194 /* Available with KVM_CAP_S390_INJECT_IRQ */
11871195 #define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq)
1196+/* Available with KVM_CAP_S390_IRQ_STATE */
1197+#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
1198+#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
11881199
11891200 #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
11901201 #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t