aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2014-01-22 14:42:57 +1100
committerEli Qiao <taget@linux.vnet.ibm.com>2014-01-22 11:58:02 +0800
commit5dd5f6f94556a52effa6a89ba7c4a19f3782f70d (patch)
tree6dff71fe505011c9a32e29da52aad9eedf6bc01f
parent15402dd3ce509f2c92f5448ac57c08799c2c6988 (diff)
downloadpowerkvm-5dd5f6f94556a52effa6a89ba7c4a19f3782f70d.tar.gz
vfio: fix virtmode handler
The existing handler assumes that the first failed TCE entry's host physical address is saved in the tce_tmp_hpas cache but it is not so the virtmode handler has to read it from the TCE list again so does this patch. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
-rw-r--r--arch/powerpc/kvm/book3s_64_vio.c4
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c6
2 files changed, 9 insertions, 1 deletions
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index 2d4f912dbb7e7..65557562ecfb7 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -433,7 +433,9 @@ static long kvmppc_h_put_tce_indirect_iommu(struct kvm_vcpu *vcpu,
return H_RESCINDED;
if (vcpu->arch.tce_rm_fail == TCERM_GETPAGE) {
- unsigned long tmp = vcpu->arch.tce_tmp_hpas[vcpu->arch.tce_tmp_num];
+ unsigned long tmp;
+ if (get_user(tmp, tces + vcpu->arch.tce_tmp_num))
+ return H_HARDWARE;
put_page(pfn_to_page(tmp >> PAGE_SHIFT));
}
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 6b54a0c9f50af..ba16a7322fa98 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -167,8 +167,13 @@ static unsigned long kvmppc_rm_hugepage_gpa_to_hpa(
/*
* Converts guest physical address to host physical address.
+ *
* Tries to increase page counter via get_page_unless_zero() and
* returns ERROR_ADDR if failed.
+ *
+ * Returns ERROR_ADDR if the page has gone before we increased
+ * page use counter. *pg may not be NULL if put_page_unless_one()
+ * failed to put the page.
*/
static unsigned long kvmppc_rm_gpa_to_hpa_and_get(struct kvm_vcpu *vcpu,
unsigned long gpa, struct page **pg)
@@ -304,6 +309,7 @@ static long kvmppc_rm_h_put_tce_indirect_iommu(struct kvm_vcpu *vcpu,
for (i = 0; i < npages; ++i) {
hpa = kvmppc_rm_gpa_to_hpa_and_get(vcpu, tces[i], &pg);
if (hpa == ERROR_ADDR) {
+ vcpu->arch.tce_tmp_hpas[i] = 0xBAADF00D; /* poison */
vcpu->arch.tce_tmp_num = i;
vcpu->arch.tce_rm_fail = pg ?
TCERM_GETPAGE : TCERM_NONE;