zanghongyong at huawei.com
2011-Dec-16  05:32 UTC
[PATCH 0/2] vhot-net: Use kvm_memslots instead of vhost_memory to translate GPA to HVA
From: Hongyong Zang <zanghongyong at huawei.com> Vhost-net uses its own vhost_memory, which results from user space (qemu) info, to translate GPA to HVA. Since kernel's kvm structure already maintains the address relationship in its member *kvm_memslots*, these patches use kernel's kvm_memslots directly without the need of initialization and maintenance of vhost_memory. Hongyong Zang (2): kvm: Introduce get_kvm_from_task vhost-net: Use kvm_memslots for address translation drivers/vhost/vhost.c | 53 +++++++++++++++++---------------------------- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 13 +++++++++++ 3 files changed, 34 insertions(+), 34 deletions(-)
zanghongyong at huawei.com
2011-Dec-16  05:32 UTC
[PATCH 1/2] kvm: Introduce get_kvm_from_task
From: Hongyong Zang <zanghongyong at huawei.com>
This function finds the kvm structure from its corresponding user
space process, such as qemu process.
Signed-off-by: Hongyong Zang <zanghongyong at huawei.com>
---
 include/linux/kvm_host.h |    2 +-
 virt/kvm/kvm_main.c      |   13 +++++++++++++
 2 files changed, 14 insertions(+), 1 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8c5c303..1b2f027 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -801,4 +801,4 @@ static inline bool kvm_check_request(int req, struct
kvm_vcpu *vcpu)
 }
 
 #endif
-
+struct kvm *get_kvm_from_task(struct task_struct *task);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index e289486..458fe29 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2664,6 +2664,19 @@ static const struct file_operations *stat_fops[] = {
 	[KVM_STAT_VM]   = &vm_stat_fops,
 };
 
+struct kvm* get_kvm_from_task(struct task_struct *task)
+{
+        struct kvm *kvm;
+
+        list_for_each_entry(kvm, &vm_list, vm_list) {
+                if(kvm->mm == task->mm)
+                    return kvm;
+        }
+
+        return NULL;
+}
+EXPORT_SYMBOL_GPL(get_kvm_from_task);
+
 static void kvm_init_debug(void)
 {
 	struct kvm_stats_debugfs_item *p;
-- 
1.7.1
zanghongyong at huawei.com
2011-Dec-16  05:32 UTC
[PATCH 2/2] vhost-net: Use kvm_memslots for address translation
From: Hongyong Zang <zanghongyong at huawei.com>
Use kvm's memslots instead of vhost_memory to traslate address
from GPA to HVA.
Signed-off-by: Hongyong Zang <zanghongyong at huawei.com>
---
 drivers/vhost/vhost.c |   53 ++++++++++++++++++------------------------------
 1 files changed, 20 insertions(+), 33 deletions(-)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index c14c42b..63e4322 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -11,6 +11,7 @@
  * Generic code for virtio server in host kernel.
  */
 
+#include <linux/kvm_host.h>
 #include <linux/eventfd.h>
 #include <linux/vhost.h>
 #include <linux/virtio_net.h>
@@ -904,23 +905,6 @@ done:
 	return r;
 }
 
-static const struct vhost_memory_region *find_region(struct vhost_memory *mem,
-						     __u64 addr, __u32 len)
-{
-	struct vhost_memory_region *reg;
-	int i;
-
-	/* linear search is not brilliant, but we really have on the order of 6
-	 * regions in practice */
-	for (i = 0; i < mem->nregions; ++i) {
-		reg = mem->regions + i;
-		if (reg->guest_phys_addr <= addr &&
-		    reg->guest_phys_addr + reg->memory_size - 1 >= addr)
-			return reg;
-	}
-	return NULL;
-}
-
 /* TODO: This is really inefficient.  We need something like get_user()
  * (instruction directly accesses the data, with an exception table entry
  * returning -EFAULT). See Documentation/x86/exception-tables.txt.
@@ -1046,40 +1030,36 @@ int vhost_init_used(struct vhost_virtqueue *vq)
 	return get_user(vq->last_used_idx, &vq->used->idx);
 }
 
-static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+static int translate_desc(struct kvm *kvm, u64 addr, u32 len,
 			  struct iovec iov[], int iov_size)
 {
-	const struct vhost_memory_region *reg;
-	struct vhost_memory *mem;
+	const struct kvm_memory_slot *slot;
+	gfn_t gfn = addr >> PAGE_SHIFT;
 	struct iovec *_iov;
 	u64 s = 0;
 	int ret = 0;
 
-	rcu_read_lock();
-
-	mem = rcu_dereference(dev->memory);
 	while ((u64)len > s) {
 		u64 size;
 		if (unlikely(ret >= iov_size)) {
 			ret = -ENOBUFS;
 			break;
 		}
-		reg = find_region(mem, addr, len);
-		if (unlikely(!reg)) {
+		slot = gfn_to_memslot(kvm, gfn);
+		if (unlikely(!slot)) {
 			ret = -EFAULT;
 			break;
 		}
 		_iov = iov + ret;
-		size = reg->memory_size - addr + reg->guest_phys_addr;
+		size = slot->npages*VHOST_PAGE_SIZE - addr +
(slot->base_gfn<<PAGE_SHIFT);
 		_iov->iov_len = min((u64)len, size);
 		_iov->iov_base = (void __user *)(unsigned long)
-			(reg->userspace_addr + addr - reg->guest_phys_addr);
+			(slot->userspace_addr + addr - (slot->base_gfn<<PAGE_SHIFT));
 		s += size;
 		addr += size;
 		++ret;
 	}
 
-	rcu_read_unlock();
 	return ret;
 }
 
@@ -1104,7 +1084,7 @@ static unsigned next_desc(struct vring_desc *desc)
 	return next;
 }
 
-static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+static int get_indirect(struct kvm *kvm, struct vhost_virtqueue *vq,
 			struct iovec iov[], unsigned int iov_size,
 			unsigned int *out_num, unsigned int *in_num,
 			struct vhost_log *log, unsigned int *log_num,
@@ -1123,7 +1103,7 @@ static int get_indirect(struct vhost_dev *dev, struct
vhost_virtqueue *vq,
 		return -EINVAL;
 	}
 
-	ret = translate_desc(dev, indirect->addr, indirect->len,
vq->indirect,
+	ret = translate_desc(kvm, indirect->addr, indirect->len,
vq->indirect,
 			     UIO_MAXIOV);
 	if (unlikely(ret < 0)) {
 		vq_err(vq, "Translation failure %d in indirect.\n", ret);
@@ -1163,7 +1143,7 @@ static int get_indirect(struct vhost_dev *dev, struct
vhost_virtqueue *vq,
 			return -EINVAL;
 		}
 
-		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+		ret = translate_desc(kvm, desc.addr, desc.len, iov + iov_count,
 				     iov_size - iov_count);
 		if (unlikely(ret < 0)) {
 			vq_err(vq, "Translation failure %d indirect idx %d\n",
@@ -1209,6 +1189,13 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct
vhost_virtqueue *vq,
 	unsigned int i, head, found = 0;
 	u16 last_avail_idx;
 	int ret;
+	struct kvm *kvm = get_kvm_from_task(current);
+
+	if(unlikely(kvm == NULL)){
+		vq_err(vq, "Failed to get corresponding kvm struct of vhost-%d\n",
+			current->pid);
+		return -EFAULT;
+	}
 
 	/* Check it isn't doing very strange things with descriptor numbers. */
 	last_avail_idx = vq->last_avail_idx;
@@ -1274,7 +1261,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct
vhost_virtqueue *vq,
 			return -EFAULT;
 		}
 		if (desc.flags & VRING_DESC_F_INDIRECT) {
-			ret = get_indirect(dev, vq, iov, iov_size,
+			ret = get_indirect(kvm, vq, iov, iov_size,
 					   out_num, in_num,
 					   log, log_num, &desc);
 			if (unlikely(ret < 0)) {
@@ -1285,7 +1272,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct
vhost_virtqueue *vq,
 			continue;
 		}
 
-		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+		ret = translate_desc(kvm, desc.addr, desc.len, iov + iov_count,
 				     iov_size - iov_count);
 		if (unlikely(ret < 0)) {
 			vq_err(vq, "Translation failure %d descriptor idx %d\n",
-- 
1.7.1
Takuya Yoshikawa
2011-Dec-16  07:05 UTC
[PATCH 0/2] vhot-net: Use kvm_memslots instead of vhost_memory to translate GPA to HVA
(2011/12/16 14:32), zanghongyong at huawei.com wrote:> From: Hongyong Zang<zanghongyong at huawei.com> > > Vhost-net uses its own vhost_memory, which results from user space (qemu) info, > to translate GPA to HVA. Since kernel's kvm structure already maintains the > address relationship in its member *kvm_memslots*, these patches use kernel's > kvm_memslots directly without the need of initialization and maintenance of > vhost_memory.Isn't vhost independent from KVM? Takuya
Sasha Levin
2011-Dec-16  07:05 UTC
[PATCH 0/2] vhot-net: Use kvm_memslots instead of vhost_memory to translate GPA to HVA
On Fri, 2011-12-16 at 13:32 +0800, zanghongyong at huawei.com wrote:> From: Hongyong Zang <zanghongyong at huawei.com> > > Vhost-net uses its own vhost_memory, which results from user space (qemu) info, > to translate GPA to HVA. Since kernel's kvm structure already maintains the > address relationship in its member *kvm_memslots*, these patches use kernel's > kvm_memslots directly without the need of initialization and maintenance of > vhost_memory.Conceptually, vhost isn't aware of KVM - it's just a driver which moves data from vq to a tap device and back. You can't simply add KVM specific code into vhost. Whats the performance benefit? -- Sasha.