Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Use RCU for arch.spapr_tce_tables

At the moment only spapr_tce_tables updates are protected against races
but not lookups. This fixes missing protection by using RCU for the list.
As lookups also happen in real mode, this uses
list_for_each_entry_lockless() (which is expected not to access any
vmalloc'd memory).

This converts release_spapr_tce_table() to a RCU scheduled handler.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Alexey Kardashevskiy and committed by
Paul Mackerras
366baf28 fcbb2ce6

+14 -11
+1
arch/powerpc/include/asm/kvm_host.h
··· 183 183 struct kvm *kvm; 184 184 u64 liobn; 185 185 u32 window_size; 186 + struct rcu_head rcu; 186 187 struct page *pages[0]; 187 188 }; 188 189
+1 -1
arch/powerpc/kvm/book3s.c
··· 807 807 { 808 808 809 809 #ifdef CONFIG_PPC64 810 - INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables); 810 + INIT_LIST_HEAD_RCU(&kvm->arch.spapr_tce_tables); 811 811 INIT_LIST_HEAD(&kvm->arch.rtas_tokens); 812 812 #endif 813 813
+11 -9
arch/powerpc/kvm/book3s_64_vio.c
··· 45 45 * sizeof(u64), PAGE_SIZE) / PAGE_SIZE; 46 46 } 47 47 48 - static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt) 48 + static void release_spapr_tce_table(struct rcu_head *head) 49 49 { 50 - struct kvm *kvm = stt->kvm; 50 + struct kvmppc_spapr_tce_table *stt = container_of(head, 51 + struct kvmppc_spapr_tce_table, rcu); 51 52 int i; 52 53 53 - mutex_lock(&kvm->lock); 54 - list_del(&stt->list); 55 54 for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++) 56 55 __free_page(stt->pages[i]); 57 - kfree(stt); 58 - mutex_unlock(&kvm->lock); 59 56 60 - kvm_put_kvm(kvm); 57 + kfree(stt); 61 58 } 62 59 63 60 static int kvm_spapr_tce_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ··· 85 88 { 86 89 struct kvmppc_spapr_tce_table *stt = filp->private_data; 87 90 88 - release_spapr_tce_table(stt); 91 + list_del_rcu(&stt->list); 92 + 93 + kvm_put_kvm(stt->kvm); 94 + 95 + call_rcu(&stt->rcu, release_spapr_tce_table); 96 + 89 97 return 0; 90 98 } 91 99 ··· 133 131 kvm_get_kvm(kvm); 134 132 135 133 mutex_lock(&kvm->lock); 136 - list_add(&stt->list, &kvm->arch.spapr_tce_tables); 134 + list_add_rcu(&stt->list, &kvm->arch.spapr_tce_tables); 137 135 138 136 mutex_unlock(&kvm->lock); 139 137
+1 -1
arch/powerpc/kvm/book3s_64_vio_hv.c
··· 51 51 struct kvm *kvm = vcpu->kvm; 52 52 struct kvmppc_spapr_tce_table *stt; 53 53 54 - list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) 54 + list_for_each_entry_lockless(stt, &kvm->arch.spapr_tce_tables, list) 55 55 if (stt->liobn == liobn) 56 56 return stt; 57 57