Skip to contentSkip to conversation

mm: export use_mm/unuse_mm to modules

PATCH Superseded Michael S. Tsirkin 3 participants 28 messages Aug 19, 2009 – Aug 27, 2009 1 message not in the archive

Subsystems (11)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Michael S. Tsirkin

author maintainer
#1 lore raw

PATCH v4 1/2 mm: export use_mm/unuse_mm to modules

vhost net module wants to do copy to/from user from a kernel thread, which needs use_mm (like what fs/aio has). Move that into mm/ and export to modules.

---
 fs/aio.c                    |   47 +----------------------------------
 include/linux/mmu_context.h |    9 ++++++
 mm/Makefile                 |    2 +-
 mm/mmu_context.c            |   58 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 47 deletions(-)
 create mode 100644 include/linux/mmu_context.h
 create mode 100644 mm/mmu_context.c
fs/aio.c +1 -46
index d065b2c..fc21c23 100644
@@ -24,6 +24,7 @@
 #include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/mmu_context.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/aio.h>
@@ -34,7 +35,6 @@
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
-#include <asm/mmu_context.h>
 
 #if DEBUG > 1
 #define dprintk		printk
@@ -595,51 +595,6 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
 }
 
 /*
- * use_mm
- *	Makes the calling kernel thread take on the specified
- *	mm context.
- *	Called by the retry thread execute retries within the
- *	iocb issuer's mm context, so that copy_from/to_user
- *	operations work seamlessly for aio.
- *	(Note: this routine is intended to be called only
- *	from a kernel thread context)
- */
-static void use_mm(struct mm_struct *mm)
-{
-	struct mm_struct *active_mm;
-	struct task_struct *tsk = current;
-
-	task_lock(tsk);
-	active_mm = tsk->active_mm;
-	atomic_inc(&mm->mm_count);
-	tsk->mm = mm;
-	tsk->active_mm = mm;
-	switch_mm(active_mm, mm, tsk);
-	task_unlock(tsk);
-
-	mmdrop(active_mm);
-}
-
-/*
- * unuse_mm
- *	Reverses the effect of use_mm, i.e. releases the
- *	specified mm context which was earlier taken on
- *	by the calling kernel thread
- *	(Note: this routine is intended to be called only
- *	from a kernel thread context)
- */
-static void unuse_mm(struct mm_struct *mm)
-{
-	struct task_struct *tsk = current;
-
-	task_lock(tsk);
-	tsk->mm = NULL;
-	/* active_mm is still 'mm' */
-	enter_lazy_tlb(mm, tsk);
-	task_unlock(tsk);
-}
-
-/*
  * Queue up a kiocb to be retried. Assumes that the kiocb
  * has already been marked as kicked, and places it on
  * the retry run list for the corresponding ioctx, if it
include/linux/mmu_context.h new file +9 -0
new file mode 100644
index 0000000..70fffeb
@@ -0,0 +1,9 @@
+#ifndef _LINUX_MMU_CONTEXT_H
+#define _LINUX_MMU_CONTEXT_H
+
+struct mm_struct;
+
+void use_mm(struct mm_struct *mm);
+void unuse_mm(struct mm_struct *mm);
+
+#endif
mm/Makefile +1 -1
index 5e0bd64..46c3892 100644
@@ -11,7 +11,7 @@ obj-y			:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
 			   maccess.o page_alloc.o page-writeback.o pdflush.o \
 			   readahead.o swap.o truncate.o vmscan.o shmem.o \
 			   prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
-			   page_isolation.o mm_init.o $(mmu-y)
+			   page_isolation.o mm_init.o mmu_context.o $(mmu-y)
 obj-y += init-mm.o
 
 obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
mm/mmu_context.c new file +58 -0

58 lines not on this page · raw message

Signature · 7 lines
1.6.2.5

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
author maintainer
#2 lore raw

PATCH v4 1/2 mm: export use_mm/unuse_mm to modules

In reply to a message not in the archive

vhost net module wants to do copy to/from user from a kernel thread, which needs use_mm (like what fs/aio has). Move that into mm/ and export to modules.

---
 fs/aio.c                    |   47 +----------------------------------
 include/linux/mmu_context.h |    9 ++++++
 mm/Makefile                 |    2 +-
 mm/mmu_context.c            |   58 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+), 47 deletions(-)
 create mode 100644 include/linux/mmu_context.h
 create mode 100644 mm/mmu_context.c
fs/aio.c +1 -46
index d065b2c..fc21c23 100644
@@ -24,6 +24,7 @@
 #include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/mmu_context.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/aio.h>
@@ -34,7 +35,6 @@
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
-#include <asm/mmu_context.h>
 
 #if DEBUG > 1
 #define dprintk		printk
@@ -595,51 +595,6 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
 }
 
 /*
- * use_mm
- *	Makes the calling kernel thread take on the specified
- *	mm context.
- *	Called by the retry thread execute retries within the
- *	iocb issuer's mm context, so that copy_from/to_user
- *	operations work seamlessly for aio.
- *	(Note: this routine is intended to be called only
- *	from a kernel thread context)
- */
-static void use_mm(struct mm_struct *mm)
-{
-	struct mm_struct *active_mm;
-	struct task_struct *tsk = current;
-
-	task_lock(tsk);
-	active_mm = tsk->active_mm;
-	atomic_inc(&mm->mm_count);
-	tsk->mm = mm;
-	tsk->active_mm = mm;
-	switch_mm(active_mm, mm, tsk);
-	task_unlock(tsk);
-
-	mmdrop(active_mm);
-}
-
-/*
- * unuse_mm
- *	Reverses the effect of use_mm, i.e. releases the
- *	specified mm context which was earlier taken on
- *	by the calling kernel thread
- *	(Note: this routine is intended to be called only
- *	from a kernel thread context)
- */
-static void unuse_mm(struct mm_struct *mm)
-{
-	struct task_struct *tsk = current;
-
-	task_lock(tsk);
-	tsk->mm = NULL;
-	/* active_mm is still 'mm' */
-	enter_lazy_tlb(mm, tsk);
-	task_unlock(tsk);
-}
-
-/*
  * Queue up a kiocb to be retried. Assumes that the kiocb
  * has already been marked as kicked, and places it on
  * the retry run list for the corresponding ioctx, if it
include/linux/mmu_context.h new file +9 -0
new file mode 100644
index 0000000..70fffeb
@@ -0,0 +1,9 @@
+#ifndef _LINUX_MMU_CONTEXT_H
+#define _LINUX_MMU_CONTEXT_H
+
+struct mm_struct;
+
+void use_mm(struct mm_struct *mm);
+void unuse_mm(struct mm_struct *mm);
+
+#endif
mm/Makefile +1 -1
index 5e0bd64..46c3892 100644
@@ -11,7 +11,7 @@ obj-y			:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
 			   maccess.o page_alloc.o page-writeback.o pdflush.o \
 			   readahead.o swap.o truncate.o vmscan.o shmem.o \
 			   prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
-			   page_isolation.o mm_init.o $(mmu-y)
+			   page_isolation.o mm_init.o mmu_context.o $(mmu-y)
 obj-y += init-mm.o
 
 obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
mm/mmu_context.c new file +58 -0

58 lines not on this page · raw message

Signature · 1 line
1.6.2.5
author maintainer
#3 lore raw

PATCH v4 2/2 vhost_net: a kernel-level virtio server

In reply to a message not in the archive

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration)
- support memory table and not just an offset (needed for kvm)

common virtio related code has been put in a separate file vhost.c and can be made into a separate module if/when more backends appear. I used Rusty's lguest.c as the source for developing this part : this supplied me with witty comments I wouldn't be able to write myself.

What it is not: vhost net is not a bus, and not a generic new system call. No assumptions are made on how guest performs hypercalls. Userspace hypervisors are supported as well as kvm.

How it works: Basically, we connect virtio frontend (configured by userspace) to a backend. The backend could be a network device, or a tun-like device. In this version I only support raw socket as a backend, which can be bound to e.g. SR IOV, or to macvlan device. Backend is also configured by userspace, including vlan/mac etc.

Status:
This works for me, and I haven't see any crashes.
I have not run any benchmarks yet, compared to userspace, I expect to see improved latency (as I save up to 4 system calls per packet) but not bandwidth/CPU (as TSO and interrupt mitigation are not supported).

Features that I plan to look at in the future:
- TSO
- interrupt mitigation
- zero copy

---
 MAINTAINERS                |   10 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  429 ++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  664 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  108 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  100 +++++++
 11 files changed, 1328 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vhost/Kconfig
 create mode 100644 drivers/vhost/Makefile
 create mode 100644 drivers/vhost/net.c
 create mode 100644 drivers/vhost/vhost.c
 create mode 100644 drivers/vhost/vhost.h
 create mode 100644 include/linux/vhost.h
MAINTAINERS +10 -0
index b1114cf..de4587f 100644
@@ -5431,6 +5431,16 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VIRTIO HOST (VHOST)
+P:	Michael S. Tsirkin
+M:	[email protected]
+L:	[email protected]
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	drivers/vhost/
+F:	include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:	Roger Luethi <[email protected]>
 S:	Maintained
arch/x86/kvm/Kconfig +1 -0
index b84e571..94f44d9 100644
@@ -64,6 +64,7 @@ config KVM_AMD
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
drivers/Makefile +1 -0
index bc4205d..1551ae1 100644
@@ -105,6 +105,7 @@ obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_OF)		+= of/
 obj-$(CONFIG_SSB)		+= ssb/
+obj-$(CONFIG_VHOST_NET)		+= vhost/
 obj-$(CONFIG_VIRTIO)		+= virtio/
 obj-$(CONFIG_VLYNQ)		+= vlynq/
 obj-$(CONFIG_STAGING)		+= staging/
drivers/vhost/Kconfig new file +11 -0
new file mode 100644
index 0000000..d955406
@@ -0,0 +1,11 @@
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.
+
drivers/vhost/Makefile new file +2 -0
new file mode 100644
index 0000000..72dd020
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
drivers/vhost/net.c new file +429 -0

429 lines not on this page · raw message

drivers/vhost/vhost.c new file +664 -0

664 lines not on this page · raw message

drivers/vhost/vhost.h new file +108 -0

108 lines not on this page · raw message

include/linux/Kbuild +1 -0
index dec2f18..975df9a 100644
@@ -360,6 +360,7 @@ unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += utsname.h
+unifdef-y += vhost.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += virtio_config.h
include/linux/miscdevice.h +1 -0
index 0521177..781a8bb 100644
@@ -30,6 +30,7 @@
 #define HPET_MINOR		228
 #define FUSE_MINOR		229
 #define KVM_MINOR		232
+#define VHOST_NET_MINOR		233
 #define MISC_DYNAMIC_MINOR	255
 
 struct device;
include/linux/vhost.h new file +100 -0

100 lines not on this page · raw message

Signature · 7 lines
1.6.2.5

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#4 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 3 lines · Michael S. Tsirkin

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

...

drivers/vhost/Kconfig line 10

Quoted 10 lines
drivers/vhost/Kconfig new file +10 -0
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.

Just want to note that the patch explanation and the Kconfig help text are exceptional examples of reader-oriented text. Nice!

drivers/vhost/net.c line 87

Quoted 7 lines
drivers/vhost/net.c new file +7 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for TX: "
+			       "%ld expected %zd\n", vq->iov->iov_len,
+			       sizeof(struct virtio_net_hdr));
+			break;
+		}

OK, this check, which is in the qemu version, is *wrong*. There should be no assumption on sg boundaries. For example, the guest should be able to put the virtio_net_hdr in the front of the skbuf data if there is room.

You should try to explicitly "consume" sizeof(struct virtio_net_hdr) of the iov, and if fail, do this message. You can skip the out <= 1 test then, too.

Anyway, I really prefer vq->iov[0]. to vq->iov-> here.

drivers/vhost/net.c line 152

Quoted 6 lines
drivers/vhost/net.c new file +6 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for RX: "
+			       "%ld expected %zd\n",
+			       vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+			break;

Here too.

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;

drivers/vhost/net.c line 362

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci. I'd like to avoid that here, though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

	u32 feature_size;
	u32 features[];
Quoted 1 line

+int vhost_net_init(void)

static?

Quoted 1 line

+void vhost_net_exit(void)

static?

Quoted 2 lines

+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */

I experienced minor confusion from the comments in this file. Where you said "user" I think "caller". No biggie though.

drivers/vhost/vhost.c line 148

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+	memory->nregions = 2;
+	memory->regions[0].guest_phys_addr = 1;
+	memory->regions[0].userspace_addr = 1;
+	memory->regions[0].memory_size = ~0ULL;
+	memory->regions[1].guest_phys_addr = 0;
+	memory->regions[1].userspace_addr = 0;
+	memory->regions[1].memory_size = 1;

Not sure I understand why there are two regions to start?

Quoted 5 lines
drivers/vhost/vhost.c new file +5 -0
+	case VHOST_SET_VRING_BASE:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {

drivers/vhost/vhost.c line 273

Quoted 10 lines
drivers/vhost/vhost.c new file +10 -0
+			r = -EINVAL;
+			break;
+		}
+		vq->last_avail_idx = s.num;
+		break;
+	case VHOST_GET_VRING_BASE:
+		s.index = idx;
+		s.num = vq->last_avail_idx;
+		r = copy_to_user(argp, &s, sizeof s);
+		break;

Ah, this is my fault. I didn't expose the last_avail_idx in the ring because the other side doesn't need it; but without it the ring state is not fully observable from outside (no external save / restore!).

I have a patch which published these indices (we have room), see:

	http://ozlabs.org/~rusty/kernel/rr-2009-08-12-1/virtio:ring-publish-indices.patch

Perhaps we should use that mechanism instead? We don't actually have to offer the feature (we don't care about the guest state), but it's nice as documentation. I've been waiting for an excuse to use that patch.

drivers/vhost/vhost.c line 397

Quoted 12 lines
drivers/vhost/vhost.c new file +12 -0
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long r;
+
+	mutex_lock(&d->mutex);
+	if (ioctl == VHOST_SET_OWNER) {
+		r = vhost_dev_set_owner(d);
+		goto done;
+	}
+
+	r = vhost_dev_check_owner(d);

You can do a VHOST_SET_OWNER without being the owner? So really, the -EPERM from all the vhost_dev_check_owner() is not a security thing, but a "I don't think you mean to do that" thing?

If so, a comment above it might help?

drivers/vhost/vhost.c line 420

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+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 */

Ah, you actually mean "this code has been carefully cache-optimized for the common case" :)

drivers/vhost/vhost.c line 440

Quoted 11 lines
drivers/vhost/vhost.c new file +11 -0
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+		   struct iovec iov[], int iov_count, int iov_size,
+		   unsigned *num)
+{
+	const struct vhost_memory_region *reg;
+	struct vhost_memory *mem;
+	struct iovec *_iov;
+	u64 s = 0;
+	int ret = 0;

Would this be neater if it returned the num iovecs used? And offsetting iov in the caller, rather than passing iov_count?

drivers/vhost/vhost.c line 542

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	/* If their number is silly, that's a fatal mistake. */
+	if (head >= vq->num) {
+		vq_err(vq, "Guest says index %u > %u is available",
+		       head, vq->num);
+		return vq->num;
+	}

Not a fatal mistake in this code/

drivers/vhost/vhost.c line 587

Quoted 1 line
drivers/vhost/vhost.c new file +1 -0
+	vq->inflight++;

vq->inflight was a brain fart in the old lguest code. See commit ebf9a5a99c1a464afe0b4dfa64416fc8b273bc5c.

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code
lguest: clean up length-used value in example launcher

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH. It should definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

Quoted 2 lines
drivers/vhost/vhost.h new file +2 -0
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {

...

Quoted 1 line

+} ____cacheline_aligned;

Really? I'd want to see numbers on this one. False sharing vs. more cache utilization.

drivers/vhost/vhost.h line 106

Quoted 5 lines
drivers/vhost/vhost.h new file +5 -0
+#define vq_err(vq, fmt, ...) do {                                  \
+		printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+		if ((vq)->error_ctx)                               \
+				eventfd_signal((vq)->error_ctx, 1);\
+	} while (0)

Mmm... guests should not be able to create unlimited printks in the host.

But really, nothing major to object to in here...

Thanks!
Rusty.

author maintainer
#5 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Thanks for the comments, I'll work on them ASAP.
Answers to questions and more comments below.

Quoted 7 lines · Rusty Russell
Quoted 3 lines · Michael S. Tsirkin

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

...

Quoted 13 lines

drivers/vhost/Kconfig line 10

Quoted 10 lines
drivers/vhost/Kconfig new file +10 -0
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.

Just want to note that the patch explanation and the Kconfig help text are exceptional examples of reader-oriented text. Nice!

High praise indeed from the author of the lguest Quest :).

Quoted 12 lines

drivers/vhost/net.c line 87

Quoted 7 lines
drivers/vhost/net.c new file +7 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for TX: "
+			       "%ld expected %zd\n", vq->iov->iov_len,
+			       sizeof(struct virtio_net_hdr));
+			break;
+		}

OK, this check, which is in the qemu version, is *wrong*. There should be no assumption on sg boundaries. For example, the guest should be able to put the virtio_net_hdr in the front of the skbuf data if there is room.

Quoted 5 lines

You should try to explicitly "consume" sizeof(struct virtio_net_hdr) of the iov, and if fail, do this message. You can skip the out <= 1 test then, too.

Anyway, I really prefer vq->iov[0]. to vq->iov-> here.

I'll fix that. Probably should fix qemu as well.

Quoted 29 lines

drivers/vhost/net.c line 152

Quoted 6 lines
drivers/vhost/net.c new file +6 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for RX: "
+			       "%ld expected %zd\n",
+			       vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+			break;

Here too.

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;

drivers/vhost/net.c line 362

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci. I'd like to avoid that here, though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

Quoted 2 lines
	u32 feature_size;
	u32 features[];

Do you feel just making it 64 bit won't be enough? How about 128 bit?

Quoted 7 lines
Quoted 1 line

+int vhost_net_init(void)

static?

Quoted 1 line

+void vhost_net_exit(void)

static?

Good catch.

Quoted 6 lines
Quoted 2 lines

+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */

I experienced minor confusion from the comments in this file. Where you said "user" I think "caller". No biggie though.

Quoted 9 lines

drivers/vhost/vhost.c line 148

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+	memory->nregions = 2;
+	memory->regions[0].guest_phys_addr = 1;
+	memory->regions[0].userspace_addr = 1;
+	memory->regions[0].memory_size = ~0ULL;
+	memory->regions[1].guest_phys_addr = 0;
+	memory->regions[1].userspace_addr = 0;
+	memory->regions[1].memory_size = 1;

Not sure I understand why there are two regions to start?

We are trying to cover a whole 2^64 range here. It's size does not fit in a single 64 bit length value. I could special case 0 length to mean 2^64, but decided against it.

Quoted 20 lines
Quoted 5 lines
drivers/vhost/vhost.c new file +5 -0
+	case VHOST_SET_VRING_BASE:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {

drivers/vhost/vhost.c line 273

Quoted 10 lines
drivers/vhost/vhost.c new file +10 -0
+			r = -EINVAL;
+			break;
+		}
+		vq->last_avail_idx = s.num;
+		break;
+	case VHOST_GET_VRING_BASE:
+		s.index = idx;
+		s.num = vq->last_avail_idx;
+		r = copy_to_user(argp, &s, sizeof s);
+		break;

Ah, this is my fault. I didn't expose the last_avail_idx in the ring because the other side doesn't need it; but without it the ring state is not fully observable from outside (no external save / restore!).

Quoted 6 lines

I have a patch which published these indices (we have room), see:

	http://ozlabs.org/~rusty/kernel/rr-2009-08-12-1/virtio:ring-publish-indices.patch

Perhaps we should use that mechanism instead? We don't actually have to offer the feature (we don't care about the guest state), but it's nice as documentation. I've been waiting for an excuse to use that patch.

Good idea and might be handy for optimizations as well, and I would have used it if it was there. I'd like to support existing guests in vhost though, so I think we need to support this ioctl for now.

Quoted 6 lines
Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long r;
+
+	mutex_lock(&d->mutex);
Quoted 8 lines

drivers/vhost/vhost.c line 397

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	if (ioctl == VHOST_SET_OWNER) {
+		r = vhost_dev_set_owner(d);
+		goto done;
+	}
+
+	r = vhost_dev_check_owner(d);

You can do a VHOST_SET_OWNER without being the owner?

Only if no one else is the owner. It has a mutual exclusion mechanism.

Quoted 3 lines

So really,
the -EPERM from all the vhost_dev_check_owner() is not a security thing, but a "I don't think you mean to do that" thing?

Mostly that. I started by assuming that an open fd can't be passed around at all, but talking with management guys here, they really like being able to open fds and pass them around through unix domain sockets.

Since using this fd from multiple processes does not work well, I decided to make this explicit in the interface. I find it quite possible that there's no security thing here, but this is just a simpler model to think about than guessing whether some crash is exploitable or not.

Quoted 1 line

If so, a comment above it might help?

Yes.

Quoted 11 lines

drivers/vhost/vhost.c line 420

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+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 */

Ah, you actually mean "this code has been carefully cache-optimized for the common case" :)

Quoted 14 lines

drivers/vhost/vhost.c line 440

Quoted 11 lines
drivers/vhost/vhost.c new file +11 -0
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+		   struct iovec iov[], int iov_count, int iov_size,
+		   unsigned *num)
+{
+	const struct vhost_memory_region *reg;
+	struct vhost_memory *mem;
+	struct iovec *_iov;
+	u64 s = 0;
+	int ret = 0;

Would this be neater if it returned the num iovecs used? And offsetting iov in the caller, rather than passing iov_count?

iov_size would have to be tweaked instead as well.

Quoted 9 lines

drivers/vhost/vhost.c line 542

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	/* If their number is silly, that's a fatal mistake. */
+	if (head >= vq->num) {
+		vq_err(vq, "Guest says index %u > %u is available",
+		       head, vq->num);
+		return vq->num;
+	}

Not a fatal mistake in this code/

Quoted 4 lines

drivers/vhost/vhost.c line 587

Quoted 1 line
drivers/vhost/vhost.c new file +1 -0
+	vq->inflight++;

vq->inflight was a brain fart in the old lguest code. See commit ebf9a5a99c1a464afe0b4dfa64416fc8b273bc5c.

I wondered about that. OK.

Quoted 4 lines

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code
lguest: clean up length-used value in example launcher

I'll go over them, thanks!
I did look over barriers, but this is tricky stuff.

Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

Good point.

Quoted 7 lines
Quoted 2 lines
drivers/vhost/vhost.h new file +2 -0
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {

...

Quoted 1 line

+} ____cacheline_aligned;

Really? I'd want to see numbers on this one. False sharing vs. more cache utilization.

I don't yet want to focus on micro optimizations. What's your guess? That it's better without? I'll kill it then ...

Quoted 7 lines

drivers/vhost/vhost.h line 106

Quoted 5 lines
drivers/vhost/vhost.h new file +5 -0
+#define vq_err(vq, fmt, ...) do {                                  \
+		printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+		if ((vq)->error_ctx)                               \
+				eventfd_signal((vq)->error_ctx, 1);\
+	} while (0)

Mmm... guests should not be able to create unlimited printks in the host.

Yes, but handy for debugging :)
I guess I'll just make it use pr_debug instead?

Quoted 4 lines

But really, nothing major to object to in here...

Thanks!
Rusty.

author maintainer
#6 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

Quoted 6 lines

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

lguest does not do it this way though, do it?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#7 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

Quoted 8 lines
Quoted 6 lines

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

lguest does not do it this way though, do it?

Does when a patch in my current queue is applied though.

Thanks,
Rusty.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#8 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 7 lines · Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

Quoted 8 lines
Quoted 6 lines

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

lguest does not do it this way though, do it?

Does when a patch in my current queue is applied though.

Thanks,
Rusty.

author maintainer
#9 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

Quoted 6 lines

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

lguest does not do it this way though, do it?

author maintainer
#10 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell

Thanks for the comments, I'll work on them ASAP.
Answers to questions and more comments below.

Quoted 7 lines · Rusty Russell
Quoted 3 lines · Michael S. Tsirkin

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

...

Quoted 13 lines

drivers/vhost/Kconfig line 10

Quoted 10 lines
drivers/vhost/Kconfig new file +10 -0
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.

Just want to note that the patch explanation and the Kconfig help text are exceptional examples of reader-oriented text. Nice!

High praise indeed from the author of the lguest Quest :).

Quoted 12 lines

drivers/vhost/net.c line 87

Quoted 7 lines
drivers/vhost/net.c new file +7 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for TX: "
+			       "%ld expected %zd\n", vq->iov->iov_len,
+			       sizeof(struct virtio_net_hdr));
+			break;
+		}

OK, this check, which is in the qemu version, is *wrong*. There should be no assumption on sg boundaries. For example, the guest should be able to put the virtio_net_hdr in the front of the skbuf data if there is room.

Quoted 5 lines

You should try to explicitly "consume" sizeof(struct virtio_net_hdr) of the iov, and if fail, do this message. You can skip the out <= 1 test then, too.

Anyway, I really prefer vq->iov[0]. to vq->iov-> here.

I'll fix that. Probably should fix qemu as well.

Quoted 29 lines

drivers/vhost/net.c line 152

Quoted 6 lines
drivers/vhost/net.c new file +6 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for RX: "
+			       "%ld expected %zd\n",
+			       vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+			break;

Here too.

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;

drivers/vhost/net.c line 362

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci. I'd like to avoid that here, though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

Quoted 2 lines
	u32 feature_size;
	u32 features[];

Do you feel just making it 64 bit won't be enough? How about 128 bit?

Quoted 7 lines
Quoted 1 line

+int vhost_net_init(void)

static?

Quoted 1 line

+void vhost_net_exit(void)

static?

Good catch.

Quoted 6 lines
Quoted 2 lines

+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */

I experienced minor confusion from the comments in this file. Where you said "user" I think "caller". No biggie though.

Quoted 9 lines

drivers/vhost/vhost.c line 148

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+	memory->nregions = 2;
+	memory->regions[0].guest_phys_addr = 1;
+	memory->regions[0].userspace_addr = 1;
+	memory->regions[0].memory_size = ~0ULL;
+	memory->regions[1].guest_phys_addr = 0;
+	memory->regions[1].userspace_addr = 0;
+	memory->regions[1].memory_size = 1;

Not sure I understand why there are two regions to start?

We are trying to cover a whole 2^64 range here. It's size does not fit in a single 64 bit length value. I could special case 0 length to mean 2^64, but decided against it.

Quoted 20 lines
Quoted 5 lines
drivers/vhost/vhost.c new file +5 -0
+	case VHOST_SET_VRING_BASE:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {

drivers/vhost/vhost.c line 273

Quoted 10 lines
drivers/vhost/vhost.c new file +10 -0
+			r = -EINVAL;
+			break;
+		}
+		vq->last_avail_idx = s.num;
+		break;
+	case VHOST_GET_VRING_BASE:
+		s.index = idx;
+		s.num = vq->last_avail_idx;
+		r = copy_to_user(argp, &s, sizeof s);
+		break;

Ah, this is my fault. I didn't expose the last_avail_idx in the ring because the other side doesn't need it; but without it the ring state is not fully observable from outside (no external save / restore!).

Quoted 6 lines

I have a patch which published these indices (we have room), see:

	http://ozlabs.org/~rusty/kernel/rr-2009-08-12-1/virtio:ring-publish-indices.patch

Perhaps we should use that mechanism instead? We don't actually have to offer the feature (we don't care about the guest state), but it's nice as documentation. I've been waiting for an excuse to use that patch.

Good idea and might be handy for optimizations as well, and I would have used it if it was there. I'd like to support existing guests in vhost though, so I think we need to support this ioctl for now.

Quoted 6 lines
Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long r;
+
+	mutex_lock(&d->mutex);
Quoted 8 lines

drivers/vhost/vhost.c line 397

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	if (ioctl == VHOST_SET_OWNER) {
+		r = vhost_dev_set_owner(d);
+		goto done;
+	}
+
+	r = vhost_dev_check_owner(d);

You can do a VHOST_SET_OWNER without being the owner?

Only if no one else is the owner. It has a mutual exclusion mechanism.

Quoted 3 lines

So really,
the -EPERM from all the vhost_dev_check_owner() is not a security thing, but a "I don't think you mean to do that" thing?

Mostly that. I started by assuming that an open fd can't be passed around at all, but talking with management guys here, they really like being able to open fds and pass them around through unix domain sockets.

Since using this fd from multiple processes does not work well, I decided to make this explicit in the interface. I find it quite possible that there's no security thing here, but this is just a simpler model to think about than guessing whether some crash is exploitable or not.

Quoted 1 line

If so, a comment above it might help?

Yes.

Quoted 11 lines

drivers/vhost/vhost.c line 420

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+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 */

Ah, you actually mean "this code has been carefully cache-optimized for the common case" :)

Quoted 14 lines

drivers/vhost/vhost.c line 440

Quoted 11 lines
drivers/vhost/vhost.c new file +11 -0
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+		   struct iovec iov[], int iov_count, int iov_size,
+		   unsigned *num)
+{
+	const struct vhost_memory_region *reg;
+	struct vhost_memory *mem;
+	struct iovec *_iov;
+	u64 s = 0;
+	int ret = 0;

Would this be neater if it returned the num iovecs used? And offsetting iov in the caller, rather than passing iov_count?

iov_size would have to be tweaked instead as well.

Quoted 9 lines

drivers/vhost/vhost.c line 542

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	/* If their number is silly, that's a fatal mistake. */
+	if (head >= vq->num) {
+		vq_err(vq, "Guest says index %u > %u is available",
+		       head, vq->num);
+		return vq->num;
+	}

Not a fatal mistake in this code/

Quoted 4 lines

drivers/vhost/vhost.c line 587

Quoted 1 line
drivers/vhost/vhost.c new file +1 -0
+	vq->inflight++;

vq->inflight was a brain fart in the old lguest code. See commit ebf9a5a99c1a464afe0b4dfa64416fc8b273bc5c.

I wondered about that. OK.

Quoted 4 lines

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code
lguest: clean up length-used value in example launcher

I'll go over them, thanks!
I did look over barriers, but this is tricky stuff.

Quoted 5 lines

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH.

If I don't, virtio net in guest uses a timer, which might be expensive. Will need to check what this does.

Quoted 3 lines

It should
definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

Good point.

Quoted 7 lines
Quoted 2 lines
drivers/vhost/vhost.h new file +2 -0
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {

...

Quoted 1 line

+} ____cacheline_aligned;

Really? I'd want to see numbers on this one. False sharing vs. more cache utilization.

I don't yet want to focus on micro optimizations. What's your guess? That it's better without? I'll kill it then ...

Quoted 7 lines

drivers/vhost/vhost.h line 106

Quoted 5 lines
drivers/vhost/vhost.h new file +5 -0
+#define vq_err(vq, fmt, ...) do {                                  \
+		printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+		if ((vq)->error_ctx)                               \
+				eventfd_signal((vq)->error_ctx, 1);\
+	} while (0)

Mmm... guests should not be able to create unlimited printks in the host.

Yes, but handy for debugging :)
I guess I'll just make it use pr_debug instead?

Quoted 4 lines

But really, nothing major to object to in here...

Thanks!
Rusty.

author maintainer
#11 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 9 lines · Rusty Russell
Quoted 9 lines
drivers/vhost/net.c new file +9 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
Quoted 8 lines

drivers/vhost/net.c line 362

Quoted 5 lines
drivers/vhost/net.c new file +5 -0
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci.

Unlike PCI, if we ever run out of bits we can just add FEATURES_EXTENDED ioctl, no need for trickery.

Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

	u32 feature_size;
	u32 features[];

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it? Right?

Signature · 1 line
MST
maintainer
#12 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 2 lines

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Wait, the *guest*?

Maybe I misunderstood something in a major way here, but I expected the features to be negotiated between host user space (qemu) and host kernel, as well as between guest and qemu (as they are already), but never between guest and kernel.

I would certainly expect the bits to be distinct from the virtio-net feature bits. E.g. stuff like TAP frame format opposed to TCP socket frame format (length+date) is something we need to negotiate here but that the guest does not care about.

Quoted 2 lines

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it?

Can't hurt, but don't use a struct unless you think we are going to need more than 64 bits.

	Arnd <><

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author maintainer
#13 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 20 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

struct vhost_get_features2 {
	__u64 bits[2];
};
Quoted 8 lines

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 2 lines

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Wait, the *guest*?

Sorry. the userspace hypervisor.

Quoted 5 lines

Maybe I misunderstood something in a major way here, but I expected the features to be negotiated between host user space (qemu) and host kernel, as well as between guest and qemu (as they are already), but never between guest and kernel.

Yes.

Quoted 5 lines

I would certainly expect the bits to be distinct from the virtio-net feature bits. E.g. stuff like TAP frame format opposed to TCP socket frame format (length+date) is something we need to negotiate here but that the guest does not care about.

My idea is to use virtio format for things I share with virtio (e.g. mergeable buffers). Since we are a kind of transport, I thought that I will use the transport bits, that is bits 28 and up for vhost things.

Quoted 7 lines
Quoted 2 lines

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it?

Can't hurt, but don't use a struct unless you think we are going to need more than 64 bits.

	Arnd <><

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author maintainer
#14 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Arnd Bergmann
Quoted 20 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

struct vhost_get_features2 {
	__u64 bits[2];
};
Quoted 8 lines

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 2 lines

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Wait, the *guest*?

Sorry. the userspace hypervisor.

Quoted 5 lines

Maybe I misunderstood something in a major way here, but I expected the features to be negotiated between host user space (qemu) and host kernel, as well as between guest and qemu (as they are already), but never between guest and kernel.

Yes.

Quoted 5 lines

I would certainly expect the bits to be distinct from the virtio-net feature bits. E.g. stuff like TAP frame format opposed to TCP socket frame format (length+date) is something we need to negotiate here but that the guest does not care about.

My idea is to use virtio format for things I share with virtio (e.g. mergeable buffers). Since we are a kind of transport, I thought that I will use the transport bits, that is bits 28 and up for vhost things.

Quoted 7 lines
Quoted 2 lines

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it?

Can't hurt, but don't use a struct unless you think we are going to need more than 64 bits.

	Arnd <><
author maintainer
#15 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Arnd Bergmann
Quoted 17 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

Quoted 6 lines
struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

I thought so, too. Rusty, agree?

Signature · 7 lines
MST

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#16 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 26 lines · Michael S. Tsirkin
Quoted 17 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

Quoted 6 lines
struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 1 line

I thought so, too. Rusty, agree?

Yep, am convinced. Make it u64 to stop us having to do this tomorrow, then we can always extend later.

Thanks,
Rusty.

#17 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 26 lines · Michael S. Tsirkin
Quoted 17 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

Quoted 6 lines
struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 1 line

I thought so, too. Rusty, agree?

Yep, am convinced. Make it u64 to stop us having to do this tomorrow, then we can always extend later.

Thanks,
Rusty.

author maintainer
#18 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Arnd Bergmann
Quoted 17 lines · Arnd Bergmann
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

Quoted 6 lines
struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

I thought so, too. Rusty, agree?

Signature · 1 line
MST
maintainer
#19 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

      u32 feature_size;
      u32 features[];

Hmm, variable length ioctl arguments, I'd rather not go there. The ioctl infrastructure already has a length argument encoded in the ioctl number. We can use that if we need more, e.g.

/* now */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
/*
* uncomment if we run out of feature bits:

struct vhost_get_features2 {
	__u64 bits[2];
};

#define VHOST_GET_FEATURES2 _IOR(VHOST_VIRTIO, 0x00, \
struct vhost_get_features2)
*/

Quoted 2 lines

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Wait, the *guest*?

Maybe I misunderstood something in a major way here, but I expected the features to be negotiated between host user space (qemu) and host kernel, as well as between guest and qemu (as they are already), but never between guest and kernel.

I would certainly expect the bits to be distinct from the virtio-net feature bits. E.g. stuff like TAP frame format opposed to TCP socket frame format (length+date) is something we need to negotiate here but that the guest does not care about.

Quoted 2 lines

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it?

Can't hurt, but don't use a struct unless you think we are going to need more than 64 bits.

	Arnd <><
author maintainer
#20 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 9 lines · Rusty Russell
Quoted 9 lines
drivers/vhost/net.c new file +9 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
Quoted 8 lines

drivers/vhost/net.c line 362

Quoted 5 lines
drivers/vhost/net.c new file +5 -0
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci.

Unlike PCI, if we ever run out of bits we can just add FEATURES_EXTENDED ioctl, no need for trickery.

Quoted 6 lines

I'd like to avoid that here,
though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

	u32 feature_size;
	u32 features[];

Thinking about this proposal some more, how will the guest determine the size to supply the GET_FEATURES ioctl?

Since we are a bit tight in 32 bit space already, let's just use a 64 bit integer and be done with it? Right?

Signature · 1 line
MST
author maintainer
#21 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Quoted 1 line

lguest: clean up length-used value in example launcher

OK, fixing that.

Thanks!

Signature · 7 lines
MST

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#22 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 11 lines · Michael S. Tsirkin
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Yep, but x86 only :) The kernel uses a real insn if XMM/XMM2, but I don't know if userspace needs that. I just use compiler barriers.

Thanks,
Rusty.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author maintainer
#23 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

Quoted 6 lines · Rusty Russell
Quoted 5 lines · Michael S. Tsirkin
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Quoted 8 lines
Quoted 6 lines

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Yep, but x86 only :)

Okay, writes are ordered them. But mb() orders reads as well, so it'll have to have a real one IMO, even in userspace?

Quoted 5 lines

The kernel uses a real insn if XMM/XMM2, but I don't
know if userspace needs that. I just use compiler barriers.

Thanks,
Rusty.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author maintainer
#24 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 6 lines · Rusty Russell
Quoted 5 lines · Michael S. Tsirkin
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Quoted 8 lines
Quoted 6 lines

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Yep, but x86 only :)

Okay, writes are ordered them. But mb() orders reads as well, so it'll have to have a real one IMO, even in userspace?

Quoted 5 lines

The kernel uses a real insn if XMM/XMM2, but I don't
know if userspace needs that. I just use compiler barriers.

Thanks,
Rusty.

#25 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 11 lines · Michael S. Tsirkin
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Yep, but x86 only :) The kernel uses a real insn if XMM/XMM2, but I don't know if userspace needs that. I just use compiler barriers.

Thanks,
Rusty.

author maintainer
#26 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 3 lines · Rusty Russell

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code

Heh, this just gets one step closer to a real wmb. I just used the correct code from linux, so I think nothing needs to be done in vhost. Apropos this change in lguest: why is a compiler barrier sufficient? The comment says devices are run in separate threads (presumably from guest?), if so don't you need to tell CPU that there's a barrier as well?

Quoted 1 line

lguest: clean up length-used value in example launcher

OK, fixing that.

Thanks!

Signature · 1 line
MST
#27 lore raw

Re: [PATCHv4 2/2] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 3 lines · Michael S. Tsirkin

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

...

drivers/vhost/Kconfig line 10

Quoted 10 lines
drivers/vhost/Kconfig new file +10 -0
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.

Just want to note that the patch explanation and the Kconfig help text are exceptional examples of reader-oriented text. Nice!

drivers/vhost/net.c line 87

Quoted 7 lines
drivers/vhost/net.c new file +7 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for TX: "
+			       "%ld expected %zd\n", vq->iov->iov_len,
+			       sizeof(struct virtio_net_hdr));
+			break;
+		}

OK, this check, which is in the qemu version, is *wrong*. There should be no assumption on sg boundaries. For example, the guest should be able to put the virtio_net_hdr in the front of the skbuf data if there is room.

You should try to explicitly "consume" sizeof(struct virtio_net_hdr) of the iov, and if fail, do this message. You can skip the out <= 1 test then, too.

Anyway, I really prefer vq->iov[0]. to vq->iov-> here.

drivers/vhost/net.c line 152

Quoted 6 lines
drivers/vhost/net.c new file +6 -0
+		/* Sanity check */
+		if (vq->iov->iov_len != sizeof(struct virtio_net_hdr)) {
+			vq_err(vq, "Unexpected header len for RX: "
+			       "%ld expected %zd\n",
+			       vq->iov->iov_len, sizeof(struct virtio_net_hdr));
+			break;

Here too.

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	u32 __user *featurep = argp;
+	int __user *fdp = argp;
+	u32 features;
+	int fd, r;

drivers/vhost/net.c line 362

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	switch (ioctl) {
+	case VHOST_NET_SET_SOCKET:
+		r = get_user(fd, fdp);
+		if (r < 0)
+			return r;
+		return vhost_net_set_socket(n, fd);
+	case VHOST_GET_FEATURES:
+		/* No features for now */
+		features = 0;
+		return put_user(features, featurep);

We may well get more than 32 feature bits, at least for virtio_net, which will force us to do some trickery in virtio_pci. I'd like to avoid that here, though it's kind of ugly. We'd need VHOST_GET_FEATURES (and ACK) to take a struct like:

	u32 feature_size;
	u32 features[];
Quoted 1 line

+int vhost_net_init(void)

static?

Quoted 1 line

+void vhost_net_exit(void)

static?

Quoted 2 lines

+/* Start polling a file. We add ourselves to file's wait queue. The user must
+ * keep a reference to a file until after vhost_poll_stop is called. */

I experienced minor confusion from the comments in this file. Where you said "user" I think "caller". No biggie though.

drivers/vhost/vhost.c line 148

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+	memory->nregions = 2;
+	memory->regions[0].guest_phys_addr = 1;
+	memory->regions[0].userspace_addr = 1;
+	memory->regions[0].memory_size = ~0ULL;
+	memory->regions[1].guest_phys_addr = 0;
+	memory->regions[1].userspace_addr = 0;
+	memory->regions[1].memory_size = 1;

Not sure I understand why there are two regions to start?

Quoted 5 lines
drivers/vhost/vhost.c new file +5 -0
+	case VHOST_SET_VRING_BASE:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {

drivers/vhost/vhost.c line 273

Quoted 10 lines
drivers/vhost/vhost.c new file +10 -0
+			r = -EINVAL;
+			break;
+		}
+		vq->last_avail_idx = s.num;
+		break;
+	case VHOST_GET_VRING_BASE:
+		s.index = idx;
+		s.num = vq->last_avail_idx;
+		r = copy_to_user(argp, &s, sizeof s);
+		break;

Ah, this is my fault. I didn't expose the last_avail_idx in the ring because the other side doesn't need it; but without it the ring state is not fully observable from outside (no external save / restore!).

I have a patch which published these indices (we have room), see:

	http://ozlabs.org/~rusty/kernel/rr-2009-08-12-1/virtio:ring-publish-indices.patch

Perhaps we should use that mechanism instead? We don't actually have to offer the feature (we don't care about the guest state), but it's nice as documentation. I've been waiting for an excuse to use that patch.

drivers/vhost/vhost.c line 397

Quoted 12 lines
drivers/vhost/vhost.c new file +12 -0
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long r;
+
+	mutex_lock(&d->mutex);
+	if (ioctl == VHOST_SET_OWNER) {
+		r = vhost_dev_set_owner(d);
+		goto done;
+	}
+
+	r = vhost_dev_check_owner(d);

You can do a VHOST_SET_OWNER without being the owner? So really, the -EPERM from all the vhost_dev_check_owner() is not a security thing, but a "I don't think you mean to do that" thing?

If so, a comment above it might help?

drivers/vhost/vhost.c line 420

Quoted 7 lines
drivers/vhost/vhost.c new file +7 -0
+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 */

Ah, you actually mean "this code has been carefully cache-optimized for the common case" :)

drivers/vhost/vhost.c line 440

Quoted 11 lines
drivers/vhost/vhost.c new file +11 -0
+/* FIXME: this does not handle a region that spans multiple
+ * address/len pairs */
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+		   struct iovec iov[], int iov_count, int iov_size,
+		   unsigned *num)
+{
+	const struct vhost_memory_region *reg;
+	struct vhost_memory *mem;
+	struct iovec *_iov;
+	u64 s = 0;
+	int ret = 0;

Would this be neater if it returned the num iovecs used? And offsetting iov in the caller, rather than passing iov_count?

drivers/vhost/vhost.c line 542

Quoted 6 lines
drivers/vhost/vhost.c new file +6 -0
+	/* If their number is silly, that's a fatal mistake. */
+	if (head >= vq->num) {
+		vq_err(vq, "Guest says index %u > %u is available",
+		       head, vq->num);
+		return vq->num;
+	}

Not a fatal mistake in this code/

drivers/vhost/vhost.c line 587

Quoted 1 line
drivers/vhost/vhost.c new file +1 -0
+	vq->inflight++;

vq->inflight was a brain fart in the old lguest code. See commit ebf9a5a99c1a464afe0b4dfa64416fc8b273bc5c.

Also, see other fixes to the lguest launcher since then which might be relevant to this code:
lguest: get more serious about wmb() in example Launcher code
lguest: clean up length-used value in example launcher

drivers/vhost/vhost.c line 638

Quoted 3 lines
drivers/vhost/vhost.c new file +3 -0
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) && vq->inflight)
+		return;

And I wouldn't support notify on empty at all, TBH. It should definitely be conditional on the guest accepting the NOTIFY_ON_EMPTY feature.

Quoted 2 lines
drivers/vhost/vhost.h new file +2 -0
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {

...

Quoted 1 line

+} ____cacheline_aligned;

Really? I'd want to see numbers on this one. False sharing vs. more cache utilization.

drivers/vhost/vhost.h line 106

Quoted 5 lines
drivers/vhost/vhost.h new file +5 -0
+#define vq_err(vq, fmt, ...) do {                                  \
+		printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__);       \
+		if ((vq)->error_ctx)                               \
+				eventfd_signal((vq)->error_ctx, 1);\
+	} while (0)

Mmm... guests should not be able to create unlimited printks in the host.

But really, nothing major to object to in here...

Thanks!
Rusty.

author maintainer
#28 lore raw

PATCH v4 2/2 vhost_net: a kernel-level virtio server

In reply to a message not in the archive

What it is: vhost net is a character device that can be used to reduce the number of system calls involved in virtio networking. Existing virtio net code is used in the guest without modification.

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration)
- support memory table and not just an offset (needed for kvm)

common virtio related code has been put in a separate file vhost.c and can be made into a separate module if/when more backends appear. I used Rusty's lguest.c as the source for developing this part : this supplied me with witty comments I wouldn't be able to write myself.

What it is not: vhost net is not a bus, and not a generic new system call. No assumptions are made on how guest performs hypercalls. Userspace hypervisors are supported as well as kvm.

How it works: Basically, we connect virtio frontend (configured by userspace) to a backend. The backend could be a network device, or a tun-like device. In this version I only support raw socket as a backend, which can be bound to e.g. SR IOV, or to macvlan device. Backend is also configured by userspace, including vlan/mac etc.

Status:
This works for me, and I haven't see any crashes.
I have not run any benchmarks yet, compared to userspace, I expect to see improved latency (as I save up to 4 system calls per packet) but not bandwidth/CPU (as TSO and interrupt mitigation are not supported).

Features that I plan to look at in the future:
- TSO
- interrupt mitigation
- zero copy

---
 MAINTAINERS                |   10 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  429 ++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  664 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  108 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  100 +++++++
 11 files changed, 1328 insertions(+), 0 deletions(-)
 create mode 100644 drivers/vhost/Kconfig
 create mode 100644 drivers/vhost/Makefile
 create mode 100644 drivers/vhost/net.c
 create mode 100644 drivers/vhost/vhost.c
 create mode 100644 drivers/vhost/vhost.h
 create mode 100644 include/linux/vhost.h
MAINTAINERS +10 -0
index b1114cf..de4587f 100644
@@ -5431,6 +5431,16 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VIRTIO HOST (VHOST)
+P:	Michael S. Tsirkin
+M:	[email protected]
+L:	[email protected]
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	drivers/vhost/
+F:	include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:	Roger Luethi <[email protected]>
 S:	Maintained
arch/x86/kvm/Kconfig +1 -0
index b84e571..94f44d9 100644
@@ -64,6 +64,7 @@ config KVM_AMD
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
drivers/Makefile +1 -0
index bc4205d..1551ae1 100644
@@ -105,6 +105,7 @@ obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
 obj-$(CONFIG_OF)		+= of/
 obj-$(CONFIG_SSB)		+= ssb/
+obj-$(CONFIG_VHOST_NET)		+= vhost/
 obj-$(CONFIG_VIRTIO)		+= virtio/
 obj-$(CONFIG_VLYNQ)		+= vlynq/
 obj-$(CONFIG_STAGING)		+= staging/
drivers/vhost/Kconfig new file +11 -0
new file mode 100644
index 0000000..d955406
@@ -0,0 +1,11 @@
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.
+
drivers/vhost/Makefile new file +2 -0
new file mode 100644
index 0000000..72dd020
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
drivers/vhost/net.c new file +429 -0

429 lines not on this page · raw message

drivers/vhost/vhost.c new file +664 -0

664 lines not on this page · raw message

drivers/vhost/vhost.h new file +108 -0

108 lines not on this page · raw message

include/linux/Kbuild +1 -0
index dec2f18..975df9a 100644
@@ -360,6 +360,7 @@ unifdef-y += uio.h
 unifdef-y += unistd.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += utsname.h
+unifdef-y += vhost.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += virtio_config.h
include/linux/miscdevice.h +1 -0
index 0521177..781a8bb 100644
@@ -30,6 +30,7 @@
 #define HPET_MINOR		228
 #define FUSE_MINOR		229
 #define KVM_MINOR		232
+#define VHOST_NET_MINOR		233
 #define MISC_DYNAMIC_MINOR	255
 
 struct device;
include/linux/vhost.h new file +100 -0

100 lines not on this page · raw message

Signature · 1 line
1.6.2.5