Skip to content

Commit 190df4a

Browse files
Claudio Imbrendaborntraeger
authored andcommitted
KVM: s390: CMMA tracking, ESSA emulation, migration mode
* Add a migration state bitmap to keep track of which pages have dirty CMMA information. * Disable CMMA by default, so we can track if it's used or not. Enable it on first use like we do for storage keys (unless we are doing a migration). * Creates a VM attribute to enter and leave migration mode. * In migration mode, CMMA is disabled in the SIE block, so ESSA is always interpreted and emulated in software. * Free the migration state on VM destroy. Signed-off-by: Claudio Imbrenda <[email protected]> Acked-by: Cornelia Huck <[email protected]> Reviewed-by: Christian Borntraeger <[email protected]> Signed-off-by: Christian Borntraeger <[email protected]>
1 parent 865279c commit 190df4a

File tree

5 files changed

+304
-6
lines changed

5 files changed

+304
-6
lines changed

Documentation/virtual/kvm/devices/vm.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,36 @@ Allows user space to disable dea key wrapping, clearing the wrapping key.
222222

223223
Parameters: none
224224
Returns: 0
225+
226+
5. GROUP: KVM_S390_VM_MIGRATION
227+
Architectures: s390
228+
229+
5.1. ATTRIBUTE: KVM_S390_VM_MIGRATION_STOP (w/o)
230+
231+
Allows userspace to stop migration mode, needed for PGSTE migration.
232+
Setting this attribute when migration mode is not active will have no
233+
effects.
234+
235+
Parameters: none
236+
Returns: 0
237+
238+
5.2. ATTRIBUTE: KVM_S390_VM_MIGRATION_START (w/o)
239+
240+
Allows userspace to start migration mode, needed for PGSTE migration.
241+
Setting this attribute when migration mode is already active will have
242+
no effects.
243+
244+
Parameters: none
245+
Returns: -ENOMEM if there is not enough free memory to start migration mode
246+
-EINVAL if the state of the VM is invalid (e.g. no memory defined)
247+
0 in case of success.
248+
249+
5.3. ATTRIBUTE: KVM_S390_VM_MIGRATION_STATUS (r/o)
250+
251+
Allows userspace to query the status of migration mode.
252+
253+
Parameters: address of a buffer in user space to store the data (u64) to;
254+
the data itself is either 0 if migration mode is disabled or 1
255+
if it is enabled
256+
Returns: -EFAULT if the given address is not accessible from kernel space
257+
0 in case of success.

arch/s390/include/asm/kvm_host.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
#define KVM_REQ_ENABLE_IBS 8
4646
#define KVM_REQ_DISABLE_IBS 9
4747
#define KVM_REQ_ICPT_OPEREXC 10
48+
#define KVM_REQ_START_MIGRATION 11
49+
#define KVM_REQ_STOP_MIGRATION 12
4850

4951
#define SIGP_CTRL_C 0x80
5052
#define SIGP_CTRL_SCN_MASK 0x3f
@@ -691,6 +693,12 @@ struct kvm_s390_vsie {
691693
struct page *pages[KVM_MAX_VCPUS];
692694
};
693695

696+
struct kvm_s390_migration_state {
697+
unsigned long bitmap_size; /* in bits (number of guest pages) */
698+
atomic64_t dirty_pages; /* number of dirty pages */
699+
unsigned long *pgste_bitmap;
700+
};
701+
694702
struct kvm_arch{
695703
void *sca;
696704
int use_esca;
@@ -718,6 +726,7 @@ struct kvm_arch{
718726
struct kvm_s390_crypto crypto;
719727
struct kvm_s390_vsie vsie;
720728
u64 epoch;
729+
struct kvm_s390_migration_state *migration_state;
721730
/* subset of available cpu features enabled by user space */
722731
DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
723732
};

arch/s390/include/uapi/asm/kvm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ struct kvm_s390_io_adapter_req {
7070
#define KVM_S390_VM_TOD 1
7171
#define KVM_S390_VM_CRYPTO 2
7272
#define KVM_S390_VM_CPU_MODEL 3
73+
#define KVM_S390_VM_MIGRATION 4
7374

7475
/* kvm attributes for mem_ctrl */
7576
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
@@ -151,6 +152,11 @@ struct kvm_s390_vm_cpu_subfunc {
151152
#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2
152153
#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3
153154

155+
/* kvm attributes for migration mode */
156+
#define KVM_S390_VM_MIGRATION_STOP 0
157+
#define KVM_S390_VM_MIGRATION_START 1
158+
#define KVM_S390_VM_MIGRATION_STATUS 2
159+
154160
/* for KVM_GET_REGS and KVM_SET_REGS */
155161
struct kvm_regs {
156162
/* general purpose regs for s390 */

arch/s390/kvm/kvm-s390.c

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/bitmap.h>
3232
#include <linux/sched/signal.h>
3333

34+
#include <linux/string.h>
3435
#include <asm/asm-offsets.h>
3536
#include <asm/lowcore.h>
3637
#include <asm/stp.h>
@@ -750,6 +751,129 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr)
750751
return 0;
751752
}
752753

754+
static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req)
755+
{
756+
int cx;
757+
struct kvm_vcpu *vcpu;
758+
759+
kvm_for_each_vcpu(cx, vcpu, kvm)
760+
kvm_s390_sync_request(req, vcpu);
761+
}
762+
763+
/*
764+
* Must be called with kvm->srcu held to avoid races on memslots, and with
765+
* kvm->lock to avoid races with ourselves and kvm_s390_vm_stop_migration.
766+
*/
767+
static int kvm_s390_vm_start_migration(struct kvm *kvm)
768+
{
769+
struct kvm_s390_migration_state *mgs;
770+
struct kvm_memory_slot *ms;
771+
/* should be the only one */
772+
struct kvm_memslots *slots;
773+
unsigned long ram_pages;
774+
int slotnr;
775+
776+
/* migration mode already enabled */
777+
if (kvm->arch.migration_state)
778+
return 0;
779+
780+
slots = kvm_memslots(kvm);
781+
if (!slots || !slots->used_slots)
782+
return -EINVAL;
783+
784+
mgs = kzalloc(sizeof(*mgs), GFP_KERNEL);
785+
if (!mgs)
786+
return -ENOMEM;
787+
kvm->arch.migration_state = mgs;
788+
789+
if (kvm->arch.use_cmma) {
790+
/*
791+
* Get the last slot. They should be sorted by base_gfn, so the
792+
* last slot is also the one at the end of the address space.
793+
* We have verified above that at least one slot is present.
794+
*/
795+
ms = slots->memslots + slots->used_slots - 1;
796+
/* round up so we only use full longs */
797+
ram_pages = roundup(ms->base_gfn + ms->npages, BITS_PER_LONG);
798+
/* allocate enough bytes to store all the bits */
799+
mgs->pgste_bitmap = vmalloc(ram_pages / 8);
800+
if (!mgs->pgste_bitmap) {
801+
kfree(mgs);
802+
kvm->arch.migration_state = NULL;
803+
return -ENOMEM;
804+
}
805+
806+
mgs->bitmap_size = ram_pages;
807+
atomic64_set(&mgs->dirty_pages, ram_pages);
808+
/* mark all the pages in active slots as dirty */
809+
for (slotnr = 0; slotnr < slots->used_slots; slotnr++) {
810+
ms = slots->memslots + slotnr;
811+
bitmap_set(mgs->pgste_bitmap, ms->base_gfn, ms->npages);
812+
}
813+
814+
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_START_MIGRATION);
815+
}
816+
return 0;
817+
}
818+
819+
/*
820+
* Must be called with kvm->lock to avoid races with ourselves and
821+
* kvm_s390_vm_start_migration.
822+
*/
823+
static int kvm_s390_vm_stop_migration(struct kvm *kvm)
824+
{
825+
struct kvm_s390_migration_state *mgs;
826+
827+
/* migration mode already disabled */
828+
if (!kvm->arch.migration_state)
829+
return 0;
830+
mgs = kvm->arch.migration_state;
831+
kvm->arch.migration_state = NULL;
832+
833+
if (kvm->arch.use_cmma) {
834+
kvm_s390_sync_request_broadcast(kvm, KVM_REQ_STOP_MIGRATION);
835+
vfree(mgs->pgste_bitmap);
836+
}
837+
kfree(mgs);
838+
return 0;
839+
}
840+
841+
static int kvm_s390_vm_set_migration(struct kvm *kvm,
842+
struct kvm_device_attr *attr)
843+
{
844+
int idx, res = -ENXIO;
845+
846+
mutex_lock(&kvm->lock);
847+
switch (attr->attr) {
848+
case KVM_S390_VM_MIGRATION_START:
849+
idx = srcu_read_lock(&kvm->srcu);
850+
res = kvm_s390_vm_start_migration(kvm);
851+
srcu_read_unlock(&kvm->srcu, idx);
852+
break;
853+
case KVM_S390_VM_MIGRATION_STOP:
854+
res = kvm_s390_vm_stop_migration(kvm);
855+
break;
856+
default:
857+
break;
858+
}
859+
mutex_unlock(&kvm->lock);
860+
861+
return res;
862+
}
863+
864+
static int kvm_s390_vm_get_migration(struct kvm *kvm,
865+
struct kvm_device_attr *attr)
866+
{
867+
u64 mig = (kvm->arch.migration_state != NULL);
868+
869+
if (attr->attr != KVM_S390_VM_MIGRATION_STATUS)
870+
return -ENXIO;
871+
872+
if (copy_to_user((void __user *)attr->addr, &mig, sizeof(mig)))
873+
return -EFAULT;
874+
return 0;
875+
}
876+
753877
static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
754878
{
755879
u8 gtod_high;
@@ -1090,6 +1214,9 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
10901214
case KVM_S390_VM_CRYPTO:
10911215
ret = kvm_s390_vm_set_crypto(kvm, attr);
10921216
break;
1217+
case KVM_S390_VM_MIGRATION:
1218+
ret = kvm_s390_vm_set_migration(kvm, attr);
1219+
break;
10931220
default:
10941221
ret = -ENXIO;
10951222
break;
@@ -1112,6 +1239,9 @@ static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr)
11121239
case KVM_S390_VM_CPU_MODEL:
11131240
ret = kvm_s390_get_cpu_model(kvm, attr);
11141241
break;
1242+
case KVM_S390_VM_MIGRATION:
1243+
ret = kvm_s390_vm_get_migration(kvm, attr);
1244+
break;
11151245
default:
11161246
ret = -ENXIO;
11171247
break;
@@ -1179,6 +1309,9 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
11791309
break;
11801310
}
11811311
break;
1312+
case KVM_S390_VM_MIGRATION:
1313+
ret = 0;
1314+
break;
11821315
default:
11831316
ret = -ENXIO;
11841317
break;
@@ -1633,6 +1766,10 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
16331766
kvm_s390_destroy_adapters(kvm);
16341767
kvm_s390_clear_float_irqs(kvm);
16351768
kvm_s390_vsie_destroy(kvm);
1769+
if (kvm->arch.migration_state) {
1770+
vfree(kvm->arch.migration_state->pgste_bitmap);
1771+
kfree(kvm->arch.migration_state);
1772+
}
16361773
KVM_EVENT(3, "vm 0x%pK destroyed", kvm);
16371774
}
16381775

@@ -1977,7 +2114,6 @@ int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu)
19772114
if (!vcpu->arch.sie_block->cbrlo)
19782115
return -ENOMEM;
19792116

1980-
vcpu->arch.sie_block->ecb2 |= ECB2_CMMA;
19812117
vcpu->arch.sie_block->ecb2 &= ~ECB2_PFMFI;
19822118
return 0;
19832119
}
@@ -2489,6 +2625,27 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
24892625
goto retry;
24902626
}
24912627

2628+
if (kvm_check_request(KVM_REQ_START_MIGRATION, vcpu)) {
2629+
/*
2630+
* Disable CMMA virtualization; we will emulate the ESSA
2631+
* instruction manually, in order to provide additional
2632+
* functionalities needed for live migration.
2633+
*/
2634+
vcpu->arch.sie_block->ecb2 &= ~ECB2_CMMA;
2635+
goto retry;
2636+
}
2637+
2638+
if (kvm_check_request(KVM_REQ_STOP_MIGRATION, vcpu)) {
2639+
/*
2640+
* Re-enable CMMA virtualization if CMMA is available and
2641+
* was used.
2642+
*/
2643+
if ((vcpu->kvm->arch.use_cmma) &&
2644+
(vcpu->kvm->mm->context.use_cmma))
2645+
vcpu->arch.sie_block->ecb2 |= ECB2_CMMA;
2646+
goto retry;
2647+
}
2648+
24922649
/* nothing to do, just clear the request */
24932650
kvm_clear_request(KVM_REQ_UNHALT, vcpu);
24942651

0 commit comments

Comments
 (0)