aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2014-01-17 16:32:39 +1100
committerEli Qiao <taget@linux.vnet.ibm.com>2014-01-22 10:26:26 +0800
commit560d837886d869a0cab7914097253b8a5a265c40 (patch)
treee0cc23664ae6051a51fd4925b545e9863a8abce8
parent6b49cdc53603dc9e85a26b3f821a1cdfd0ef444d (diff)
downloadpowerkvm-560d837886d869a0cab7914097253b8a5a265c40.tar.gz
vfio: fix in-kernel and ioctl handlers
This fixes missing read/write TCE bits in VFIO map/unmap ioctls. This fixes the real mode handler to switch to the virtual mode if pte does not have "write" AND "dirty" bits set. This fixes get_user_pages_fast() call in the virtual mode handler to use correct write flag (used to be 0 always). This adds a lock around a kvm_memory_slot struct use. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> (cherry picked from commit 754177ee49cd27c9380e7bb9c0de6f8488197ca3) Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
-rw-r--r--arch/powerpc/kernel/iommu.c1
-rw-r--r--arch/powerpc/kvm/book3s_64_vio.c8
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c2
3 files changed, 8 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 02aaae61d999e..3018b250a969e 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1107,6 +1107,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
return -EFAULT;
}
hpa = __pa((unsigned long) page_address(page)) + offset;
+ hpa |= tce & (TCE_PCI_READ | TCE_PCI_WRITE);
ret = iommu_tce_build(tbl, entry, &hpa, 1, false);
if (ret)
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index d8cd27e40fe55..2d4f912dbb7e7 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -338,13 +338,17 @@ static void __user *kvmppc_gpa_to_hva_and_get(struct kvm_vcpu *vcpu,
{
unsigned long hva, gfn = gpa >> PAGE_SHIFT;
struct kvm_memory_slot *memslot;
- const int is_write = 0;
+ const int is_write = !!(gpa & TCE_PCI_WRITE);
+ int idx = srcu_read_lock(&vcpu->kvm->srcu);
memslot = search_memslots(kvm_memslots(vcpu->kvm), gfn);
- if (!memslot)
+ if (!memslot) {
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
return ERROR_ADDR;
+ }
hva = __gfn_to_hva_memslot(memslot, gfn) | (gpa & ~PAGE_MASK);
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
if (get_user_pages_fast(hva & PAGE_MASK, 1, is_write, pg) != 1)
return ERROR_ADDR;
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index 8ed948426d47b..22f09d85ce867 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -205,7 +205,7 @@ static unsigned long kvmppc_rm_gpa_to_hpa_and_get(struct kvm_vcpu *vcpu,
if (shift > PAGE_SHIFT)
return ERROR_ADDR;
- if (((gpa & TCE_PCI_WRITE) || pte_write(pte)) && !pte_dirty(pte))
+ if ((gpa & TCE_PCI_WRITE) && !(pte_write(pte) && pte_dirty(pte)))
return ERROR_ADDR;
if (!pte_young(pte))