diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2014-01-17 16:32:39 +1100 |
---|---|---|
committer | Eli Qiao <taget@linux.vnet.ibm.com> | 2014-01-22 10:26:26 +0800 |
commit | 560d837886d869a0cab7914097253b8a5a265c40 (patch) | |
tree | e0cc23664ae6051a51fd4925b545e9863a8abce8 | |
parent | 6b49cdc53603dc9e85a26b3f821a1cdfd0ef444d (diff) | |
download | powerkvm-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.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_64_vio.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_64_vio_hv.c | 2 |
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)) |