Netdev List
 help / color / mirror / Atom feed
* [PATCHv7 0/3] vhost: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-03 17:23 UTC (permalink / raw)
  To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm

Rusty, ok, I think I've addressed all comments so far here.  In
particular I have added write logging for live migration, indirect
buffers and virtio net header (enables gso).  I'd like this to go
into linux-next, through your tree, and hopefully 2.6.33.
What do you think?

---

This implements vhost: a kernel-level backend for virtio,
The main motivation for this work is to reduce virtualization
overhead for virtio by removing system calls on data path,
without guest changes. For virtio-net, this removes up to
4 system calls per packet: vm exit for kick, reentry for kick,
iothread wakeup for packet, interrupt injection for packet.

This driver is pretty minimal, but it's fully functional (including
migration support interfaces), and already shows performance (especially
latency) improvement over userspace.

Some more detailed description attached to the patch itself.

The patches apply to both 2.6.32-rc5 and kvm.git.  I'd like them to go
into linux-next if possible.  Please comment.

Changelog from v6:
- review comments by Daniel Walker addressed
- checkpatch cleanup
- fix build on 32 bit
- maintainers entry corrected

Changelog from v5:
- tun support
- backends with virtio net header support (enables GSO, checksum etc)
- 32 bit compat fixed
- support indirect buffers, tx exit mitigation,
  tx interrupt mitigation
- support write logging (allows migration without virtio ring code in userspace)

Changelog from v4:
- disable rx notification when have rx buffers
- addressed all comments from Rusty's review
- copy bugfixes from lguest commits:
	ebf9a5a99c1a464afe0b4dfa64416fc8b273bc5c
	e606490c440900e50ccf73a54f6fc6150ff40815

Changelog from v3:
- checkpatch fixes

Changelog from v2:
- Comments on RCU usage
- Compat ioctl support
- Make variable static
- Copied more idiomatic english from Rusty

Changes from v1:
- Move use_mm/unuse_mm from fs/aio.c to mm instead of copying.
- Reorder code to avoid need for forward declarations
- Kill a couple of debugging printks

Michael S. Tsirkin (3):
  tun: export underlying socket
  mm: export use_mm/unuse_mm to modules
  vhost_net: a kernel-level virtio server

 MAINTAINERS                |    9 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/net/tun.c          |  101 ++++-
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  633 +++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  970 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  158 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/if_tun.h     |   14 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  126 ++++++
 mm/mmu_context.c           |    3 +
 14 files changed, 2012 insertions(+), 19 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

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

^ permalink raw reply

* [PATCHv7 1/3] tun: export underlying socket
From: Michael S. Tsirkin @ 2009-11-03 17:24 UTC (permalink / raw)
  To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <cover.1257267892.git.mst@redhat.com>

Tun device looks similar to a packet socket
in that both pass complete frames from/to userspace.

This patch fills in enough fields in the socket underlying tun driver
to support sendmsg/recvmsg operations, and message flags
MSG_TRUNC and MSG_DONTWAIT, and exports access to this socket
to modules.  Regular read/write behaviour is unchanged.

This way, code using raw sockets to inject packets
into a physical device, can support injecting
packets into host network stack almost without modification.

First user of this interface will be vhost virtualization
accelerator.

Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---

This was posted to netdev separately as well.
Assuming it's okay with davem, I think it makes sense to merge this
patch through Rusty's tree because vhost is the first user of the new
interface.  Posted here for completeness.


 drivers/net/tun.c      |  101 +++++++++++++++++++++++++++++++++++++++---------
 include/linux/if_tun.h |   14 +++++++
 2 files changed, 96 insertions(+), 19 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 4fdfa2a..18f8876 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -144,6 +144,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
 	err = 0;
 	tfile->tun = tun;
 	tun->tfile = tfile;
+	tun->socket.file = file;
 	dev_hold(tun->dev);
 	sock_hold(tun->socket.sk);
 	atomic_inc(&tfile->count);
@@ -158,6 +159,7 @@ static void __tun_detach(struct tun_struct *tun)
 	/* Detach from net device */
 	netif_tx_lock_bh(tun->dev);
 	tun->tfile = NULL;
+	tun->socket.file = NULL;
 	netif_tx_unlock_bh(tun->dev);
 
 	/* Drop read queue */
@@ -387,7 +389,8 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* Notify and wake up reader process */
 	if (tun->flags & TUN_FASYNC)
 		kill_fasync(&tun->fasync, SIGIO, POLL_IN);
-	wake_up_interruptible(&tun->socket.wait);
+	wake_up_interruptible_poll(&tun->socket.wait, POLLIN |
+				   POLLRDNORM | POLLRDBAND);
 	return NETDEV_TX_OK;
 
 drop:
@@ -743,7 +746,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 	len = min_t(int, skb->len, len);
 
 	skb_copy_datagram_const_iovec(skb, 0, iv, total, len);
-	total += len;
+	total += skb->len;
 
 	tun->dev->stats.tx_packets++;
 	tun->dev->stats.tx_bytes += len;
@@ -751,34 +754,23 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 	return total;
 }
 
-static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
-			    unsigned long count, loff_t pos)
+static ssize_t tun_do_read(struct tun_struct *tun,
+			   struct kiocb *iocb, const struct iovec *iv,
+			   ssize_t len, int noblock)
 {
-	struct file *file = iocb->ki_filp;
-	struct tun_file *tfile = file->private_data;
-	struct tun_struct *tun = __tun_get(tfile);
 	DECLARE_WAITQUEUE(wait, current);
 	struct sk_buff *skb;
-	ssize_t len, ret = 0;
-
-	if (!tun)
-		return -EBADFD;
+	ssize_t ret = 0;
 
 	DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-	len = iov_length(iv, count);
-	if (len < 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-
 	add_wait_queue(&tun->socket.wait, &wait);
 	while (len) {
 		current->state = TASK_INTERRUPTIBLE;
 
 		/* Read frames from the queue */
 		if (!(skb=skb_dequeue(&tun->socket.sk->sk_receive_queue))) {
-			if (file->f_flags & O_NONBLOCK) {
+			if (noblock) {
 				ret = -EAGAIN;
 				break;
 			}
@@ -805,6 +797,27 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
 	current->state = TASK_RUNNING;
 	remove_wait_queue(&tun->socket.wait, &wait);
 
+	return ret;
+}
+
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+			    unsigned long count, loff_t pos)
+{
+	struct file *file = iocb->ki_filp;
+	struct tun_file *tfile = file->private_data;
+	struct tun_struct *tun = __tun_get(tfile);
+	ssize_t len, ret;
+
+	if (!tun)
+		return -EBADFD;
+	len = iov_length(iv, count);
+	if (len < 0) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = tun_do_read(tun, iocb, iv, len, file->f_flags & O_NONBLOCK);
+	ret = min_t(ssize_t, ret, len);
 out:
 	tun_put(tun);
 	return ret;
@@ -847,7 +860,8 @@ static void tun_sock_write_space(struct sock *sk)
 		return;
 
 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-		wake_up_interruptible_sync(sk->sk_sleep);
+		wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+						POLLWRNORM | POLLWRBAND);
 
 	tun = container_of(sk, struct tun_sock, sk)->tun;
 	kill_fasync(&tun->fasync, SIGIO, POLL_OUT);
@@ -858,6 +872,37 @@ static void tun_sock_destruct(struct sock *sk)
 	free_netdev(container_of(sk, struct tun_sock, sk)->tun->dev);
 }
 
+static int tun_sendmsg(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *m, size_t total_len)
+{
+	struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+	return tun_get_user(tun, m->msg_iov, total_len,
+			    m->msg_flags & MSG_DONTWAIT);
+}
+
+static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *m, size_t total_len,
+		       int flags)
+{
+	struct tun_struct *tun = container_of(sock, struct tun_struct, socket);
+	int ret;
+	if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+		return -EINVAL;
+	ret = tun_do_read(tun, iocb, m->msg_iov, total_len,
+			  flags & MSG_DONTWAIT);
+	if (ret > total_len) {
+		m->msg_flags |= MSG_TRUNC;
+		ret = flags & MSG_TRUNC ? ret : total_len;
+	}
+	return ret;
+}
+
+/* Ops structure to mimic raw sockets with tun */
+static const struct proto_ops tun_socket_ops = {
+	.sendmsg = tun_sendmsg,
+	.recvmsg = tun_recvmsg,
+};
+
 static struct proto tun_proto = {
 	.name		= "tun",
 	.owner		= THIS_MODULE,
@@ -986,6 +1031,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 			goto err_free_dev;
 
 		init_waitqueue_head(&tun->socket.wait);
+		tun->socket.ops = &tun_socket_ops;
 		sock_init_data(&tun->socket, sk);
 		sk->sk_write_space = tun_sock_write_space;
 		sk->sk_sndbuf = INT_MAX;
@@ -1489,6 +1535,23 @@ static void tun_cleanup(void)
 	rtnl_link_unregister(&tun_link_ops);
 }
 
+/* Get an underlying socket object from tun file.  Returns error unless file is
+ * attached to a device.  The returned object works like a packet socket, it
+ * can be used for sock_sendmsg/sock_recvmsg.  The caller is responsible for
+ * holding a reference to the file for as long as the socket is in use. */
+struct socket *tun_get_socket(struct file *file)
+{
+	struct tun_struct *tun;
+	if (file->f_op != &tun_fops)
+		return ERR_PTR(-EINVAL);
+	tun = tun_get(file);
+	if (!tun)
+		return ERR_PTR(-EBADFD);
+	tun_put(tun);
+	return &tun->socket;
+}
+EXPORT_SYMBOL_GPL(tun_get_socket);
+
 module_init(tun_init);
 module_exit(tun_cleanup);
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 3f5fd52..404abe0 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -86,4 +86,18 @@ struct tun_filter {
 	__u8   addr[0][ETH_ALEN];
 };
 
+#ifdef __KERNEL__
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+struct socket *tun_get_socket(struct file *);
+#else
+#include <linux/err.h>
+#include <linux/errno.h>
+struct file;
+struct socket;
+static inline struct socket *tun_get_socket(struct file *f)
+{
+	return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_TUN */
+#endif /* __KERNEL__ */
 #endif /* __IF_TUN_H */
-- 
1.6.5.2.143.g8cc62

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

^ permalink raw reply related

* [PATCHv7 2/3] mm: export use_mm/unuse_mm to modules
From: Michael S. Tsirkin @ 2009-11-03 17:24 UTC (permalink / raw)
  To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <cover.1257267892.git.mst@redhat.com>

vhost net module wants to do copy to/from user from a kernel thread,
which needs use_mm. Export it to modules.

Acked-by: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 mm/mmu_context.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/mm/mmu_context.c b/mm/mmu_context.c
index ded9081..0777654 100644
--- a/mm/mmu_context.c
+++ b/mm/mmu_context.c
@@ -5,6 +5,7 @@
 
 #include <linux/mm.h>
 #include <linux/mmu_context.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 
 #include <asm/mmu_context.h>
@@ -37,6 +38,7 @@ void use_mm(struct mm_struct *mm)
 	if (active_mm != mm)
 		mmdrop(active_mm);
 }
+EXPORT_SYMBOL_GPL(use_mm);
 
 /*
  * unuse_mm
@@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm)
 	enter_lazy_tlb(mm, tsk);
 	task_unlock(tsk);
 }
+EXPORT_SYMBOL_GPL(unuse_mm);
-- 
1.6.5.2.143.g8cc62

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

^ permalink raw reply related

* [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-03 17:24 UTC (permalink / raw)
  To: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm
In-Reply-To: <cover.1257267892.git.mst@redhat.com>

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, bug work-arounds in userspace)
- write logging is supported (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 tap
device.  Backend is also configured by userspace, including vlan/mac
etc.

Status: This works for me, and I haven't see any crashes.
Compared to userspace, people reported improved latency (as I save up to
4 system calls per packet), as well as better bandwidth and CPU
utilization.

Features that I plan to look at in the future:
- mergeable buffers
- zero copy
- scalability tuning: figure out the best threading model to use

Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 MAINTAINERS                |    9 +
 arch/x86/kvm/Kconfig       |    1 +
 drivers/Makefile           |    1 +
 drivers/vhost/Kconfig      |   11 +
 drivers/vhost/Makefile     |    2 +
 drivers/vhost/net.c        |  633 +++++++++++++++++++++++++++++
 drivers/vhost/vhost.c      |  970 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/vhost/vhost.h      |  158 +++++++
 include/linux/Kbuild       |    1 +
 include/linux/miscdevice.h |    1 +
 include/linux/vhost.h      |  126 ++++++
 11 files changed, 1913 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

diff --git a/MAINTAINERS b/MAINTAINERS
index 8824115..980a69b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5619,6 +5619,15 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VIRTIO HOST (VHOST)
+M:	"Michael S. Tsirkin" <mst@redhat.com>
+L:	kvm@vger.kernel.org
+L:	virtualization@lists.osdl.org
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/vhost/
+F:	include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:	Roger Luethi <rl@hellgate.ch>
 S:	Maintained
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index b84e571..94f44d9 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -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
 
diff --git a/drivers/Makefile b/drivers/Makefile
index 6ee53c7..81e3659 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -106,6 +106,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/
diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig
new file mode 100644
index 0000000..d955406
--- /dev/null
+++ b/drivers/vhost/Kconfig
@@ -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.
+
diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile
new file mode 100644
index 0000000..72dd020
--- /dev/null
+++ b/drivers/vhost/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
new file mode 100644
index 0000000..4af3b98
--- /dev/null
+++ b/drivers/vhost/net.c
@@ -0,0 +1,633 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * virtio-net server in host kernel.
+ */
+
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mmu_context.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/file.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <linux/if_tun.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_NET_WEIGHT 0x80000
+
+enum {
+	VHOST_NET_VQ_RX = 0,
+	VHOST_NET_VQ_TX = 1,
+	VHOST_NET_VQ_MAX = 2,
+};
+
+enum vhost_net_poll_state {
+	VHOST_NET_POLL_DISABLED = 0,
+	VHOST_NET_POLL_STARTED = 1,
+	VHOST_NET_POLL_STOPPED = 2,
+};
+
+struct vhost_net {
+	struct vhost_dev dev;
+	struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
+	struct vhost_poll poll[VHOST_NET_VQ_MAX];
+	/* Tells us whether we are polling a socket for TX.
+	 * We only do this when socket buffer fills up.
+	 * Protected by tx vq lock. */
+	enum vhost_net_poll_state tx_poll_state;
+};
+
+/* Pop first len bytes from iovec. Return number of segments used. */
+static int move_iovec_hdr(struct iovec *from, struct iovec *to,
+			  size_t len, int iov_count)
+{
+	int seg = 0;
+	size_t size;
+	while (len && seg < iov_count) {
+		size = min(from->iov_len, len);
+		to->iov_base = from->iov_base;
+		to->iov_len = size;
+		from->iov_len -= size;
+		from->iov_base += size;
+		len -= size;
+		++from;
+		++to;
+		++seg;
+	}
+	return seg;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_stop(struct vhost_net *net)
+{
+	if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED))
+		return;
+	vhost_poll_stop(net->poll + VHOST_NET_VQ_TX);
+	net->tx_poll_state = VHOST_NET_POLL_STOPPED;
+}
+
+/* Caller must have TX VQ lock */
+static void tx_poll_start(struct vhost_net *net, struct socket *sock)
+{
+	if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
+		return;
+	vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
+	net->tx_poll_state = VHOST_NET_POLL_STARTED;
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_tx(struct vhost_net *net)
+{
+	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
+	unsigned head, out, in, s;
+	struct msghdr msg = {
+		.msg_name = NULL,
+		.msg_namelen = 0,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_iov = vq->iov,
+		.msg_flags = MSG_DONTWAIT,
+	};
+	size_t len, total_len = 0;
+	int err, wmem;
+	size_t hdr_size;
+	struct socket *sock = rcu_dereference(vq->private_data);
+	if (!sock)
+		return;
+
+	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+	if (wmem >= sock->sk->sk_sndbuf)
+		return;
+
+	use_mm(net->dev.mm);
+	mutex_lock(&vq->mutex);
+	vhost_no_notify(vq);
+
+	if (wmem < sock->sk->sk_sndbuf * 2)
+		tx_poll_stop(net);
+	hdr_size = vq->hdr_size;
+
+	for (;;) {
+		head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in,
+					 NULL, NULL);
+		/* Nothing new?  Wait for eventfd to tell us they refilled. */
+		if (head == vq->num) {
+			wmem = atomic_read(&sock->sk->sk_wmem_alloc);
+			if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
+				tx_poll_start(net, sock);
+				set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+				break;
+			}
+			if (vhost_notify(vq))
+				continue;
+			break;
+		}
+		if (in) {
+			vq_err(vq, "Unexpected descriptor format for TX: "
+			       "out %d, int %d\n", out, in);
+			break;
+		}
+		/* Skip header. TODO: support TSO. */
+		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, out);
+		msg.msg_iovlen = out;
+		len = iov_length(vq->iov, out);
+		/* Sanity check */
+		if (!len) {
+			vq_err(vq, "Unexpected header len for TX: "
+			       "%ld expected %zd\n",
+			       iov_length(vq->hdr, s), hdr_size);
+			break;
+		}
+		/* TODO: Check specific error and bomb out unless ENOBUFS? */
+		err = sock->ops->sendmsg(NULL, sock, &msg, len);
+		if (unlikely(err < 0)) {
+			vhost_discard_vq_desc(vq);
+			tx_poll_start(net, sock);
+			break;
+		}
+		if (err != len)
+			pr_err("Truncated TX packet: "
+			       " len %d != %zd\n", err, len);
+		vhost_add_used_and_trigger(&net->dev, vq, head, 0);
+		total_len += len;
+		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+			vhost_poll_queue(&vq->poll);
+			break;
+		}
+	}
+
+	mutex_unlock(&vq->mutex);
+	unuse_mm(net->dev.mm);
+}
+
+/* Expects to be always run from workqueue - which acts as
+ * read-size critical section for our kind of RCU. */
+static void handle_rx(struct vhost_net *net)
+{
+	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX];
+	unsigned head, out, in, log, s;
+	struct vhost_log *vq_log;
+	struct msghdr msg = {
+		.msg_name = NULL,
+		.msg_namelen = 0,
+		.msg_control = NULL, /* FIXME: get and handle RX aux data. */
+		.msg_controllen = 0,
+		.msg_iov = vq->iov,
+		.msg_flags = MSG_DONTWAIT,
+	};
+
+	struct virtio_net_hdr hdr = {
+		.flags = 0,
+		.gso_type = VIRTIO_NET_HDR_GSO_NONE
+	};
+
+	size_t len, total_len = 0;
+	int err;
+	size_t hdr_size;
+	struct socket *sock = rcu_dereference(vq->private_data);
+	if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue))
+		return;
+
+	use_mm(net->dev.mm);
+	mutex_lock(&vq->mutex);
+	vhost_no_notify(vq);
+	hdr_size = vq->hdr_size;
+
+	vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ?
+		vq->log : NULL;
+
+	for (;;) {
+		head = vhost_get_vq_desc(&net->dev, vq, vq->iov, &out, &in,
+					 vq_log, &log);
+		/* OK, now we need to know about added descriptors. */
+		if (head == vq->num && vhost_notify(vq))
+			/* They could have slipped one in as we were doing that:
+			 * check again. */
+			continue;
+		/* Nothing new?  Wait for eventfd to tell us they refilled. */
+		if (head == vq->num)
+			break;
+		/* We don't need to be notified again. */
+		vhost_no_notify(vq);
+		if (out) {
+			vq_err(vq, "Unexpected descriptor format for RX: "
+			       "out %d, int %d\n",
+			       out, in);
+			break;
+		}
+		/* Skip header. TODO: support TSO/mergeable rx buffers. */
+		s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in);
+		msg.msg_iovlen = in;
+		len = iov_length(vq->iov, in);
+		/* Sanity check */
+		if (!len) {
+			vq_err(vq, "Unexpected header len for RX: "
+			       "%zd expected %zd\n",
+			       iov_length(vq->hdr, s), hdr_size);
+			break;
+		}
+		err = sock->ops->recvmsg(NULL, sock, &msg,
+					 len, MSG_DONTWAIT | MSG_TRUNC);
+		/* TODO: Check specific error and bomb out unless EAGAIN? */
+		if (err < 0) {
+			vhost_discard_vq_desc(vq);
+			break;
+		}
+		/* TODO: Should check and handle checksum. */
+		if (err > len) {
+			pr_err("Discarded truncated rx packet: "
+			       " len %d > %zd\n", err, len);
+			vhost_discard_vq_desc(vq);
+			continue;
+		}
+		len = err;
+		err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size);
+		if (err) {
+			vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n",
+			       vq->iov->iov_base, err);
+			break;
+		}
+		len += hdr_size;
+		vhost_add_used_and_trigger(&net->dev, vq, head, len);
+		if (unlikely(vq_log))
+			vhost_log_write(vq, vq_log, log, len);
+		total_len += len;
+		if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
+			vhost_poll_queue(&vq->poll);
+			break;
+		}
+	}
+
+	mutex_unlock(&vq->mutex);
+	unuse_mm(net->dev.mm);
+}
+
+static void handle_tx_kick(struct work_struct *work)
+{
+	struct vhost_virtqueue *vq;
+	struct vhost_net *net;
+	vq = container_of(work, struct vhost_virtqueue, poll.work);
+	net = container_of(vq->dev, struct vhost_net, dev);
+	handle_tx(net);
+}
+
+static void handle_rx_kick(struct work_struct *work)
+{
+	struct vhost_virtqueue *vq;
+	struct vhost_net *net;
+	vq = container_of(work, struct vhost_virtqueue, poll.work);
+	net = container_of(vq->dev, struct vhost_net, dev);
+	handle_rx(net);
+}
+
+static void handle_tx_net(struct work_struct *work)
+{
+	struct vhost_net *net;
+	net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_TX].work);
+	handle_tx(net);
+}
+
+static void handle_rx_net(struct work_struct *work)
+{
+	struct vhost_net *net;
+	net = container_of(work, struct vhost_net, poll[VHOST_NET_VQ_RX].work);
+	handle_rx(net);
+}
+
+static int vhost_net_open(struct inode *inode, struct file *f)
+{
+	struct vhost_net *n = kzalloc(sizeof *n, GFP_KERNEL);
+	int r;
+	if (!n)
+		return -ENOMEM;
+	f->private_data = n;
+	n->vqs[VHOST_NET_VQ_TX].handle_kick = handle_tx_kick;
+	n->vqs[VHOST_NET_VQ_RX].handle_kick = handle_rx_kick;
+	r = vhost_dev_init(&n->dev, n->vqs, VHOST_NET_VQ_MAX);
+	if (r < 0) {
+		kfree(n);
+		return r;
+	}
+
+	vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT);
+	vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN);
+	n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+	return 0;
+}
+
+static void vhost_net_disable_vq(struct vhost_net *n, int index)
+{
+	if (!n->vqs[index].private_data)
+		return;
+	if (index == VHOST_NET_VQ_TX) {
+		tx_poll_stop(n);
+		n->tx_poll_state = VHOST_NET_POLL_DISABLED;
+	} else
+		vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_enable_vq(struct vhost_net *n, int index)
+{
+	struct socket *sock = n->vqs[index].private_data;
+	if (!sock)
+		return;
+	if (index == VHOST_NET_VQ_TX) {
+		n->tx_poll_state = VHOST_NET_POLL_STOPPED;
+		tx_poll_start(n, sock);
+	} else
+		vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+}
+
+static struct socket *vhost_net_stop_vq(struct vhost_net *n, int index)
+{
+	struct socket *sock;
+
+	mutex_lock(&n->vqs[index].mutex);
+	sock = n->vqs[index].private_data;
+	vhost_net_disable_vq(n, index);
+	rcu_assign_pointer(n->vqs[index].private_data, NULL);
+	mutex_unlock(&n->vqs[index].mutex);
+	return sock;
+}
+
+static void vhost_net_stop(struct vhost_net *n, struct socket **tx_sock,
+			   struct socket **rx_sock)
+{
+	*tx_sock = vhost_net_stop_vq(n, VHOST_NET_VQ_TX);
+	*rx_sock = vhost_net_stop_vq(n, VHOST_NET_VQ_RX);
+}
+
+static void vhost_net_flush_vq(struct vhost_net *n, int index)
+{
+	vhost_poll_flush(n->poll + index);
+	vhost_poll_flush(&n->dev.vqs[index].poll);
+}
+
+static void vhost_net_flush(struct vhost_net *n)
+{
+	vhost_net_flush_vq(n, VHOST_NET_VQ_TX);
+	vhost_net_flush_vq(n, VHOST_NET_VQ_RX);
+}
+
+static int vhost_net_release(struct inode *inode, struct file *f)
+{
+	struct vhost_net *n = f->private_data;
+	struct socket *tx_sock;
+	struct socket *rx_sock;
+
+	vhost_net_stop(n, &tx_sock, &rx_sock);
+	vhost_net_flush(n);
+	vhost_dev_cleanup(&n->dev);
+	if (tx_sock)
+		fput(tx_sock->file);
+	if (rx_sock)
+		fput(rx_sock->file);
+	/* We do an extra flush before freeing memory,
+	 * since jobs can re-queue themselves. */
+	vhost_net_flush(n);
+	kfree(n);
+	return 0;
+}
+
+static struct socket *get_raw_socket(int fd)
+{
+	struct {
+		struct sockaddr_ll sa;
+		char  buf[MAX_ADDR_LEN];
+	} uaddr;
+	int uaddr_len = sizeof uaddr, r;
+	struct socket *sock = sockfd_lookup(fd, &r);
+	if (!sock)
+		return ERR_PTR(-ENOTSOCK);
+
+	/* Parameter checking */
+	if (sock->sk->sk_type != SOCK_RAW) {
+		r = -ESOCKTNOSUPPORT;
+		goto err;
+	}
+
+	r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa,
+			       &uaddr_len, 0);
+	if (r)
+		goto err;
+
+	if (uaddr.sa.sll_family != AF_PACKET) {
+		r = -EPFNOSUPPORT;
+		goto err;
+	}
+	return sock;
+err:
+	fput(sock->file);
+	return ERR_PTR(r);
+}
+
+static struct socket *get_tun_socket(int fd)
+{
+	struct file *file = fget(fd);
+	struct socket *sock;
+	if (!file)
+		return ERR_PTR(-EBADF);
+	sock = tun_get_socket(file);
+	if (IS_ERR(sock))
+		fput(file);
+	return sock;
+}
+
+static struct socket *get_socket(int fd)
+{
+	struct socket *sock;
+	if (fd == -1)
+		return NULL;
+	sock = get_raw_socket(fd);
+	if (!IS_ERR(sock))
+		return sock;
+	sock = get_tun_socket(fd);
+	if (!IS_ERR(sock))
+		return sock;
+	return ERR_PTR(-ENOTSOCK);
+}
+
+static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
+{
+	struct socket *sock, *oldsock = NULL;
+	struct vhost_virtqueue *vq;
+	int r;
+
+	mutex_lock(&n->dev.mutex);
+	r = vhost_dev_check_owner(&n->dev);
+	if (r)
+		goto done;
+
+	if (index >= VHOST_NET_VQ_MAX) {
+		r = -ENOBUFS;
+		goto done;
+	}
+	vq = n->vqs + index;
+	mutex_lock(&vq->mutex);
+	sock = get_socket(fd);
+	if (IS_ERR(sock)) {
+		r = PTR_ERR(sock);
+		goto done;
+	}
+
+	/* start polling new socket */
+	oldsock = vq->private_data;
+	if (sock == oldsock)
+		goto done;
+
+	vhost_net_disable_vq(n, index);
+	rcu_assign_pointer(vq->private_data, sock);
+	vhost_net_enable_vq(n, index);
+	mutex_unlock(&vq->mutex);
+done:
+	mutex_unlock(&n->dev.mutex);
+	if (oldsock) {
+		vhost_net_flush_vq(n, index);
+		fput(oldsock->file);
+	}
+	return r;
+}
+
+static long vhost_net_reset_owner(struct vhost_net *n)
+{
+	struct socket *tx_sock = NULL;
+	struct socket *rx_sock = NULL;
+	long r;
+	mutex_lock(&n->dev.mutex);
+	r = vhost_dev_check_owner(&n->dev);
+	if (r)
+		goto done;
+	vhost_net_stop(n, &tx_sock, &rx_sock);
+	vhost_net_flush(n);
+	r = vhost_dev_reset_owner(&n->dev);
+done:
+	mutex_unlock(&n->dev.mutex);
+	if (tx_sock)
+		fput(tx_sock->file);
+	if (rx_sock)
+		fput(rx_sock->file);
+	return r;
+}
+
+static void vhost_net_set_features(struct vhost_net *n, u64 features)
+{
+	size_t hdr_size = features & (1 << VHOST_NET_F_VIRTIO_NET_HDR) ?
+		sizeof(struct virtio_net_hdr) : 0;
+	int i;
+	mutex_unlock(&n->dev.mutex);
+	n->dev.acked_features = features;
+	smp_wmb();
+	for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
+		mutex_lock(&n->vqs[i].mutex);
+		n->vqs[i].hdr_size = hdr_size;
+		mutex_unlock(&n->vqs[i].mutex);
+	}
+	mutex_unlock(&n->dev.mutex);
+	vhost_net_flush(n);
+}
+
+static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
+			    unsigned long arg)
+{
+	struct vhost_net *n = f->private_data;
+	void __user *argp = (void __user *)arg;
+	u32 __user *featurep = argp;
+	struct vhost_vring_file backend;
+	u64 features;
+	int r;
+	switch (ioctl) {
+	case VHOST_NET_SET_BACKEND:
+		r = copy_from_user(&backend, argp, sizeof backend);
+		if (r < 0)
+			return r;
+		return vhost_net_set_backend(n, backend.index, backend.fd);
+	case VHOST_GET_FEATURES:
+		features = VHOST_FEATURES;
+		return put_user(features, featurep);
+	case VHOST_ACK_FEATURES:
+		r = get_user(features, featurep);
+		/* No features for now */
+		if (r < 0)
+			return r;
+		if (features & ~VHOST_FEATURES)
+			return -EOPNOTSUPP;
+		vhost_net_set_features(n, features);
+		return 0;
+	case VHOST_RESET_OWNER:
+		return vhost_net_reset_owner(n);
+	default:
+		r = vhost_dev_ioctl(&n->dev, ioctl, arg);
+		vhost_net_flush(n);
+		return r;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
+				   unsigned long arg)
+{
+	return vhost_net_ioctl(f, ioctl, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+const static struct file_operations vhost_net_fops = {
+	.owner          = THIS_MODULE,
+	.release        = vhost_net_release,
+	.unlocked_ioctl = vhost_net_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = vhost_net_compat_ioctl,
+#endif
+	.open           = vhost_net_open,
+};
+
+static struct miscdevice vhost_net_misc = {
+	VHOST_NET_MINOR,
+	"vhost-net",
+	&vhost_net_fops,
+};
+
+int vhost_net_init(void)
+{
+	int r = vhost_init();
+	if (r)
+		goto err_init;
+	r = misc_register(&vhost_net_misc);
+	if (r)
+		goto err_reg;
+	return 0;
+err_reg:
+	vhost_cleanup();
+err_init:
+	return r;
+
+}
+module_init(vhost_net_init);
+
+void vhost_net_exit(void)
+{
+	misc_deregister(&vhost_net_misc);
+	vhost_cleanup();
+}
+module_exit(vhost_net_exit);
+
+MODULE_VERSION("0.0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael S. Tsirkin");
+MODULE_DESCRIPTION("Host kernel accelerator for virtio net");
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
new file mode 100644
index 0000000..9e2ecc3
--- /dev/null
+++ b/drivers/vhost/vhost.c
@@ -0,0 +1,970 @@
+/* Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Generic code for virtio server in host kernel.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/rcupdate.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/highmem.h>
+
+#include <linux/net.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+
+#include <net/sock.h>
+
+#include "vhost.h"
+
+enum {
+	VHOST_MEMORY_MAX_NREGIONS = 64,
+	VHOST_MEMORY_F_LOG = 0x1,
+};
+
+static struct workqueue_struct *vhost_workqueue;
+
+static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
+			    poll_table *pt)
+{
+	struct vhost_poll *poll;
+	poll = container_of(pt, struct vhost_poll, table);
+
+	poll->wqh = wqh;
+	add_wait_queue(wqh, &poll->wait);
+}
+
+static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync,
+			     void *key)
+{
+	struct vhost_poll *poll;
+	poll = container_of(wait, struct vhost_poll, wait);
+	if (!((unsigned long)key & poll->mask))
+		return 0;
+
+	queue_work(vhost_workqueue, &poll->work);
+	return 0;
+}
+
+/* Init poll structure */
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+		     unsigned long mask)
+{
+	INIT_WORK(&poll->work, func);
+	init_waitqueue_func_entry(&poll->wait, vhost_poll_wakeup);
+	init_poll_funcptr(&poll->table, vhost_poll_func);
+	poll->mask = mask;
+}
+
+/* Start polling a file. We add ourselves to file's wait queue. The caller must
+ * keep a reference to a file until after vhost_poll_stop is called. */
+void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+{
+	unsigned long mask;
+	mask = file->f_op->poll(file, &poll->table);
+	if (mask)
+		vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+}
+
+/* Stop polling a file. After this function returns, it becomes safe to drop the
+ * file reference. You must also flush afterwards. */
+void vhost_poll_stop(struct vhost_poll *poll)
+{
+	remove_wait_queue(poll->wqh, &poll->wait);
+}
+
+/* Flush any work that has been scheduled. When calling this, don't hold any
+ * locks that are also used by the callback. */
+void vhost_poll_flush(struct vhost_poll *poll)
+{
+	flush_work(&poll->work);
+}
+
+void vhost_poll_queue(struct vhost_poll *poll)
+{
+	queue_work(vhost_workqueue, &poll->work);
+}
+
+long vhost_dev_init(struct vhost_dev *dev,
+		    struct vhost_virtqueue *vqs, int nvqs)
+{
+	int i;
+	dev->vqs = vqs;
+	dev->nvqs = nvqs;
+	mutex_init(&dev->mutex);
+
+	for (i = 0; i < dev->nvqs; ++i) {
+		dev->vqs[i].dev = dev;
+		mutex_init(&dev->vqs[i].mutex);
+		if (dev->vqs[i].handle_kick)
+			vhost_poll_init(&dev->vqs[i].poll,
+					dev->vqs[i].handle_kick,
+					POLLIN);
+	}
+	return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_check_owner(struct vhost_dev *dev)
+{
+	/* Are you the owner? If not, I don't think you mean to do that */
+	return dev->mm == current->mm ? 0 : -EPERM;
+}
+
+/* Caller should have device mutex */
+static long vhost_dev_set_owner(struct vhost_dev *dev)
+{
+	/* Is there an owner already? */
+	if (dev->mm)
+		return -EBUSY;
+	/* No owner, become one */
+	dev->mm = get_task_mm(current);
+	return 0;
+}
+
+/* Caller should have device mutex */
+long vhost_dev_reset_owner(struct vhost_dev *dev)
+{
+	struct vhost_memory *memory;
+
+	/* Restore memory to default 1:1 mapping. */
+	memory = kzalloc(offsetof(struct vhost_memory, regions) +
+			 2 * sizeof *memory->regions, GFP_KERNEL);
+	if (!memory)
+		return -ENOMEM;
+
+	vhost_dev_cleanup(dev);
+
+	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;
+	dev->memory = memory;
+	return 0;
+}
+
+/* Caller should have device mutex */
+void vhost_dev_cleanup(struct vhost_dev *dev)
+{
+	int i;
+	for (i = 0; i < dev->nvqs; ++i) {
+		if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
+			vhost_poll_stop(&dev->vqs[i].poll);
+			vhost_poll_flush(&dev->vqs[i].poll);
+		}
+		if (dev->vqs[i].error_ctx)
+			eventfd_ctx_put(dev->vqs[i].error_ctx);
+		if (dev->vqs[i].error)
+			fput(dev->vqs[i].error);
+		if (dev->vqs[i].kick)
+			fput(dev->vqs[i].kick);
+		if (dev->vqs[i].call_ctx)
+			eventfd_ctx_put(dev->vqs[i].call_ctx);
+		if (dev->vqs[i].call)
+			fput(dev->vqs[i].call);
+		dev->vqs[i].error_ctx = NULL;
+		dev->vqs[i].error = NULL;
+		dev->vqs[i].kick = NULL;
+		dev->vqs[i].call_ctx = NULL;
+		dev->vqs[i].call = NULL;
+	}
+	if (dev->log_ctx)
+		eventfd_ctx_put(dev->log_ctx);
+	dev->log_ctx = NULL;
+	if (dev->log_file)
+		fput(dev->log_file);
+	dev->log_file = NULL;
+	/* No one will access memory at this point */
+	kfree(dev->memory);
+	dev->memory = NULL;
+	if (dev->mm)
+		mmput(dev->mm);
+	dev->mm = NULL;
+}
+
+static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
+{
+	struct vhost_memory mem, *newmem, *oldmem;
+	unsigned long size = offsetof(struct vhost_memory, regions);
+	long r;
+	r = copy_from_user(&mem, m, size);
+	if (r)
+		return r;
+	if (mem.padding)
+		return -EOPNOTSUPP;
+	if (mem.nregions > VHOST_MEMORY_MAX_NREGIONS)
+		return -E2BIG;
+	newmem = kmalloc(size + mem.nregions * sizeof *m->regions, GFP_KERNEL);
+	if (!newmem)
+		return -ENOMEM;
+
+	memcpy(newmem, &mem, size);
+	r = copy_from_user(newmem->regions, m->regions,
+			   mem.nregions * sizeof *m->regions);
+	if (r) {
+		kfree(newmem);
+		return r;
+	}
+	oldmem = d->memory;
+	rcu_assign_pointer(d->memory, newmem);
+	synchronize_rcu();
+	kfree(oldmem);
+	return 0;
+}
+
+static int init_used(struct vhost_virtqueue *vq)
+{
+	int r = put_user(vq->used_flags, &vq->used->flags);
+	if (r)
+		return r;
+	return get_user(vq->last_used_idx, &vq->used->idx);
+}
+
+static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
+{
+	struct file *eventfp, *filep = NULL,
+		    *pollstart = NULL, *pollstop = NULL;
+	struct eventfd_ctx *ctx = NULL;
+	u32 __user *idxp = argp;
+	struct vhost_virtqueue *vq;
+	struct vhost_vring_state s;
+	struct vhost_vring_file f;
+	struct vhost_vring_addr a;
+	u32 idx;
+	long r;
+
+	r = get_user(idx, idxp);
+	if (r < 0)
+		return r;
+	if (idx > d->nvqs)
+		return -ENOBUFS;
+
+	vq = d->vqs + idx;
+
+	mutex_lock(&vq->mutex);
+
+	switch (ioctl) {
+	case VHOST_SET_VRING_NUM:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {
+			r = -EINVAL;
+			break;
+		}
+		vq->num = s.num;
+		break;
+	case VHOST_SET_VRING_BASE:
+		r = copy_from_user(&s, argp, sizeof s);
+		if (r < 0)
+			break;
+		if (s.num > 0xffff) {
+			r = -EINVAL;
+			break;
+		}
+		vq->avail_idx = 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;
+	case VHOST_SET_VRING_DESC:
+		r = copy_from_user(&a, argp, sizeof a);
+		if (r < 0)
+			break;
+		if (a.padding) {
+			r = -EOPNOTSUPP;
+			break;
+		}
+		if ((u64)(unsigned long)a.user_addr != a.user_addr) {
+			r = -EFAULT;
+			break;
+		}
+		vq->desc = (void __user *)(unsigned long)a.user_addr;
+		break;
+	case VHOST_SET_VRING_AVAIL:
+		r = copy_from_user(&a, argp, sizeof a);
+		if (r < 0)
+			break;
+		if (a.padding) {
+			r = -EOPNOTSUPP;
+			break;
+		}
+		if ((u64)(unsigned long)a.user_addr != a.user_addr) {
+			r = -EFAULT;
+			break;
+		}
+		if (a.user_addr & (sizeof *vq->avail->ring - 1)) {
+			r = -EINVAL;
+			break;
+		}
+		vq->avail = (void __user *)(unsigned long)a.user_addr;
+		/* Forget the cached index value. */
+		vq->avail_idx = vq->last_avail_idx;
+		break;
+	case VHOST_SET_VRING_USED:
+		r = copy_from_user(&a, argp, sizeof a);
+		if (r < 0)
+			break;
+		if (a.padding) {
+			r = -EOPNOTSUPP;
+			break;
+		}
+		if ((u64)(unsigned long)a.user_addr != a.user_addr) {
+			r = -EFAULT;
+			break;
+		}
+		if (a.user_addr & (sizeof *vq->used->ring - 1)) {
+			r = -EINVAL;
+			break;
+		}
+		vq->used = (void __user *)(unsigned long)a.user_addr;
+		r = init_used(vq);
+		if (r)
+			break;
+		break;
+	case VHOST_SET_VRING_LOG:
+		r = copy_from_user(&a, argp, sizeof a);
+		if (r < 0)
+			break;
+		if (a.padding) {
+			r = -EOPNOTSUPP;
+			break;
+		}
+		if (a.user_addr == VHOST_VRING_LOG_DISABLE) {
+			vq->log_used = false;
+			break;
+		}
+		if (a.user_addr & (sizeof *vq->used->ring - 1)) {
+			r = -EINVAL;
+			break;
+		}
+		vq->log_used = true;
+		vq->log_addr = a.user_addr;
+		break;
+	case VHOST_SET_VRING_KICK:
+		r = copy_from_user(&f, argp, sizeof f);
+		if (r < 0)
+			break;
+		eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+		if (IS_ERR(eventfp))
+			return PTR_ERR(eventfp);
+		if (eventfp != vq->kick) {
+			pollstop = filep = vq->kick;
+			pollstart = vq->kick = eventfp;
+		} else
+			filep = eventfp;
+		break;
+	case VHOST_SET_VRING_CALL:
+		r = copy_from_user(&f, argp, sizeof f);
+		if (r < 0)
+			break;
+		eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+		if (IS_ERR(eventfp))
+			return PTR_ERR(eventfp);
+		if (eventfp != vq->call) {
+			filep = vq->call;
+			ctx = vq->call_ctx;
+			vq->call = eventfp;
+			vq->call_ctx = eventfp ?
+				eventfd_ctx_fileget(eventfp) : NULL;
+		} else
+			filep = eventfp;
+		break;
+	case VHOST_SET_VRING_ERR:
+		r = copy_from_user(&f, argp, sizeof f);
+		if (r < 0)
+			break;
+		eventfp = f.fd == -1 ? NULL : eventfd_fget(f.fd);
+		if (IS_ERR(eventfp))
+			return PTR_ERR(eventfp);
+		if (eventfp != vq->error) {
+			filep = vq->error;
+			vq->error = eventfp;
+			ctx = vq->error_ctx;
+			vq->error_ctx = eventfp ?
+				eventfd_ctx_fileget(eventfp) : NULL;
+		} else
+			filep = eventfp;
+		break;
+	default:
+		r = -ENOIOCTLCMD;
+	}
+
+	if (pollstop && vq->handle_kick)
+		vhost_poll_stop(&vq->poll);
+
+	if (ctx)
+		eventfd_ctx_put(ctx);
+	if (filep)
+		fput(filep);
+
+	if (pollstart && vq->handle_kick)
+		vhost_poll_start(&vq->poll, vq->kick);
+
+	mutex_unlock(&vq->mutex);
+
+	if (pollstop && vq->handle_kick)
+		vhost_poll_flush(&vq->poll);
+	return r;
+}
+
+long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct file *eventfp, *filep = NULL;
+	struct eventfd_ctx *ctx = NULL;
+	u64 p;
+	long r;
+	int i, fd;
+
+	mutex_lock(&d->mutex);
+	/* If you are not the owner, you can become one */
+	if (ioctl == VHOST_SET_OWNER) {
+		r = vhost_dev_set_owner(d);
+		goto done;
+	}
+
+	/* You must be the owner to do anything else */
+	r = vhost_dev_check_owner(d);
+	if (r)
+		goto done;
+
+	switch (ioctl) {
+	case VHOST_SET_MEM_TABLE:
+		r = vhost_set_memory(d, argp);
+		break;
+	case VHOST_SET_LOG_BASE:
+		r = get_user(p, (u64 __user *)argp);
+		if (r < 0)
+			break;
+		if ((u64)(unsigned long)p != p) {
+			r = -EFAULT;
+			break;
+		}
+		for (i = 0; i < d->nvqs; ++i) {
+			mutex_lock(&d->vqs[i].mutex);
+			d->vqs[i].log_base = (void __user *)(unsigned long)p;
+			mutex_unlock(&d->vqs[i].mutex);
+		}
+		break;
+	case VHOST_SET_LOG_FD:
+		r = get_user(fd, (int __user *)argp);
+		if (r < 0)
+			break;
+		eventfp = fd == -1 ? NULL : eventfd_fget(fd);
+		if (IS_ERR(eventfp)) {
+			r = PTR_ERR(eventfp);
+			break;
+		}
+		if (eventfp != d->log_file) {
+			filep = d->log_file;
+			ctx = d->log_ctx;
+			d->log_ctx = eventfp ?
+				eventfd_ctx_fileget(eventfp) : NULL;
+		} else
+			filep = eventfp;
+		for (i = 0; i < d->nvqs; ++i) {
+			mutex_lock(&d->vqs[i].mutex);
+			d->vqs[i].log_ctx = d->log_ctx;
+			mutex_unlock(&d->vqs[i].mutex);
+		}
+		if (ctx)
+			eventfd_ctx_put(ctx);
+		if (filep)
+			fput(filep);
+		break;
+	default:
+		r = vhost_set_vring(d, ioctl, argp);
+		break;
+	}
+done:
+	mutex_unlock(&d->mutex);
+	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.
+ */
+static int set_bit_to_user(int nr, void __user *addr)
+{
+	unsigned long log = (unsigned long)addr;
+	struct page *page;
+	void *base;
+	int bit = nr + (log % PAGE_SIZE) * 8;
+	int r;
+	r = get_user_pages_fast(log, 1, 1, &page);
+	if (r)
+		return r;
+	base = kmap_atomic(page, KM_USER0);
+	set_bit(bit, base);
+	kunmap_atomic(base, KM_USER0);
+	set_page_dirty_lock(page);
+	put_page(page);
+	return 0;
+}
+
+static int log_write(void __user *log_base,
+		     u64 write_address, u64 write_length)
+{
+	int r;
+	if (!write_length)
+		return 0;
+	write_address /= VHOST_PAGE_SIZE;
+	for (;;) {
+		u64 base = (u64)log_base;
+		u64 log = base + write_address / 8;
+		int bit = write_address % 8;
+		if ((u64)(unsigned long)log != log)
+			return -EFAULT;
+		r = set_bit_to_user(bit, (void __user *)log);
+		if (r < 0)
+			return r;
+		if (write_length <= VHOST_PAGE_SIZE)
+			break;
+		write_length -= VHOST_PAGE_SIZE;
+		write_address += VHOST_PAGE_SIZE;
+	}
+	return r;
+}
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+		    unsigned int log_num, u64 len)
+{
+	int i, r;
+
+	/* Make sure data written is seen before log. */
+	wmb();
+	for (i = 0; i < log_num; ++i) {
+		u64 l = min(log[i].len, len);
+		r = log_write(vq->log_base, log[i].addr, l);
+		if (r < 0)
+			return r;
+		len -= l;
+		if (!len)
+			return 0;
+	}
+	if (vq->log_ctx)
+		eventfd_signal(vq->log_ctx, 1);
+	/* Length written exceeds what we have stored. This is a bug. */
+	BUG();
+	return 0;
+}
+
+int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
+		   struct iovec iov[], int iov_size)
+{
+	const struct vhost_memory_region *reg;
+	struct vhost_memory *mem;
+	struct iovec *_iov;
+	u64 s = 0;
+	int ret = 0;
+
+	rcu_read_lock();
+
+	mem = rcu_dereference(dev->memory);
+	while ((u64)len > s) {
+		u64 size;
+		if (ret >= iov_size) {
+			ret = -ENOBUFS;
+			break;
+		}
+		reg = find_region(mem, addr, len);
+		if (!reg) {
+			ret = -EFAULT;
+			break;
+		}
+		_iov = iov + ret;
+		size = reg->memory_size - addr + reg->guest_phys_addr;
+		_iov->iov_len = min((u64)len, size);
+		_iov->iov_base = (void *)
+			(reg->userspace_addr + addr - reg->guest_phys_addr);
+		s += size;
+		addr += size;
+		++ret;
+	}
+
+	rcu_read_unlock();
+	return ret;
+}
+
+/* Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain,
+ * or -1 if we're at the end. */
+static unsigned next_desc(struct vring_desc *desc)
+{
+	unsigned int next;
+
+	/* If this descriptor says it doesn't chain, we're done. */
+	if (!(desc->flags & VRING_DESC_F_NEXT))
+		return -1;
+
+	/* Check they're not leading us off end of descriptors. */
+	next = desc->next;
+	/* Make sure compiler knows to grab that: we don't want it changing! */
+	/* We will use the result as an index in an array, so most
+	 * architectures only need a compiler barrier here. */
+	read_barrier_depends();
+
+	return next;
+}
+
+static unsigned get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+			     struct iovec iov[],
+			     unsigned int *out_num, unsigned int *in_num,
+			     struct vhost_log *log, unsigned int *log_num,
+			     struct vring_desc *indirect)
+{
+	struct vring_desc desc;
+	unsigned int i = 0, count, found = 0;
+	int ret;
+
+	/* Sanity check */
+	if (indirect->len % sizeof desc) {
+		vq_err(vq, "Invalid length in indirect descriptor: "
+		       "len 0x%llx not multiple of 0x%zx\n",
+		       (unsigned long long)indirect->len,
+		       sizeof desc);
+		return -EINVAL;
+	}
+
+	ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
+			     ARRAY_SIZE(vq->indirect));
+	if (ret < 0) {
+		vq_err(vq, "Translation failure %d in indirect.\n", ret);
+		return ret;
+	}
+
+	/* We will use the result as an address to read from, so most
+	 * architectures only need a compiler barrier here. */
+	read_barrier_depends();
+
+	count = indirect->len / sizeof desc;
+	/* Buffers are chained via a 16 bit next field, so
+	 * we can have at most 2^16 of these. */
+	if (count > USHORT_MAX + 1) {
+		vq_err(vq, "Indirect buffer length too big: %d\n",
+		       indirect->len);
+		return -E2BIG;
+	}
+
+	do {
+		unsigned iov_count = *in_num + *out_num;
+		if (++found > count) {
+			vq_err(vq, "Loop detected: last one at %u "
+			       "indirect size %u\n",
+			       i, count);
+			return -EINVAL;
+		}
+		if (memcpy_fromiovec((unsigned char *)&desc, vq->indirect,
+				     sizeof desc)) {
+			vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
+			       i, (size_t)indirect->addr + i * sizeof desc);
+			return -EINVAL;
+		}
+		if (desc.flags & VRING_DESC_F_INDIRECT) {
+			vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",
+			       i, (size_t)indirect->addr + i * sizeof desc);
+			return -EINVAL;
+		}
+
+		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+				     VHOST_NET_MAX_SG - iov_count);
+		if (ret < 0) {
+			vq_err(vq, "Translation failure %d indirect idx %d\n",
+			       ret, i);
+			return ret;
+		}
+		/* If this is an input descriptor, increment that count. */
+		if (desc.flags & VRING_DESC_F_WRITE) {
+			*in_num += ret;
+			if (unlikely(log)) {
+				log[*log_num].addr = desc.addr;
+				log[*log_num].len = desc.len;
+				++*log_num;
+			}
+		} else {
+			/* If it's an output descriptor, they're all supposed
+			 * to come before any input descriptors. */
+			if (*in_num) {
+				vq_err(vq, "Indirect descriptor "
+				       "has out after in: idx %d\n", i);
+				return -EINVAL;
+			}
+			*out_num += ret;
+		}
+	} while ((i = next_desc(&desc)) != -1);
+	return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which
+ * is never a valid descriptor number) if none was found. */
+unsigned vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
+			   struct iovec iov[],
+			   unsigned int *out_num, unsigned int *in_num,
+			   struct vhost_log *log, unsigned int *log_num)
+{
+	struct vring_desc desc;
+	unsigned int i, head, found = 0;
+	u16 last_avail_idx;
+	int ret;
+
+	/* Check it isn't doing very strange things with descriptor numbers. */
+	last_avail_idx = vq->last_avail_idx;
+	if (get_user(vq->avail_idx, &vq->avail->idx)) {
+		vq_err(vq, "Failed to access avail idx at %p\n",
+		       &vq->avail->idx);
+		return vq->num;
+	}
+
+	if ((u16)(vq->avail_idx - last_avail_idx) > vq->num) {
+		vq_err(vq, "Guest moved used index from %u to %u",
+		       last_avail_idx, vq->avail_idx);
+		return vq->num;
+	}
+
+	/* If there's nothing new since last we looked, return invalid. */
+	if (vq->avail_idx == last_avail_idx)
+		return vq->num;
+
+	/* Only get avail ring entries after they have been exposed by guest. */
+	rmb();
+
+	/* Grab the next descriptor number they're advertising, and increment
+	 * the index we've seen. */
+	if (get_user(head, &vq->avail->ring[last_avail_idx % vq->num])) {
+		vq_err(vq, "Failed to read head: idx %d address %p\n",
+		       last_avail_idx,
+		       &vq->avail->ring[last_avail_idx % vq->num]);
+		return vq->num;
+	}
+
+	/* If their number is silly, that's an error. */
+	if (head >= vq->num) {
+		vq_err(vq, "Guest says index %u > %u is available",
+		       head, vq->num);
+		return vq->num;
+	}
+
+	/* When we start there are none of either input nor output. */
+	*out_num = *in_num = 0;
+	if (unlikely(log))
+		*log_num = 0;
+
+	i = head;
+	do {
+		unsigned iov_count = *in_num + *out_num;
+		if (i >= vq->num) {
+			vq_err(vq, "Desc index is %u > %u, head = %u",
+			       i, vq->num, head);
+			return vq->num;
+		}
+		if (++found > vq->num) {
+			vq_err(vq, "Loop detected: last one at %u "
+			       "vq size %u head %u\n",
+			       i, vq->num, head);
+			return vq->num;
+		}
+		ret = copy_from_user(&desc, vq->desc + i, sizeof desc);
+		if (ret) {
+			vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
+			       i, vq->desc + i);
+			return vq->num;
+		}
+		if (desc.flags & VRING_DESC_F_INDIRECT) {
+			ret = get_indirect(dev, vq, iov, out_num, in_num,
+					   log, log_num, &desc);
+			if (ret < 0) {
+				vq_err(vq, "Failure detected "
+				       "in indirect descriptor at idx %d\n", i);
+				return vq->num;
+			}
+			continue;
+		}
+
+		ret = translate_desc(dev, desc.addr, desc.len, iov + iov_count,
+				     VHOST_NET_MAX_SG - iov_count);
+		if (ret < 0) {
+			vq_err(vq, "Translation failure %d descriptor idx %d\n",
+			       ret, i);
+			return vq->num;
+		}
+		if (desc.flags & VRING_DESC_F_WRITE) {
+			/* If this is an input descriptor,
+			 * increment that count. */
+			*in_num += ret;
+			if (unlikely(log)) {
+				log[*log_num].addr = desc.addr;
+				log[*log_num].len = desc.len;
+				++*log_num;
+			}
+		} else {
+			/* If it's an output descriptor, they're all supposed
+			 * to come before any input descriptors. */
+			if (*in_num) {
+				vq_err(vq, "Descriptor has out after in: "
+				       "idx %d\n", i);
+				return vq->num;
+			}
+			*out_num += ret;
+		}
+	} while ((i = next_desc(&desc)) != -1);
+
+	/* On success, increment avail index. */
+	vq->last_avail_idx++;
+	return head;
+}
+
+/* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
+void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
+{
+	vq->last_avail_idx--;
+}
+
+/* After we've used one of their buffers, we tell them about it.  We'll then
+ * want to send them an interrupt, using vq->call. */
+int vhost_add_used(struct vhost_virtqueue *vq,
+			  unsigned int head, int len)
+{
+	struct vring_used_elem *used;
+
+	/* The virtqueue contains a ring of used buffers.  Get a pointer to the
+	 * next entry in that used ring. */
+	used = &vq->used->ring[vq->last_used_idx % vq->num];
+	if (put_user(head, &used->id)) {
+		vq_err(vq, "Failed to write used id");
+		return -EFAULT;
+	}
+	if (put_user(len, &used->len)) {
+		vq_err(vq, "Failed to write used len");
+		return -EFAULT;
+	}
+	/* Make sure buffer is written before we update index. */
+	wmb();
+	if (put_user(vq->last_used_idx + 1, &vq->used->idx)) {
+		vq_err(vq, "Failed to increment used idx");
+		return -EFAULT;
+	}
+	if (unlikely(vq->log_used)) {
+		/* Make sure data is seen before log. */
+		wmb();
+		log_write(vq->log_base, vq->log_addr + sizeof *vq->used->ring *
+			  (vq->last_used_idx % vq->num),
+			  sizeof *vq->used->ring);
+		log_write(vq->log_base, vq->log_addr, sizeof *vq->used->ring);
+		if (vq->log_ctx)
+			eventfd_signal(vq->log_ctx, 1);
+	}
+	vq->last_used_idx++;
+	return 0;
+}
+
+/* This actually sends the interrupt for this virtqueue */
+void vhost_trigger_irq(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
+	__u16 flags = 0;
+	if (get_user(flags, &vq->avail->flags)) {
+		vq_err(vq, "Failed to get flags");
+		return;
+	}
+
+	/* If they don't want an interrupt, don't send one, unless empty. */
+	if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
+	    (vq->avail_idx != vq->last_avail_idx ||
+	     !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
+		return;
+
+	/* Send the Guest an interrupt tell them we used something up. */
+	if (vq->call_ctx)
+		eventfd_signal(vq->call_ctx, 1);
+}
+
+/* And here's the combo meal deal.  Supersize me! */
+void vhost_add_used_and_trigger(struct vhost_dev *dev,
+				struct vhost_virtqueue *vq,
+				unsigned int head, int len)
+{
+	vhost_add_used(vq, head, len);
+	vhost_trigger_irq(dev, vq);
+}
+
+/* OK, now we need to know about added descriptors. */
+bool vhost_notify(struct vhost_virtqueue *vq)
+{
+	int r;
+	if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
+		return false;
+	vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
+	r = put_user(vq->used_flags, &vq->used->flags);
+	if (r)
+		vq_err(vq, "Failed to disable notification: %d\n", r);
+	/* They could have slipped one in as we were doing that: make
+	 * sure it's written, tell caller it needs to check again. */
+	mb();
+	return true;
+}
+
+/* We don't need to be notified again. */
+void vhost_no_notify(struct vhost_virtqueue *vq)
+{
+	int r;
+	if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
+		return;
+	vq->used_flags |= VRING_USED_F_NO_NOTIFY;
+	r = put_user(vq->used_flags, &vq->used->flags);
+	if (r)
+		vq_err(vq, "Failed to enable notification: %d\n", r);
+}
+
+int vhost_init(void)
+{
+	vhost_workqueue = create_singlethread_workqueue("vhost");
+	if (!vhost_workqueue)
+		return -ENOMEM;
+	return 0;
+}
+
+void vhost_cleanup(void)
+{
+	destroy_workqueue(vhost_workqueue);
+}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
new file mode 100644
index 0000000..d3900de
--- /dev/null
+++ b/drivers/vhost/vhost.h
@@ -0,0 +1,158 @@
+#ifndef _VHOST_H
+#define _VHOST_H
+
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+#include <linux/uio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_device;
+
+enum {
+	VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
+};
+
+/* Poll a file (eventfd or socket) */
+/* Note: there's nothing vhost specific about this structure. */
+struct vhost_poll {
+	poll_table                table;
+	wait_queue_head_t        *wqh;
+	wait_queue_t              wait;
+	/* struct which will handle all actual work. */
+	struct work_struct        work;
+	unsigned long		  mask;
+};
+
+void vhost_poll_init(struct vhost_poll *poll, work_func_t func,
+		     unsigned long mask);
+void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+void vhost_poll_stop(struct vhost_poll *poll);
+void vhost_poll_flush(struct vhost_poll *poll);
+void vhost_poll_queue(struct vhost_poll *poll);
+
+struct vhost_log {
+	u64 addr;
+	u64 len;
+};
+
+/* The virtqueue structure describes a queue attached to a device. */
+struct vhost_virtqueue {
+	struct vhost_dev *dev;
+
+	/* The actual ring of buffers. */
+	struct mutex mutex;
+	unsigned int num;
+	struct vring_desc __user *desc;
+	struct vring_avail __user *avail;
+	struct vring_used __user *used;
+	struct file *kick;
+	struct file *call;
+	struct file *error;
+	struct eventfd_ctx *call_ctx;
+	struct eventfd_ctx *error_ctx;
+	struct eventfd_ctx *log_ctx;
+
+	struct vhost_poll poll;
+
+	/* The routine to call when the Guest pings us, or timeout. */
+	work_func_t handle_kick;
+
+	/* Last available index we saw. */
+	u16 last_avail_idx;
+
+	/* Caches available index value from user. */
+	u16 avail_idx;
+
+	/* Last index we used. */
+	u16 last_used_idx;
+
+	/* Used flags */
+	u16 used_flags;
+
+	/* Log writes to used structure. */
+	bool log_used;
+	u64 log_addr;
+
+	struct iovec indirect[VHOST_NET_MAX_SG];
+	struct iovec iov[VHOST_NET_MAX_SG];
+	struct iovec hdr[VHOST_NET_MAX_SG];
+	size_t hdr_size;
+	/* We use a kind of RCU to access private pointer.
+	 * All readers access it from workqueue, which makes it possible to
+	 * flush the workqueue instead of synchronize_rcu. Therefore readers do
+	 * not need to call rcu_read_lock/rcu_read_unlock: the beginning of
+	 * work item execution acts instead of rcu_read_lock() and the end of
+	 * work item execution acts instead of rcu_read_lock().
+	 * Writers use virtqueue mutex. */
+	void *private_data;
+	/* Log write descriptors */
+	void __user *log_base;
+	struct vhost_log log[VHOST_NET_MAX_SG];
+};
+
+struct vhost_dev {
+	/* Readers use RCU to access memory table pointer
+	 * log base pointer and features.
+	 * Writers use mutex below.*/
+	struct vhost_memory *memory;
+	struct mm_struct *mm;
+	struct mutex mutex;
+	unsigned acked_features;
+	struct vhost_virtqueue *vqs;
+	int nvqs;
+	struct file *log_file;
+	struct eventfd_ctx *log_ctx;
+};
+
+long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
+long vhost_dev_check_owner(struct vhost_dev *);
+long vhost_dev_reset_owner(struct vhost_dev *);
+void vhost_dev_cleanup(struct vhost_dev *);
+long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
+
+unsigned vhost_get_vq_desc(struct vhost_dev *, struct vhost_virtqueue *,
+			   struct iovec iov[],
+			   unsigned int *out_num, unsigned int *in_num,
+			   struct vhost_log *log, unsigned int *log_num);
+void vhost_discard_vq_desc(struct vhost_virtqueue *);
+
+int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len);
+void vhost_trigger_irq(struct vhost_dev *, struct vhost_virtqueue *);
+void vhost_add_used_and_trigger(struct vhost_dev *, struct vhost_virtqueue *,
+				unsigned int head, int len);
+void vhost_no_notify(struct vhost_virtqueue *);
+bool vhost_notify(struct vhost_virtqueue *);
+
+int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
+		    unsigned int log_num, u64 len);
+
+int vhost_init(void);
+void vhost_cleanup(void);
+
+#define vq_err(vq, fmt, ...) do {                                  \
+		pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
+		if ((vq)->error_ctx)                               \
+				eventfd_signal((vq)->error_ctx, 1);\
+	} while (0)
+
+enum {
+	VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
+			 (1 << VIRTIO_RING_F_INDIRECT_DESC) |
+			 (1 << VHOST_F_LOG_ALL) |
+			 (1 << VHOST_NET_F_VIRTIO_NET_HDR),
+};
+
+static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
+{
+	unsigned acked_features = rcu_dereference(dev->acked_features);
+	return acked_features & (1 << bit);
+}
+
+#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 3f384d4..b6335c6 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -361,6 +361,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
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index adaf3c1..8b5f7cc 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -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;
diff --git a/include/linux/vhost.h b/include/linux/vhost.h
new file mode 100644
index 0000000..f66142f
--- /dev/null
+++ b/include/linux/vhost.h
@@ -0,0 +1,126 @@
+#ifndef _LINUX_VHOST_H
+#define _LINUX_VHOST_H
+/* Userspace interface for in-kernel virtio accelerators. */
+
+/* vhost is used to reduce the number of system calls involved in virtio.
+ *
+ * Existing virtio net code is used in the guest without modification.
+ *
+ * This header includes interface used by userspace hypervisor for
+ * device configuration.
+ */
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+
+struct vhost_vring_state {
+	unsigned int index;
+	unsigned int num;
+};
+
+struct vhost_vring_file {
+	unsigned int index;
+	int fd; /* Pass -1 to unbind from file. */
+
+};
+
+struct vhost_vring_addr {
+	unsigned int index;
+	unsigned int padding;
+	__u64 user_addr;
+};
+
+struct vhost_memory_region {
+	__u64 guest_phys_addr;
+	__u64 memory_size; /* bytes */
+	__u64 userspace_addr;
+	__u64 flags_padding; /* No flags are currently specified. */
+};
+
+/* All region addresses and sizes must be 4K aligned. */
+#define VHOST_PAGE_SIZE 0x1000
+
+struct vhost_memory {
+	__u32 nregions;
+	__u32 padding;
+	struct vhost_memory_region regions[0];
+};
+
+/* ioctls */
+
+#define VHOST_VIRTIO 0xAF
+
+/* Features bitmask for forward compatibility.  Transport bits are used for
+ * vhost specific features. */
+#define VHOST_GET_FEATURES	_IOR(VHOST_VIRTIO, 0x00, __u64)
+#define VHOST_ACK_FEATURES	_IOW(VHOST_VIRTIO, 0x00, __u64)
+
+/* Set current process as the (exclusive) owner of this file descriptor.  This
+ * must be called before any other vhost command.  Further calls to
+ * VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
+#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
+/* Give up ownership, and reset the device to default values.
+ * Allows subsequent call to VHOST_OWNER_SET to succeed. */
+#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
+
+/* Set up/modify memory layout */
+#define VHOST_SET_MEM_TABLE	_IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
+
+/* Write logging setup. */
+/* Memory writes can optionally be logged by setting bit at an offset
+ * (calculated from the physical address) from specified log base.
+ * The bit is set using an atomic 32 bit operation. */
+/* Set base address for logging. */
+#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
+/* Specify an eventfd file descriptor to signal on log write. */
+#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
+
+/* Ring setup. These parameters can not be modified while ring is running
+ * (bound to a device). */
+/* Set number of descriptors in ring */
+#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
+/* Start of array of descriptors (virtually contiguous) */
+#define VHOST_SET_VRING_DESC _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
+/* Used structure address. Must be 32 bit aligned */
+#define VHOST_SET_VRING_USED _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_addr)
+/* Available structure address. Must be 16 bit aligned */
+#define VHOST_SET_VRING_AVAIL _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_addr)
+/* Base value where queue looks for available descriptors */
+#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+/* Get accessor: reads index, writes value in num */
+#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x14, struct vhost_vring_state)
+
+/* Logging support. Can be modified while ring is running. */
+/* Log writes to used structure, at offset calculated from specified address.
+ * Address must be 32 bit aligned. Pass 0x1 to disable logging. */
+#define VHOST_SET_VRING_LOG _IOW(VHOST_VIRTIO, 0x18, struct vhost_vring_addr)
+#define VHOST_VRING_LOG_DISABLE (0x1)
+
+/* The following ioctls use eventfd file descriptors to signal and poll
+ * for events. */
+
+/* Set eventfd to poll for added buffers */
+#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
+/* Set eventfd to signal when buffers have beed used */
+#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
+/* Set eventfd to signal an error */
+#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
+
+/* VHOST_NET specific defines */
+
+/* Attach virtio net ring to a raw socket, or tap device.
+ * The socket must be already bound to an ethernet device, this device will be
+ * used for transmit.  Pass fd -1 to unbind from the socket and the transmit
+ * device.  This can be used to stop the ring (e.g. for migration). */
+#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
+
+/* Feature bits */
+/* Log all write descriptors. Can be changed while device is active. */
+#define VHOST_F_LOG_ALL 26
+/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
+#define VHOST_NET_F_VIRTIO_NET_HDR 27
+
+#endif
-- 
1.6.5.2.143.g8cc62

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

^ permalink raw reply related

* Re: [PATCHv7 2/3] mm: export use_mm/unuse_mm to modules
From: Gregory Haskins @ 2009-11-03 17:32 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, Rusty Russell, s.hetze
In-Reply-To: <20091103172411.GC5591@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 1066 bytes --]

Michael S. Tsirkin wrote:
> vhost net module wants to do copy to/from user from a kernel thread,
> which needs use_mm. Export it to modules.
> 
> Acked-by: Andrea Arcangeli <aarcange@redhat.com>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

I need this too:

Acked-by: Gregory Haskins <ghaskins@novell.com>

> ---
>  mm/mmu_context.c |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/mm/mmu_context.c b/mm/mmu_context.c
> index ded9081..0777654 100644
> --- a/mm/mmu_context.c
> +++ b/mm/mmu_context.c
> @@ -5,6 +5,7 @@
>  
>  #include <linux/mm.h>
>  #include <linux/mmu_context.h>
> +#include <linux/module.h>
>  #include <linux/sched.h>
>  
>  #include <asm/mmu_context.h>
> @@ -37,6 +38,7 @@ void use_mm(struct mm_struct *mm)
>  	if (active_mm != mm)
>  		mmdrop(active_mm);
>  }
> +EXPORT_SYMBOL_GPL(use_mm);
>  
>  /*
>   * unuse_mm
> @@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm)
>  	enter_lazy_tlb(mm, tsk);
>  	task_unlock(tsk);
>  }
> +EXPORT_SYMBOL_GPL(unuse_mm);



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 267 bytes --]

^ permalink raw reply

* 2.6.32-rc5-mmotm1101 - kernel BUG at net/ipv4/tcp_input.c:3707!
From: Valdis.Kletnieks @ 2009-11-03 17:50 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, netdev

[-- Attachment #1: Type: text/plain, Size: 5440 bytes --]

Seen right after I started 'fetchmail'.  Reproducible - 3 out of 3.
I'll bisect this tonight if nobody jumps up and yells they know what it is...

Looking at the traceback, I wonder if we started sending the SYN packet,
but didn't finish the paperwork before the SYN/ACK came back?

[   87.269743] ------------[ cut here ]------------
[   87.270011] kernel BUG at net/ipv4/tcp_input.c:3707!
[   87.270011] invalid opcode: 0000 [#1] PREEMPT SMP 
[   87.270011] last sysfs file: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT0/charge_full
[   87.270011] CPU 0 
[   87.270011] Modules linked in: ext4 jbd2 crc16 [last unloaded: microcode]
[   87.270011] Pid: 2421, comm: fetchmail Not tainted 2.6.32-rc5-mmotm1101 #1 Latitude D820                   
[   87.270011] RIP: 0010:[<ffffffff813d13c2>]  [<ffffffff813d13c2>] tcp_parse_options+0x62/0x273
[   87.270011] RSP: 0018:ffff880002603af8  EFLAGS: 00010202
[   87.270011] RAX: 0000000000000001 RBX: ffff880002603b78 RCX: 000000000000000a
[   87.270011] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffffffff81ad9fb0
[   87.270011] RBP: ffff880002603b48 R08: ffff88007e2d9000 R09: 0000000000000001
[   87.270011] R10: 00000000000006f6 R11: ffff880002603a78 R12: 0000000000000000
[   87.270011] R13: ffff88007eb0ece8 R14: 0000000000000000 R15: ffff88007e693168
[   87.270011] FS:  00007fa02ff827c0(0000) GS:ffff880002600000(0000) knlGS:0000000000000000
[   87.270011] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   87.270011] CR2: 00000032cf7411e0 CR3: 000000007e41d000 CR4: 00000000000006f0
[   87.270011] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   87.270011] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[   87.270011] Process fetchmail (pid: 2421, threadinfo ffff880079234000, task ffff88007d2bc300)
[   87.270011] Stack:
[   87.270011]  ffff880002603b48 ffffffff00000001 000000000000000a ffffffff00000000
[   87.270011] <0> 0000000000000000 ffff88007903bbc0 ffff88007e693168 ffff88007c6eb2c0
[   87.270011] <0> 0000000000000000 0000000000000000 ffff880002603bc8 ffffffff81430486
[   87.270011] Call Trace:
[   87.270011]  <IRQ> 
[   87.270011]  [<ffffffff81430486>] tcp_v6_conn_request+0x171/0x3cb
[   87.270011]  [<ffffffff813d3bf8>] tcp_rcv_state_process+0x5f/0x857
[   87.270011]  [<ffffffff8142ff4d>] tcp_v6_do_rcv+0x313/0x445
[   87.270011]  [<ffffffff814bd489>] ? _spin_lock_nested+0x42/0x49
[   87.270011]  [<ffffffff8143155b>] ? tcp_v6_rcv+0x2aa/0x61c
[   87.270011]  [<ffffffff814316f6>] tcp_v6_rcv+0x445/0x61c
[   87.270011]  [<ffffffff81414bb9>] ip6_input_finish+0x1bf/0x31f
[   87.270011]  [<ffffffff81414d66>] ip6_input+0x4d/0x54
[   87.270011]  [<ffffffff81414502>] ip6_rcv_finish+0x22/0x26
[   87.270011]  [<ffffffff81414964>] ipv6_rcv+0x45e/0x4b4
[   87.270011]  [<ffffffff81391662>] netif_receive_skb+0x29e/0x2c8
[   87.270011]  [<ffffffff81391717>] process_backlog+0x8b/0xc1
[   87.270011]  [<ffffffff81391e6a>] net_rx_action+0xed/0x2b0
[   87.270011]  [<ffffffff8108518a>] ? handle_edge_irq+0x16a/0x176
[   87.270011]  [<ffffffff81041c2a>] __do_softirq+0x127/0x23c
[   87.270011]  [<ffffffff813922f4>] ? rcu_read_unlock_bh+0x21/0x23
[   87.270011]  [<ffffffff8100347c>] call_softirq+0x1c/0x34
[   87.270011]  <EOI> 
[   87.270011]  [<ffffffff810049cc>] do_softirq+0x44/0xf0
[   87.270011]  [<ffffffff813922f4>] ? rcu_read_unlock_bh+0x21/0x23
[   87.270011]  [<ffffffff810414c7>] _local_bh_enable_ip+0x120/0x16e
[   87.270011]  [<ffffffff8104152d>] local_bh_enable+0xd/0xf
[   87.270011]  [<ffffffff813922f4>] rcu_read_unlock_bh+0x21/0x23
[   87.270011]  [<ffffffff81392e10>] dev_queue_xmit+0x3e4/0x408
[   87.270011]  [<ffffffff81392b70>] ? dev_queue_xmit+0x144/0x408
[   87.270011]  [<ffffffff8139afa8>] neigh_resolve_output+0x1ef/0x240
[   87.270011]  [<ffffffff81410f50>] ? ip6_output_finish+0x0/0xfc
[   87.270011]  [<ffffffff81410fec>] ip6_output_finish+0x9c/0xfc
[   87.270011]  [<ffffffff8141242d>] ip6_output2+0x2bf/0x2c8
[   87.270011]  [<ffffffff81413107>] ip6_output+0xcd1/0xce6
[   87.270011]  [<ffffffff813ab63a>] ? rcu_read_unlock+0x21/0x23
[   87.270011]  [<ffffffff813ab89b>] ? nf_hook_slow+0xca/0xdb
[   87.270011]  [<ffffffff81410c9c>] ? dst_output+0x0/0xd
[   87.270011]  [<ffffffff81410ca7>] dst_output+0xb/0xd
[   87.270011]  [<ffffffff81413517>] ip6_xmit+0x3fb/0x4d4
[   87.270011]  [<ffffffff8143dba6>] ? __inet6_hash+0xe5/0x122
[   87.270011]  [<ffffffff814358b2>] inet6_csk_xmit+0x265/0x274
[   87.270011]  [<ffffffff811caa4c>] ? _raw_spin_lock+0xe9/0x1ab
[   87.270011]  [<ffffffff813d557d>] tcp_transmit_skb+0x816/0x85f
[   87.270011]  [<ffffffff813d6ed5>] tcp_connect+0x3ae/0x409
[   87.270011]  [<ffffffff8142f74f>] tcp_v6_connect+0x4f0/0x55e
[   87.270011]  [<ffffffff813e78d0>] inet_stream_connect+0xa0/0x268
[   87.270011]  [<ffffffff81383c71>] sys_connect+0x75/0x98
[   87.270011]  [<ffffffff810e2328>] ? path_put+0x1d/0x22
[   87.270011]  [<ffffffff81066193>] ? trace_hardirqs_on_caller+0x16/0x13c
[   87.270011]  [<ffffffff8107fdf1>] ? audit_syscall_entry+0xcb/0x19c
[   87.270011]  [<ffffffff8100246b>] system_call_fastpath+0x16/0x1b
[   87.270011] Code: e9 04 4d 85 f6 88 4d c0 0f 94 c2 31 c0 45 85 e4 0f 94 c0 21 d0 31 d2 89 c6 89 45 b8 e8 70 6a cc ff 8b 45 b8 8a 4d c0 85 c0 74 04 <0f> 0b eb fe 0f b6 d1 49 83 c7 38 8d 14 95 ec ff ff ff 49 8d 45 
[   87.270011] RIP  [<ffffffff813d13c2>] tcp_parse_options+0x62/0x273
[   87.270011]  RSP <ffff880002603af8>


[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply

* Re: [PATCH 1/3] sysfs directory scaling: rbtree for dirent name lookups
From: Greg KH @ 2009-11-03 17:56 UTC (permalink / raw)
  To: Benjamin LaHaise
  Cc: Eric Dumazet, Eric W. Biederman, Octavian Purdila, netdev,
	Cosmin Ratiu, linux-kernel
In-Reply-To: <20091103164550.GM8227@kvack.org>

On Tue, Nov 03, 2009 at 11:45:50AM -0500, Benjamin LaHaise wrote:
> On Tue, Nov 03, 2009 at 08:07:15AM -0800, Greg KH wrote:
> > But registering 20000 devices is a far different problem from using
> > those 20000 devices :)
> 
> Registering 20,000 devices *is* a real world problem (I'm actually aiming 
> for 100,000, as that's what roughly fits in a single 10Gbps link -- something 
> that a mid range system can now route).  When an edge router comes up from 
> reboot, or after a link has been down, the rate at which customers connect 
> is important -- too slow, and you get a pile of support calls from customers 
> complaining that their connection is down.  Because of the data structures 
> used, there isn't even any improvement from an SMP system, so this needs 
> to be addressed directly.

Ok, how long are we talking about here?

thanks,

greg k-h

^ permalink raw reply

* Re: 2.6.32-rc5-mmotm1101 - kernel BUG at net/ipv4/tcp_input.c:3707!
From: Eric Dumazet @ 2009-11-03 18:02 UTC (permalink / raw)
  To: Valdis.Kletnieks
  Cc: Andrew Morton, linux-kernel, netdev, Gilad Ben-Yossef,
	Ori Finkelman
In-Reply-To: <5765.1257270611@turing-police.cc.vt.edu>

Valdis.Kletnieks@vt.edu a écrit :
> Seen right after I started 'fetchmail'.  Reproducible - 3 out of 3.
> I'll bisect this tonight if nobody jumps up and yells they know what it is...
> 
> Looking at the traceback, I wonder if we started sending the SYN packet,
> but didn't finish the paperwork before the SYN/ACK came back?
> 
> [   87.269743] ------------[ cut here ]------------
> [   87.270011] kernel BUG at net/ipv4/tcp_input.c:3707!
> [   87.270011] invalid opcode: 0000 [#1] PREEMPT SMP 
> [   87.270011] last sysfs file: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT0/charge_full
> [   87.270011] CPU 0 
> [   87.270011] Modules linked in: ext4 jbd2 crc16 [last unloaded: microcode]
> [   87.270011] Pid: 2421, comm: fetchmail Not tainted 2.6.32-rc5-mmotm1101 #1 Latitude D820                   
> [   87.270011] RIP: 0010:[<ffffffff813d13c2>]  [<ffffffff813d13c2>] tcp_parse_options+0x62/0x273
> [   87.270011] RSP: 0018:ffff880002603af8  EFLAGS: 00010202
> [   87.270011] RAX: 0000000000000001 RBX: ffff880002603b78 RCX: 000000000000000a
> [   87.270011] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffffffff81ad9fb0
> [   87.270011] RBP: ffff880002603b48 R08: ffff88007e2d9000 R09: 0000000000000001
> [   87.270011] R10: 00000000000006f6 R11: ffff880002603a78 R12: 0000000000000000
> [   87.270011] R13: ffff88007eb0ece8 R14: 0000000000000000 R15: ffff88007e693168
> [   87.270011] FS:  00007fa02ff827c0(0000) GS:ffff880002600000(0000) knlGS:0000000000000000
> [   87.270011] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   87.270011] CR2: 00000032cf7411e0 CR3: 000000007e41d000 CR4: 00000000000006f0
> [   87.270011] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [   87.270011] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> [   87.270011] Process fetchmail (pid: 2421, threadinfo ffff880079234000, task ffff88007d2bc300)
> [   87.270011] Stack:
> [   87.270011]  ffff880002603b48 ffffffff00000001 000000000000000a ffffffff00000000
> [   87.270011] <0> 0000000000000000 ffff88007903bbc0 ffff88007e693168 ffff88007c6eb2c0
> [   87.270011] <0> 0000000000000000 0000000000000000 ffff880002603bc8 ffffffff81430486
> [   87.270011] Call Trace:
> [   87.270011]  <IRQ> 
> [   87.270011]  [<ffffffff81430486>] tcp_v6_conn_request+0x171/0x3cb
> [   87.270011]  [<ffffffff813d3bf8>] tcp_rcv_state_process+0x5f/0x857
> [   87.270011]  [<ffffffff8142ff4d>] tcp_v6_do_rcv+0x313/0x445
> [   87.270011]  [<ffffffff814bd489>] ? _spin_lock_nested+0x42/0x49
> [   87.270011]  [<ffffffff8143155b>] ? tcp_v6_rcv+0x2aa/0x61c
> [   87.270011]  [<ffffffff814316f6>] tcp_v6_rcv+0x445/0x61c
> [   87.270011]  [<ffffffff81414bb9>] ip6_input_finish+0x1bf/0x31f
> [   87.270011]  [<ffffffff81414d66>] ip6_input+0x4d/0x54
> [   87.270011]  [<ffffffff81414502>] ip6_rcv_finish+0x22/0x26
> [   87.270011]  [<ffffffff81414964>] ipv6_rcv+0x45e/0x4b4
> [   87.270011]  [<ffffffff81391662>] netif_receive_skb+0x29e/0x2c8
> [   87.270011]  [<ffffffff81391717>] process_backlog+0x8b/0xc1
> [   87.270011]  [<ffffffff81391e6a>] net_rx_action+0xed/0x2b0
> [   87.270011]  [<ffffffff8108518a>] ? handle_edge_irq+0x16a/0x176
> [   87.270011]  [<ffffffff81041c2a>] __do_softirq+0x127/0x23c
> [   87.270011]  [<ffffffff813922f4>] ? rcu_read_unlock_bh+0x21/0x23
> [   87.270011]  [<ffffffff8100347c>] call_softirq+0x1c/0x34
> [   87.270011]  <EOI> 
> [   87.270011]  [<ffffffff810049cc>] do_softirq+0x44/0xf0
> [   87.270011]  [<ffffffff813922f4>] ? rcu_read_unlock_bh+0x21/0x23
> [   87.270011]  [<ffffffff810414c7>] _local_bh_enable_ip+0x120/0x16e
> [   87.270011]  [<ffffffff8104152d>] local_bh_enable+0xd/0xf
> [   87.270011]  [<ffffffff813922f4>] rcu_read_unlock_bh+0x21/0x23
> [   87.270011]  [<ffffffff81392e10>] dev_queue_xmit+0x3e4/0x408
> [   87.270011]  [<ffffffff81392b70>] ? dev_queue_xmit+0x144/0x408
> [   87.270011]  [<ffffffff8139afa8>] neigh_resolve_output+0x1ef/0x240
> [   87.270011]  [<ffffffff81410f50>] ? ip6_output_finish+0x0/0xfc
> [   87.270011]  [<ffffffff81410fec>] ip6_output_finish+0x9c/0xfc
> [   87.270011]  [<ffffffff8141242d>] ip6_output2+0x2bf/0x2c8
> [   87.270011]  [<ffffffff81413107>] ip6_output+0xcd1/0xce6
> [   87.270011]  [<ffffffff813ab63a>] ? rcu_read_unlock+0x21/0x23
> [   87.270011]  [<ffffffff813ab89b>] ? nf_hook_slow+0xca/0xdb
> [   87.270011]  [<ffffffff81410c9c>] ? dst_output+0x0/0xd
> [   87.270011]  [<ffffffff81410ca7>] dst_output+0xb/0xd
> [   87.270011]  [<ffffffff81413517>] ip6_xmit+0x3fb/0x4d4
> [   87.270011]  [<ffffffff8143dba6>] ? __inet6_hash+0xe5/0x122
> [   87.270011]  [<ffffffff814358b2>] inet6_csk_xmit+0x265/0x274
> [   87.270011]  [<ffffffff811caa4c>] ? _raw_spin_lock+0xe9/0x1ab
> [   87.270011]  [<ffffffff813d557d>] tcp_transmit_skb+0x816/0x85f
> [   87.270011]  [<ffffffff813d6ed5>] tcp_connect+0x3ae/0x409
> [   87.270011]  [<ffffffff8142f74f>] tcp_v6_connect+0x4f0/0x55e
> [   87.270011]  [<ffffffff813e78d0>] inet_stream_connect+0xa0/0x268
> [   87.270011]  [<ffffffff81383c71>] sys_connect+0x75/0x98
> [   87.270011]  [<ffffffff810e2328>] ? path_put+0x1d/0x22
> [   87.270011]  [<ffffffff81066193>] ? trace_hardirqs_on_caller+0x16/0x13c
> [   87.270011]  [<ffffffff8107fdf1>] ? audit_syscall_entry+0xcb/0x19c
> [   87.270011]  [<ffffffff8100246b>] system_call_fastpath+0x16/0x1b
> [   87.270011] Code: e9 04 4d 85 f6 88 4d c0 0f 94 c2 31 c0 45 85 e4 0f 94 c0 21 d0 31 d2 89 c6 89 45 b8 e8 70 6a cc ff 8b 45 b8 8a 4d c0 85 c0 74 04 <0f> 0b eb fe 0f b6 d1 49 83 c7 38 8d 14 95 ec ff ff ff 49 8d 45 
> [   87.270011] RIP  [<ffffffff813d13c2>] tcp_parse_options+0x62/0x273
> [   87.270011]  RSP <ffff880002603af8>
> 


BUG_ON(!estab && !dst); 

Probably comes from commit 022c3f7d82f0f1c68018696f2f027b87b9bb45c2

(Allow tcp_parse_options to consult dst entry)

CC Gilad Ben-Yossef <gilad@codefidence.com> and Ori Finkelman <ori@comsleep.com> for a diagnostic

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Eric Dumazet @ 2009-11-03 18:03 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, gregory.haskins, Rusty Russell, s.hetze, Paul E. McKenney
In-Reply-To: <20091103172422.GD5591@redhat.com>

Michael S. Tsirkin a écrit :
> +static void handle_tx(struct vhost_net *net)
> +{
> +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> +	unsigned head, out, in, s;
> +	struct msghdr msg = {
> +		.msg_name = NULL,
> +		.msg_namelen = 0,
> +		.msg_control = NULL,
> +		.msg_controllen = 0,
> +		.msg_iov = vq->iov,
> +		.msg_flags = MSG_DONTWAIT,
> +	};
> +	size_t len, total_len = 0;
> +	int err, wmem;
> +	size_t hdr_size;
> +	struct socket *sock = rcu_dereference(vq->private_data);
> +	if (!sock)
> +		return;
> +
> +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> +	if (wmem >= sock->sk->sk_sndbuf)
> +		return;
> +
> +	use_mm(net->dev.mm);
> +	mutex_lock(&vq->mutex);
> +	vhost_no_notify(vq);
> +

using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
that your use of RCU is not correct.

1) rcu_dereference() should be done inside a read_rcu_lock() section, and
   we are not allowed to sleep in such a section.
   (Quoting Documentation/RCU/whatisRCU.txt :
     It is illegal to block while in an RCU read-side critical section, )

2) mutex_lock() can sleep (ie block)

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

^ permalink raw reply

* Re: [PATCH] iproute2: Avoid rounding errors for 100%.
From: Stephen Hemminger @ 2009-11-03 18:05 UTC (permalink / raw)
  To: Arnd Hannemann; +Cc: netdev@vger.kernel.org
In-Reply-To: <4AF06617.6030804@nets.rwth-aachen.de>

On Tue, 03 Nov 2009 18:19:19 +0100
Arnd Hannemann <hannemann@nets.rwth-aachen.de> wrote:

> Stephen Hemminger wrote:
> > On Tue, 03 Nov 2009 17:19:45 +0100
> > Arnd Hannemann <hannemann@nets.rwth-aachen.de> wrote:
> > 
> >> Although the patch makes sense,
> >> it does not fix the bug/effect we were seeing.
> >> A netem reorder percentage of 100% will still get packets reordered.
> >> (if the netem queue is not empty)
> >>
> >>
> >> hannemann@nets.rwth-aachen.de wrote:
> >>> From: Arnd Hannemann <hannemann@nets.rwth-aachen.de>
> >>>
> >>> We noticed that a netem reorder percentage of 100% will still get packets reordered.
> >>> This patch fixes that.
> >>>
> >>> Signed-off-by: Arnd Hannemann <hannemann@nets.rwth-aachen.de>
> >>> ---
> >>>  tc/tc_util.c |    6 ++++--
> >>>  1 files changed, 4 insertions(+), 2 deletions(-)
> >>>
> >>> diff --git a/tc/tc_util.c b/tc/tc_util.c
> >>> index fe2c7eb..2641f2e 100644
> >>> --- a/tc/tc_util.c
> >>> +++ b/tc/tc_util.c
> >>> @@ -363,8 +363,10 @@ int get_percent(__u32 *percent, const char *str)
> >>>  		return -1;
> >>>  	if (*p && strcmp(p, "%"))
> >>>  		return -1;
> >>> -
> >>> -	*percent = (unsigned) rint(per * max_percent_value);
> >>> +	if (per == 1.)
> >>> +		*percent = max_percent_value;
> >>> +	else
> >>> +		*percent = (unsigned) rint(per * max_percent_value);
> >>>  	return 0;
> >>>  }
> >>>  
> >>
> > 
> > If you don't want reordering, don't specify reordering?
> 
> Are you arguing against the correctness of my patch?
> 
> Regarding, the reordering thingy/bug/effect whatever:
> We would like to specify reordering with something like this:
> Please delay 1% of the packets with 5ms.
> 
> We thought that would be possible with
> tc qdisc add dev eth0 root netem delay 5m reorder 99%
> 
> But unfortunately it is not. Any better idea?
> 

I think the problem isn't in iproute utilities but in the code inside
netem kernel module. 

-- 

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Gregory Haskins @ 2009-11-03 18:08 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Michael S. Tsirkin, netdev, virtualization, kvm, linux-kernel,
	mingo, linux-mm, akpm, hpa, Rusty Russell, s.hetze,
	Paul E. McKenney
In-Reply-To: <4AF0708B.4020406@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1496 bytes --]

Eric Dumazet wrote:
> Michael S. Tsirkin a écrit :
>> +static void handle_tx(struct vhost_net *net)
>> +{
>> +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
>> +	unsigned head, out, in, s;
>> +	struct msghdr msg = {
>> +		.msg_name = NULL,
>> +		.msg_namelen = 0,
>> +		.msg_control = NULL,
>> +		.msg_controllen = 0,
>> +		.msg_iov = vq->iov,
>> +		.msg_flags = MSG_DONTWAIT,
>> +	};
>> +	size_t len, total_len = 0;
>> +	int err, wmem;
>> +	size_t hdr_size;
>> +	struct socket *sock = rcu_dereference(vq->private_data);
>> +	if (!sock)
>> +		return;
>> +
>> +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
>> +	if (wmem >= sock->sk->sk_sndbuf)
>> +		return;
>> +
>> +	use_mm(net->dev.mm);
>> +	mutex_lock(&vq->mutex);
>> +	vhost_no_notify(vq);
>> +
> 
> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
> that your use of RCU is not correct.
> 
> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
>    we are not allowed to sleep in such a section.
>    (Quoting Documentation/RCU/whatisRCU.txt :
>      It is illegal to block while in an RCU read-side critical section, )
> 
> 2) mutex_lock() can sleep (ie block)
> 


Michael,
  I warned you that this needed better documentation ;)

Eric,
  I think I flagged this once before, but Michael convinced me that it
was indeed "ok", if but perhaps a bit unconventional.  I will try to
find the thread.

Kind Regards,
-Greg


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 267 bytes --]

^ permalink raw reply

* Re: [PATCH net-next-2.6] bnx2: avoid compiler warnings
From: Michael Chan @ 2009-11-03 18:01 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David S. Miller, Linux Netdev List
In-Reply-To: <4AEFF536.1020402@gmail.com>


On Tue, 2009-11-03 at 01:17 -0800, Eric Dumazet wrote:
> drivers/net/bnx2.c: In function ‘bnx2_enable_forced_2g5’:
> drivers/net/bnx2.c:1447: warning: ‘bmcr’ may be used uninitialized in this function
> drivers/net/bnx2.c: In function ‘bnx2_disable_forced_2g5’:
> drivers/net/bnx2.c:1482: warning: ‘bmcr’ may be used uninitialized in this function
> 
> One fix would be to have an initial value, but a plain return might be better.

I agree that plain return is better.  Thanks.

Acked-by: Michael Chan <mchan@broadcom.com>

> 
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> 
> diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
> index 08cddb6..539d23b 100644
> --- a/drivers/net/bnx2.c
> +++ b/drivers/net/bnx2.c
> @@ -1466,6 +1466,8 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
>  	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
>  		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
>  		bmcr |= BCM5708S_BMCR_FORCE_2500;
> +	} else {
> +		return;
>  	}
>  
>  	if (bp->autoneg & AUTONEG_SPEED) {
> @@ -1500,6 +1502,8 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
>  	} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
>  		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
>  		bmcr &= ~BCM5708S_BMCR_FORCE_2500;
> +	} else {
> +		return;
>  	}
>  
>  	if (bp->autoneg & AUTONEG_SPEED)
> 



^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Gregory Haskins @ 2009-11-03 18:14 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Michael S. Tsirkin, netdev, virtualization, kvm, linux-kernel,
	mingo, linux-mm, akpm, hpa, Rusty Russell, s.hetze,
	Paul E. McKenney
In-Reply-To: <4AF07199.2020601@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1658 bytes --]

Gregory Haskins wrote:
> Eric Dumazet wrote:
>> Michael S. Tsirkin a écrit :
>>> +static void handle_tx(struct vhost_net *net)
>>> +{
>>> +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
>>> +	unsigned head, out, in, s;
>>> +	struct msghdr msg = {
>>> +		.msg_name = NULL,
>>> +		.msg_namelen = 0,
>>> +		.msg_control = NULL,
>>> +		.msg_controllen = 0,
>>> +		.msg_iov = vq->iov,
>>> +		.msg_flags = MSG_DONTWAIT,
>>> +	};
>>> +	size_t len, total_len = 0;
>>> +	int err, wmem;
>>> +	size_t hdr_size;
>>> +	struct socket *sock = rcu_dereference(vq->private_data);
>>> +	if (!sock)
>>> +		return;
>>> +
>>> +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
>>> +	if (wmem >= sock->sk->sk_sndbuf)
>>> +		return;
>>> +
>>> +	use_mm(net->dev.mm);
>>> +	mutex_lock(&vq->mutex);
>>> +	vhost_no_notify(vq);
>>> +
>> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
>> that your use of RCU is not correct.
>>
>> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
>>    we are not allowed to sleep in such a section.
>>    (Quoting Documentation/RCU/whatisRCU.txt :
>>      It is illegal to block while in an RCU read-side critical section, )
>>
>> 2) mutex_lock() can sleep (ie block)
>>
> 
> 
> Michael,
>   I warned you that this needed better documentation ;)
> 
> Eric,
>   I think I flagged this once before, but Michael convinced me that it
> was indeed "ok", if but perhaps a bit unconventional.  I will try to
> find the thread.
> 
> Kind Regards,
> -Greg
> 

Here it is:

http://lkml.org/lkml/2009/8/12/173

Kind Regards,
-Greg


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 267 bytes --]

^ permalink raw reply

* RE: Subject: [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody @ 2009-11-03 18:24 UTC (permalink / raw)
  To: Joe Perches
  Cc: netdev@vger.kernel.org, Adapter Linux Open SRC Team,
	Greg Kroah-Hartman
In-Reply-To: <1257053039.1917.147.camel@Joe-Laptop.home>

Joe,
Thanks for your input. We are in the process addressing the comments that we are getting.

Can you please give examples or elaborate your comment? It would be really helpful.
Thanks,
-- Rasesh

-----Original Message-----
From: Joe Perches [mailto:joe@perches.com] 
Sent: Saturday, October 31, 2009 10:24 PM
To: Rasesh Mody
Cc: netdev@vger.kernel.org; Adapter Linux Open SRC Team; Greg Kroah-Hartman
Subject: Re: Subject: [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver

There are an awful lot of non linux standard
uses in this code set.

Perhaps staging would be a good place to start?


^ permalink raw reply

* [announce] new rt2800 drivers for Ralink wireless & project tree
From: Bartlomiej Zolnierkiewicz @ 2009-11-03 18:51 UTC (permalink / raw)
  To: linux-wireless
  Cc: linux-kernel, netdev, Ivo van Doorn, Randy Dunlap, Luis Correia,
	John W. Linville, Ingo Molnar, Johannes Berg, Jarek Poplawski,
	Pekka Enberg, David Miller


Hi,

The following patch series (against wireless-next) addresses issues raised
during code review and subsequently rejected by rt2x00/wireless/networking
maintainers.


Namely, it:

- Adds abstraction of chipset register access for chipsets connected to
  different buses by using new structure (struct rt2800_ops) which contains
  all needed register access methods.

  [ It is a prerequisite for fixing code duplication between rt2800usb.c
    and rt2800pci.c drivers. ]

- Fixes code duplication in rt2800usb.h and rt2800pci.h header files by
  using new shared rt2800.h header (almost 1800 LOC gone).

  Updated debugging scripts are located here:

      http://www.kernel.org/pub/linux/kernel/people/bart/rt2800/scripts/

  (they also work fine with older drivers)

- Adds rt2800 library containing common code for PCI and USB versions
  of rt2800 chipsets.  This removes over 1300 LOC and allows us to save
  a lot of maintenance burden in the future. 


It also fixes two real bugs (one in rt2800pci and one in rt2800usb) found
as a direct result of the code de-duplication:

- Fix rt2800usb driver to write the rfcsr read request into RF_CSR_CFG
  register and not BBP_CSR_CFG one in rt2800usb_rfcsr_read().

- Use the correct encryption key index for TX frames in rt2800pci (this is
  based on rt2800usb patch from Benoit PAPILLAULT already in Linus' tree,
  unfortunately the fix was not ported over to rt2800pci).

  [ There are also some minor code rt2x00 infrastructure fixes and improvements
     here and there... ]


All in all over 3100 LOC are gone and rt2800pci specific code is:

 1685 drivers/net/wireless/rt2x00/rt2800pci.c
  180 drivers/net/wireless/rt2x00/rt2800pci.h
 1865 total

instead of:

  3323 drivers/net/wireless/rt2x00/rt2800pci.c
  1960 drivers/net/wireless/rt2x00/rt2800pci.h
  5283 total

  (wireless-next and net-next trees)

which means decrease of the code needed for rt2800pci by 65% (this in turn
translates to 31% decrease for rt2800 specific code and 9% for whole rt2x00
infrastructure).

The rewrite was quite conservative and there is still a room for improvement
but it should serve as a good starting base for all future work on rt2800
drivers, and there is a lot to do there (both drivers are still practically
non-functional).

Comments and patches are welcomed.


The following changes since commit fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028a:
  Juuso Oikarinen (1):
        wl1271: Generalize command response reading

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/bart/misc.git rt2800

Bartlomiej Zolnierkiewicz (40):
      rt2800usb: fix rt2800usb_rfcsr_read()
      rt2800pci: fix crypto in TX frame
      rt2800pci: fix comment about register access
      rt2800pci: fix comment about IV/EIV fields
      rt2x00: fix rt2x00usb_register_read() comment
      rt2800usb: use rt2x00usb_register_multiwrite() to set key entries
      rt2800usb: add rt2800_register_[read,write]() wrappers
      rt2800pci: add rt2800_register_[read,write]() wrappers
      rt2800usb: add rt2800_register_multi[read,write]() wrappers
      rt2800pci: add rt2800_register_multi[read,write]() wrappers
      rt2800usb: add rt2800_regbusy_read() wrapper
      rt2800pci: add rt2800_regbusy_read() wrapper
      rt2800usb: add rt2800_bbp_[read,write]() wrappers
      rt2800pci: add rt2800_bbp_[read,write]() wrappers
      rt2800usb: add rt2800_rfcsr_[read,write]() wrappers
      rt2800pci: add rt2800_rfcsr_[read,write]() wrappers
      rt2800usb: add rt2800_rf_[read,write]() wrappers
      rt2800pci: add rt2800_rf_[read,write]() wrappers
      rt2800usb: add rt2800_mcu_request() wrapper
      rt2800pci: add rt2800_mcu_request() wrapper
      rt2x00: add driver private field to struct rt2x00_dev
      rt2800usb: convert to use struct rt2800_ops methods
      rt2800pci: convert to use struct rt2800_ops methods
      rt2x00: fix rt2x00usb_register_multiwrite() arguments
      rt2x00: fix rt2x00usb_regbusy_read() arguments
      rt2x00: fix rt2x00pci_register_multi[read,write]() arguments
      rt2800: add rt2800lib.h
      rt2800usb: fix comments in rt2800usb.h
      rt2800usb: add RXINFO_DESC_SIZE definition
      rt2800: fix duplication in header files
      rt2800: fix comments in rt2800.h
      rt2x00: add support for different chipset interfaces
      rt2800: prepare for rt2800lib addition
      rt2800: add rt2800lib (part one)
      rt2x00: remove needless ifdefs from rt2x00leds.h
      rt2800: add rt2800lib (part two)
      rt2x00: move REGISTER_BUSY_* definitions to rt2x00.h
      rt2800: add rt2800lib (part three)
      rt2800: add rt2800lib (part four)
      MAINTAINERS: add rt2800 entry

 MAINTAINERS                              |    7 +
 drivers/net/wireless/rt2x00/Kconfig      |    5 +
 drivers/net/wireless/rt2x00/Makefile     |    1 +
 drivers/net/wireless/rt2x00/rt2800.h     | 1816 ++++++++++++++++++++++++++++
 drivers/net/wireless/rt2x00/rt2800lib.c  | 1817 ++++++++++++++++++++++++++++
 drivers/net/wireless/rt2x00/rt2800lib.h  |  134 +++
 drivers/net/wireless/rt2x00/rt2800pci.c  | 1908 +++---------------------------
 drivers/net/wireless/rt2x00/rt2800pci.h  | 1780 ----------------------------
 drivers/net/wireless/rt2x00/rt2800usb.c  | 1828 ++---------------------------
 drivers/net/wireless/rt2x00/rt2800usb.h  | 1818 +----------------------------
 drivers/net/wireless/rt2x00/rt2x00.h     |   33 +
 drivers/net/wireless/rt2x00/rt2x00leds.h |    4 -
 drivers/net/wireless/rt2x00/rt2x00pci.h  |   24 +-
 drivers/net/wireless/rt2x00/rt2x00usb.c  |    2 +-
 drivers/net/wireless/rt2x00/rt2x00usb.h  |   17 +-
 15 files changed, 4036 insertions(+), 7158 deletions(-)
 create mode 100644 drivers/net/wireless/rt2x00/rt2800.h
 create mode 100644 drivers/net/wireless/rt2x00/rt2800lib.c
 create mode 100644 drivers/net/wireless/rt2x00/rt2800lib.h

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Eric Dumazet @ 2009-11-03 18:51 UTC (permalink / raw)
  To: Gregory Haskins
  Cc: Michael S. Tsirkin, netdev, virtualization, kvm, linux-kernel,
	mingo, linux-mm, akpm, hpa, Rusty Russell, s.hetze,
	Paul E. McKenney
In-Reply-To: <4AF072EE.9020202@gmail.com>

Gregory Haskins a écrit :
> Gregory Haskins wrote:
>> Eric Dumazet wrote:
>>> Michael S. Tsirkin a écrit :
>>>> +static void handle_tx(struct vhost_net *net)
>>>> +{
>>>> +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
>>>> +	unsigned head, out, in, s;
>>>> +	struct msghdr msg = {
>>>> +		.msg_name = NULL,
>>>> +		.msg_namelen = 0,
>>>> +		.msg_control = NULL,
>>>> +		.msg_controllen = 0,
>>>> +		.msg_iov = vq->iov,
>>>> +		.msg_flags = MSG_DONTWAIT,
>>>> +	};
>>>> +	size_t len, total_len = 0;
>>>> +	int err, wmem;
>>>> +	size_t hdr_size;
>>>> +	struct socket *sock = rcu_dereference(vq->private_data);
>>>> +	if (!sock)
>>>> +		return;
>>>> +
>>>> +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
>>>> +	if (wmem >= sock->sk->sk_sndbuf)
>>>> +		return;
>>>> +
>>>> +	use_mm(net->dev.mm);
>>>> +	mutex_lock(&vq->mutex);
>>>> +	vhost_no_notify(vq);
>>>> +
>>> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
>>> that your use of RCU is not correct.
>>>
>>> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
>>>    we are not allowed to sleep in such a section.
>>>    (Quoting Documentation/RCU/whatisRCU.txt :
>>>      It is illegal to block while in an RCU read-side critical section, )
>>>
>>> 2) mutex_lock() can sleep (ie block)
>>>
>>
>> Michael,
>>   I warned you that this needed better documentation ;)
>>
>> Eric,
>>   I think I flagged this once before, but Michael convinced me that it
>> was indeed "ok", if but perhaps a bit unconventional.  I will try to
>> find the thread.
>>
>> Kind Regards,
>> -Greg
>>
> 
> Here it is:
> 
> http://lkml.org/lkml/2009/8/12/173
> 

Yes, this doesnt convince me at all, and could be a precedent for a wrong RCU use.
People wanting to use RCU do a grep on kernel sources to find how to correctly
use RCU.

Michael, please use existing locking/barrier mechanisms, and not pretend to use RCU.

Some automatic tools might barf later.

For example, we could add a debugging facility to check that rcu_dereference() is used
in an appropriate context, ie conflict with existing mutex_lock() debugging facility.


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

^ permalink raw reply

* Re: 2.6.32-rc5-mmotm1101 - kernel BUG at net/ipv4/tcp_input.c:3707!
From: Gilad Ben-Yossef @ 2009-11-03 19:20 UTC (permalink / raw)
  To: Valdis.Kletnieks
  Cc: Eric Dumazet, Andrew Morton, linux-kernel, netdev, Ori Finkelman
In-Reply-To: <4AF07024.80103@gmail.com>

Eric Dumazet wrote:

> Valdis.Kletnieks@vt.edu a écrit :
>   
>> Seen right after I started 'fetchmail'.  Reproducible - 3 out of 3.
>> I'll bisect this tonight if nobody jumps up and yells they know what it is...
>>     
Bah... this is most probably my fault. Sorry about that.

Can you please try the patch in the next email?

But also, can you please send me the route table in effect when this 
happened and the fetchmail command line/config (removing any passwords 
or account details of course)? I want to understand better when this 
happens.

Thanks!
Gilad


-- 
Gilad Ben-Yossef
Chief Coffee Drinker & CTO
Codefidence Ltd.

Web:   http://codefidence.com
Cell:  +972-52-8260388
Skype: gilad_codefidence
Tel:   +972-8-9316883 ext. 201
Fax:   +972-8-9316884
Email: gilad@codefidence.com

Check out our Open Source technology and training blog - http://tuxology.net

	"The biggest risk you can take it is to take no risk."
		-- Mark Zuckerberg and probably others


^ permalink raw reply

* [PATCH 1/1] Use defaults when no route options are available
From: Gilad Ben-Yossef @ 2009-11-03 19:21 UTC (permalink / raw)
  To: Valdis.Kletnieks; +Cc: netdev, ori, linux-kernel, Andrew Morton
In-Reply-To: <4AF07024.80103@gmail.com>

Trying to parse the option of a SYN packet that we have
no route entry for should just use global wide defaults
for route entry options.

Signed-off-by: Gilad Ben-Yossef <gilad@codefidence.com>
---
 include/net/dst.h    |    2 +-
 net/ipv4/tcp_input.c |    2 --
 2 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/include/net/dst.h b/include/net/dst.h
index b562be3..0654c27 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -114,7 +114,7 @@ dst_metric(const struct dst_entry *dst, int metric)
 static inline u32
 dst_feature(const struct dst_entry *dst, u32 feature)
 {
-	return dst_metric(dst, RTAX_FEATURES) & feature;
+	return (dst ? dst_metric(dst, RTAX_FEATURES) & feature : 0);
 }
 
 static inline u32 dst_mtu(const struct dst_entry *dst)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 4262da5..57e99e1 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3704,8 +3704,6 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
 	struct tcphdr *th = tcp_hdr(skb);
 	int length = (th->doff * 4) - sizeof(struct tcphdr);
 
-	BUG_ON(!estab && !dst);
-
 	ptr = (unsigned char *)(th + 1);
 	opt_rx->saw_tstamp = 0;
 
-- 
1.5.6.3


^ permalink raw reply related

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Gregory Haskins @ 2009-11-03 19:50 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Michael S. Tsirkin, netdev, virtualization, kvm, linux-kernel,
	mingo, linux-mm, akpm, hpa, Rusty Russell, s.hetze,
	Paul E. McKenney
In-Reply-To: <4AF07BB7.1020802@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1995 bytes --]

Eric Dumazet wrote:
> Gregory Haskins a écrit :
>> Gregory Haskins wrote:
>>> Eric Dumazet wrote:
>>>> Michael S. Tsirkin a écrit :

>>>> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
>>>> that your use of RCU is not correct.
>>>>
>>>> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
>>>>    we are not allowed to sleep in such a section.
>>>>    (Quoting Documentation/RCU/whatisRCU.txt :
>>>>      It is illegal to block while in an RCU read-side critical section, )
>>>>
>>>> 2) mutex_lock() can sleep (ie block)
>>>>
>>> Michael,
>>>   I warned you that this needed better documentation ;)
>>>
>>> Eric,
>>>   I think I flagged this once before, but Michael convinced me that it
>>> was indeed "ok", if but perhaps a bit unconventional.  I will try to
>>> find the thread.
>>>
>>> Kind Regards,
>>> -Greg
>>>
>> Here it is:
>>
>> http://lkml.org/lkml/2009/8/12/173
>>
> 
> Yes, this doesnt convince me at all, and could be a precedent for a wrong RCU use.
> People wanting to use RCU do a grep on kernel sources to find how to correctly
> use RCU.
> 
> Michael, please use existing locking/barrier mechanisms, and not pretend to use RCU.

Yes, I would tend to agree with you.  In fact, I think I suggested that
a normal barrier should be used instead of abusing rcu_dereference().

But as far as his code is concerned, I think it technically works
properly, and that was my main point.  Also note that the usage
rcu_dereference+mutex_lock() are not necessarily broken, per se:  it
could be an srcu-based critical section created by the caller, for
instance.  It would be perfectly legal to sleep on the mutex if that
were the case.

To me, the bigger issue is that the rcu_dereference() without any
apparent hint of a corresponding RSCS is simply confusing as a reviewer.
 smp_rmb() (or whatever is proper in this case) is probably more
appropriate.

Kind Regards,
-Greg



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 267 bytes --]

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-03 19:55 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: netdev, virtualization, kvm, linux-kernel, mingo, linux-mm, akpm,
	hpa, gregory.haskins, Rusty Russell, s.hetze, Paul E. McKenney
In-Reply-To: <4AF0708B.4020406@gmail.com>

On Tue, Nov 03, 2009 at 07:03:55PM +0100, Eric Dumazet wrote:
> Michael S. Tsirkin a écrit :
> > +static void handle_tx(struct vhost_net *net)
> > +{
> > +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> > +	unsigned head, out, in, s;
> > +	struct msghdr msg = {
> > +		.msg_name = NULL,
> > +		.msg_namelen = 0,
> > +		.msg_control = NULL,
> > +		.msg_controllen = 0,
> > +		.msg_iov = vq->iov,
> > +		.msg_flags = MSG_DONTWAIT,
> > +	};
> > +	size_t len, total_len = 0;
> > +	int err, wmem;
> > +	size_t hdr_size;
> > +	struct socket *sock = rcu_dereference(vq->private_data);
> > +	if (!sock)
> > +		return;
> > +
> > +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> > +	if (wmem >= sock->sk->sk_sndbuf)
> > +		return;
> > +
> > +	use_mm(net->dev.mm);
> > +	mutex_lock(&vq->mutex);
> > +	vhost_no_notify(vq);
> > +
> 
> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
> that your use of RCU is not correct.
> 
> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
>    we are not allowed to sleep in such a section.
>    (Quoting Documentation/RCU/whatisRCU.txt :
>      It is illegal to block while in an RCU read-side critical section, )
> 
> 2) mutex_lock() can sleep (ie block)

This use is correct. See comment in vhost.h This use of RCU has been
acked by Paul E. McKenney (paulmck@linux.vnet.ibm.com) as well.
There are many ways to use RCU not all of which involve read_rcu_lock.

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

^ permalink raw reply

* Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server
From: Michael S. Tsirkin @ 2009-11-03 19:58 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Gregory Haskins, netdev, virtualization, kvm, linux-kernel, mingo,
	linux-mm, akpm, hpa, Rusty Russell, s.hetze, Paul E. McKenney
In-Reply-To: <4AF07BB7.1020802@gmail.com>

On Tue, Nov 03, 2009 at 07:51:35PM +0100, Eric Dumazet wrote:
> Gregory Haskins a écrit :
> > Gregory Haskins wrote:
> >> Eric Dumazet wrote:
> >>> Michael S. Tsirkin a écrit :
> >>>> +static void handle_tx(struct vhost_net *net)
> >>>> +{
> >>>> +	struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_TX];
> >>>> +	unsigned head, out, in, s;
> >>>> +	struct msghdr msg = {
> >>>> +		.msg_name = NULL,
> >>>> +		.msg_namelen = 0,
> >>>> +		.msg_control = NULL,
> >>>> +		.msg_controllen = 0,
> >>>> +		.msg_iov = vq->iov,
> >>>> +		.msg_flags = MSG_DONTWAIT,
> >>>> +	};
> >>>> +	size_t len, total_len = 0;
> >>>> +	int err, wmem;
> >>>> +	size_t hdr_size;
> >>>> +	struct socket *sock = rcu_dereference(vq->private_data);
> >>>> +	if (!sock)
> >>>> +		return;
> >>>> +
> >>>> +	wmem = atomic_read(&sock->sk->sk_wmem_alloc);
> >>>> +	if (wmem >= sock->sk->sk_sndbuf)
> >>>> +		return;
> >>>> +
> >>>> +	use_mm(net->dev.mm);
> >>>> +	mutex_lock(&vq->mutex);
> >>>> +	vhost_no_notify(vq);
> >>>> +
> >>> using rcu_dereference() and mutex_lock() at the same time seems wrong, I suspect
> >>> that your use of RCU is not correct.
> >>>
> >>> 1) rcu_dereference() should be done inside a read_rcu_lock() section, and
> >>>    we are not allowed to sleep in such a section.
> >>>    (Quoting Documentation/RCU/whatisRCU.txt :
> >>>      It is illegal to block while in an RCU read-side critical section, )
> >>>
> >>> 2) mutex_lock() can sleep (ie block)
> >>>
> >>
> >> Michael,
> >>   I warned you that this needed better documentation ;)
> >>
> >> Eric,
> >>   I think I flagged this once before, but Michael convinced me that it
> >> was indeed "ok", if but perhaps a bit unconventional.  I will try to
> >> find the thread.
> >>
> >> Kind Regards,
> >> -Greg
> >>
> > 
> > Here it is:
> > 
> > http://lkml.org/lkml/2009/8/12/173
> > 
> 
> Yes, this doesnt convince me at all, and could be a precedent for a wrong RCU use.
> People wanting to use RCU do a grep on kernel sources to find how to correctly
> use RCU.
> 
> Michael, please use existing locking/barrier mechanisms, and not pretend to use RCU.
> 
> Some automatic tools might barf later.
> 
> For example, we could add a debugging facility to check that rcu_dereference() is used
> in an appropriate context, ie conflict with existing mutex_lock() debugging facility.


Paul, you acked this previously. Should I add you acked-by line so
people calm down?  If you would rather I replace
rcu_dereference/rcu_assign_pointer with rmb/wmb, I can do this.
Or maybe patch Documentation to explain this RCU usage?

-- 
MST

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

^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Bartlomiej Zolnierkiewicz @ 2009-11-03 19:59 UTC (permalink / raw)
  To: Ivo van Doorn
  Cc: netdev, Randy Dunlap, Luis Correia, John W. Linville, Ingo Molnar,
	Johannes Berg, Jarek Poplawski, Pekka Enberg, David Miller,
	linux-wireless, linux-kernel
In-Reply-To: <200911021943.12069.IvDoorn@gmail.com>

On Monday 02 November 2009 19:43:10 Ivo van Doorn wrote:
> Well and then another rt2x00 developer discovered this nice little
> fight about rt2x00 on the mailinglists...
> 
> First for the record, because at the start people where talking about the
> maintainership of rt2x00, one thing needs to be straight:
> 
> As mentioned in the MAINTAINERS file, the rt2x00 project is listed as maintainer
> for the rt2x00 drivers. The rt2x00 drivers include _all_ drivers in the
> drivers/net/wireless/rt2x00 folder.
> 
> At this time I am hold the position within the rt2x00 team which is making the
> decisions about the rt2x00 code and design.

rt2x00 doesn't "own" Linux Ralink support, ditto for rt2800 drivers.

This is not how things work here, sorry.

> I am also the one that is (N)Acks the patches from others when they are send
> to the rt2x00-users or linux-wireless mailinglist.

If you are not willing to stand behind your own patches, how do you expect
others to trust your judgment?

> As for my behavior in discussions:
> 
> I am doing my best to listen to all complains regarding the rt2x00 code and design and
> improve it if the complainer has a valid point. However, obviously I can disagree with
> the complainer and in that case I will explain to that person _why_ I disagree. It is up
> to the complainer to convince me that he is right, agree with my response, or whine.
> 
> Now as for more specific responses:
> 
> On Thursday 29 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > rt2800 drivers have their maintainers and I would like to know what they
> > are doing besides complaining about users and staging tree..
> 
> Working for Avanade, Zarafa and as freelancer for Linux Magazine.
> But I guess you mean rt2x00 specific work?
> Well that list consists of:
>  - Listening to people complain
>  - Responding to those people, because otherwise they complain that they are being ignored.
>  - Following bug reports, and request testing or additional information if required
>  - Bugfixing
>  - Reviewing patches from contributors
>  - Applying patches from contributors
>  - Discussing improvements over patches from contributors
> 
> Well nothing of this list should be new to you, but apparently you needed some confirmation.

I meant rt2800 support specifically, sorry if this was not clear.

The work on rt2800 drivers was started in the beginning of 2008 and after
few months you were already behind deadlines that you had set yourself:

	http://markmail.org/message/a753dws6tqytb3a4

During almost two years rt2x00 project didn't manage to produce working
support for rt2800..  in the meantime the world has moved on and we have
another chipset generation (rt30x0) to worry about, and also rt33xx one
on the horizon..

> On Thursday 29 October 2009, Johannes Berg wrote:
> > On Thu, 2009-10-29 at 07:20 -0700, David Miller wrote:
> > 
> > > In case you're concerned, I actually agree with John and others
> > > on this issue, and disagree with your position.
> > 
> > In this particular case, I think it makes more sense to duplicate the
> > code _especially_ because it's not working yet. That frees people
> > hacking on it of having to worry about breaking other devices.
> 
> Thank you Johannes, that is exactly what I was trying to tell Bartlomiej
> in the previous discussion.

Nope, it just adds needles development/maintenance burden since it will
make people lose fixes already applied to the working code, please see my
other mail.

> On Wednesday 28 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > I find it rather disappointing that all my review comments regarding
> > rt2800pci support were just completely ignored and then the initial
> > patch was merged just as it was..
> 
> Your code review comments were commented upon with my reasons
> why this code duplication exists. I even admitted that when the time is
> ready I will remove the code duplication.

The right time was two years ago when you were starting working on those
drivers.  IOW It shouldn't have happened in the first place.

I also have serious questions about transparency of the process and cannot
understand why it takes so long for the code to be pushed upstream.

commit 1761631 -- obvious bugfix and I'm pretty sure I've seen it in rt2x00
tree back in September (you're re-basing rt2x00 tree at random moments so it
is impossible to track the status of patches that you are handling).

rt2800pci patch itself has been getting dust in your tree since at least
April (it hasn't received any bigger updates since then)..

> On Thursday 29 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > Quite the contrary, I'm pretty confident that addressing my review concerns
> > would result in better RT28x00 / RT30x0 support in the very near future.
> 
> The review concerns regarding the duplicate code would only reduce the
> amount of code. It would not magically fix bugs (at least the chance of that
> would be quite small).

Please see my other mail.

> So far rt2800usb performs better then rt2800pci, and the difference gets
> only bigger when I use the exact same register initialization from rt2800usb
> in rt2800pci.
> 
> But Bartjmoiej knows that the register initialization can be exactly the same,
> from his experience with the staging drivers.
> So far hasn't been interested in sharing the knowledge in what must be
> changed in rt2800pci/usb to make them both work with the same register
> initialization.

The knowledge is all in your local copy of linux-next (I don't memorize
things like chipset initialization sequences) and in the review comments
that you have happily dismissed.

-- 
Bartlomiej Zolnierkiewicz

^ permalink raw reply

* Re: [PATCH 1/3] sysfs directory scaling: rbtree for dirent name lookups
From: Benjamin LaHaise @ 2009-11-03 20:01 UTC (permalink / raw)
  To: Greg KH
  Cc: Eric Dumazet, Eric W. Biederman, Octavian Purdila, netdev,
	Cosmin Ratiu, linux-kernel
In-Reply-To: <20091103035058.GA19515@kroah.com>

On Mon, Nov 02, 2009 at 07:50:58PM -0800, Greg KH wrote:
> On Sun, Nov 01, 2009 at 11:31:30AM -0500, Benjamin LaHaise wrote:
> > Use an rbtree in sysfs_dirent to speed up file lookup times
> > 
> > Systems with large numbers (tens of thousands and more) of network 
> > interfaces stress the sysfs code in ways that make the linear search for 
> > a name match take far too long.  Avoid this by using an rbtree.
> 
> What kind of speedups are you seeing here?  And do these changes cause a
> memory increase due to the structure changes which outweigh the
> speedups?

Depends on the number of interfaces being created.  Without the patch, 
interface creation time tends to double or worse for every 5,000-10,000 
additional network interfaces.

> What kind of test are you doing to reproduce this?

I'm creating 30,000+ network interfaces, with the goal being 100,000.  
With other hacks in the tree to get around the sysctl and procfs scaling 
issues, as well as disabling things like NetworkManager, the results look 
as follows:

	Interfaces	no-rb	rbtree	rbtree+list
	0-5,000		13.8s	14.0s	13.0s
	5,000-10,000	20.0s	17.4s	14.4s
	10,000-15,000	27.3s	24.1s	16.9s
	15,000-20,000	36.3s	32.2s	19.7s
	20,000-25,000	45.2s	40.0s	22.9s
	25,000-30,000	54.2s	48.2s	26.6s
	30,000-35,000	63.9s	54.9s	30.7s

Thoughts?

		-ben

^ permalink raw reply

* CLONE_NEWNET requires CAP_NET_RAW (and the intended CAP_SYS_ADMIN)
From: Eric Paris @ 2009-11-03 20:15 UTC (permalink / raw)
  To: netdev; +Cc: nhorman, acme, dwalsh

We just saw today, because vsftpd just started using by default, that
CLONE_NEWNET requires both the intended CAP_SYS_ADMIN (see
kernel/nsproxy.c::copy_namespace()) and the unintended CAP_NET_RAW.
This is because tcp_sk_init() calls inet_ctl_sock_create() with
SOCK_RAW.  Ultimately we end up in inet_create() which see that
answer->capability is equal to CAP_NET_RAW.  So now it checks
capable(CAP_NET_RAW).

What you will find is that the generic __sock_create() has an argument
"int kern" which is passed to the security server to bypass checks which
were caused by the kernel, not because of userspace.  That flag is not
passed down to the create() function in struct net_proto_family.  I
think the easiest solution is to add the kern argument to the
net_proto_family create function and pass it along to the security
system so it can make the right decision.

I also see that the whole capability checking in struct inet_protosw
(and can, dccp, and sctp) seem overly complicated.  Most of it (all but
inet) could just be deleted since they aren't doing anything.  Inet
could replace it with just a single if (SOCK_RAW) which make the
security server changes very simple....

Did I explain my problem (I don't want to check CAP_NET_RAW)?  Do people
see an issue with me passing kern down to create?  Anyone have problems
with me ripping out the half ass unused security infrastructure?

-Eric


^ permalink raw reply

* Re: pull request: wireless-next-2.6 2009-10-28
From: Ivo van Doorn @ 2009-11-03 20:32 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz
  Cc: netdev, Randy Dunlap, Luis Correia, John W. Linville, Ingo Molnar,
	Johannes Berg, Jarek Poplawski, Pekka Enberg, David Miller,
	linux-wireless, linux-kernel
In-Reply-To: <200911032059.23409.bzolnier@gmail.com>

On Tuesday 03 November 2009, Bartlomiej Zolnierkiewicz wrote:
> On Monday 02 November 2009 19:43:10 Ivo van Doorn wrote:
> > Well and then another rt2x00 developer discovered this nice little
> > fight about rt2x00 on the mailinglists...
> > 
> > First for the record, because at the start people where talking about the
> > maintainership of rt2x00, one thing needs to be straight:
> > 
> > As mentioned in the MAINTAINERS file, the rt2x00 project is listed as maintainer
> > for the rt2x00 drivers. The rt2x00 drivers include _all_ drivers in the
> > drivers/net/wireless/rt2x00 folder.
> > 
> > At this time I am hold the position within the rt2x00 team which is making the
> > decisions about the rt2x00 code and design.
> 
> rt2x00 doesn't "own" Linux Ralink support, ditto for rt2800 drivers.

You really have problems reading mails, haven't you? Or at least you
only want to read what you want to read...

Please READ the paragraph again.
 
I will highlight the thing again:
"about the rt2x00 code and design"

I am not talking about Ralink support I am talking about RT2X00 support.

If you feel that the maintainer of a particular driver has no say about the driver
he wrote himself, then I am not seeing the point of having maintainers. We can
then all just randomly hack in all drivers without any form of structure.

> > I am also the one that is (N)Acks the patches from others when they are send
> > to the rt2x00-users or linux-wireless mailinglist.
> 
> If you are not willing to stand behind your own patches, how do you expect
> others to trust your judgment?

Ehm, please explain? I am sending patches upstream, but apparently I don't stand behind them?
Then why the f*** am I sending them?

> > As for my behavior in discussions:
> > 
> > I am doing my best to listen to all complains regarding the rt2x00 code and design and
> > improve it if the complainer has a valid point. However, obviously I can disagree with
> > the complainer and in that case I will explain to that person _why_ I disagree. It is up
> > to the complainer to convince me that he is right, agree with my response, or whine.
> > 
> > Now as for more specific responses:
> > 
> > On Thursday 29 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > > rt2800 drivers have their maintainers and I would like to know what they
> > > are doing besides complaining about users and staging tree..
> > 
> > Working for Avanade, Zarafa and as freelancer for Linux Magazine.
> > But I guess you mean rt2x00 specific work?
> > Well that list consists of:
> >  - Listening to people complain
> >  - Responding to those people, because otherwise they complain that they are being ignored.
> >  - Following bug reports, and request testing or additional information if required
> >  - Bugfixing
> >  - Reviewing patches from contributors
> >  - Applying patches from contributors
> >  - Discussing improvements over patches from contributors
> > 
> > Well nothing of this list should be new to you, but apparently you needed some confirmation.
> 
> I meant rt2800 support specifically, sorry if this was not clear.
> 
> The work on rt2800 drivers was started in the beginning of 2008 and after
> few months you were already behind deadlines that you had set yourself:
> 
> 	http://markmail.org/message/a753dws6tqytb3a4
> 
> During almost two years rt2x00 project didn't manage to produce working
> support for rt2800..  in the meantime the world has moved on and we have
> another chipset generation (rt30x0) to worry about, and also rt33xx one
> on the horizon..

And thank you for your valuable effort in assisting in the driver development
during those 2 years. I am really happy about people looking from the sideline
and complaining things are not moving as fast as they would like it.
If you cared about the slow progress, then you had the past 2 years to help out,
but apparently that is too much to ask. Unfortunately a lot of people think like
you, which means that during those 2 years dozens of people have complained
about the lack of progress without any of them helping out (and I am not talking
about users only, I am also talking about people who have programming skills).

If you look at the Signed-off list of the rt2800pci/usb patches you will see that
only a handfull of people actually helped.

> > On Thursday 29 October 2009, Johannes Berg wrote:
> > > On Thu, 2009-10-29 at 07:20 -0700, David Miller wrote:
> > > 
> > > > In case you're concerned, I actually agree with John and others
> > > > on this issue, and disagree with your position.
> > > 
> > > In this particular case, I think it makes more sense to duplicate the
> > > code _especially_ because it's not working yet. That frees people
> > > hacking on it of having to worry about breaking other devices.t initialization sequences) and in the review 
> > 
> > Thank you Johannes, that is exactly what I was trying to tell Bartlomiej
> > in the previous discussion.
> 
> Nope, it just adds needles development/maintenance burden since it will
> make people lose fixes already applied to the working code, please see my
> other mail.

As mentioned in my mail, there were differences in the drivers during development,
and I had a working rt2800usb driver as base. But with the same settings the rt2800pci
couldn't get to work.

With the merged drivers you would constantly need to check if it works for rt2800pci,
but also if you haven't broken rt2800usb in the meantime. This way rt2800usb was
able to be merged months before rt2800pci because there was no common code.

Once both drivers are solid working, then there are no problems with merging them,
I wonder how many times I have to repeat that...

> > On Wednesday 28 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > > I find it rather disappointing that all my review comments regarding
> > > rt2800pci support were just completely ignored and then the initial
> > > patch was merged just as it was..
> > 
> > Your code review comments were commented upon with my reasons
> > why this code duplication exists. I even admitted that when the time is
> > ready I will remove the code duplication.
> 
> The right time was two years ago when you were starting working on those
> drivers.  IOW It shouldn't have happened in the first place.

Please see my other mail, please read my above comment, and thank you again
for participating in the rt2800 development of those 2 years.

> I also have serious questions about transparency of the process and cannot
> understand why it takes so long for the code to be pushed upstream.

So you start looking now, and complain you can't see the process of the last 2 years?
There have been dozens of status reports regarding rt2800, and the number of responses
in general have always been limited.

But now I reread that last sentence, you are complaining that rt2800pci wasn't pushed
upstream earlier? While this whole discussion is about that merging rt2800pci was a bad
idea?

> commit 1761631 -- obvious bugfix and I'm pretty sure I've seen it in rt2x00
> tree back in September (you're re-basing rt2x00 tree at random moments so it
> is impossible to track the status of patches that you are handling).

I'm missing the point here.

> rt2800pci patch itself has been getting dust in your tree since at least
> April (it hasn't received any bigger updates since then)..

And how many times do I have to repeat the reason?
I think that after dozens of mails, the message should have been clear, especially
to somebody who apparently has been monitoring and worrying about the development
process for the last 2 years....

> > On Thursday 29 October 2009, Bartlomiej Zolnierkiewicz wrote:
> > > Quite the contrary, I'm pretty confident that addressing my review concerns
> > > would result in better RT28x00 / RT30x0 support in the very near future.
> > 
> > The review concerns regarding the duplicate code would only reduce the
> > amount of code. It would not magically fix bugs (at least the chance of that
> > would be quite small).
> 
> Please see my other mail.

And did your patches make rt2800pci work better?
Does rt2800usb suddenly work for 11n networks?

> > So far rt2800usb performs better then rt2800pci, and the difference gets
> > only bigger when I use the exact same register initialization from rt2800usb
> > in rt2800pci.
> > 
> > But Bartjmoiej knows that the register initialization can be exactly the same,
> > from his experience with the staging drivers.
> > So far hasn't been interested in sharing the knowledge in what must be
> > changed in rt2800pci/usb to make them both work with the same register
> > initialization.
> 
> The knowledge is all in your local copy of linux-next (I don't memorize
> things like chipset initialization sequences) and in the review comments
> that you have happily dismissed.

Your review comments were regarding _moving_ code to a generic stack
for rt2800pci and rt2800usb while I already indicated that would not improve
the status of rt2800pci (instead it would make it worse, since I already tested
if those settings would work). But apparently merging the code is better then
fixing the code.

Ivo

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox