Skip to contentSkip to conversation

tun: export underlying socket

PATCH Superseded Michael S. Tsirkin 7 participants 66 messages Nov 3, 2009 – Nov 8, 2009 1 message not in the archive

Subsystems (10)

v7 of 9 Superseded Latest is v9 →

lore
Share & tools
lore

Michael S. Tsirkin

author maintainer
#1 lore raw

PATCH v7 1/3 tun: export underlying socket

In reply to a message not in the archive

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.

---

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(-)
drivers/net/tun.c +82 -19
index 4fdfa2a..18f8876 100644
@@ -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);
include/linux/if_tun.h +14 -0
index 3f5fd52..404abe0 100644
@@ -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 */
Signature · 7 lines
1.6.5.2.143.g8cc62

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

PATCH v7 1/3 tun: export underlying socket

In reply to a message not in the archive

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.

---

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(-)
drivers/net/tun.c +82 -19
index 4fdfa2a..18f8876 100644
@@ -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);
include/linux/if_tun.h +14 -0
index 3f5fd52..404abe0 100644
@@ -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 */
Signature · 1 line
1.6.5.2.143.g8cc62
author maintainer
#5 lore raw

PATCH v7 2/3 mm: export use_mm/unuse_mm to modules

In reply to a message not in the archive

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

---
 mm/mmu_context.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
mm/mmu_context.c +3 -0
index ded9081..0777654 100644
@@ -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);
Signature · 7 lines
1.6.5.2.143.g8cc62

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

PATCH v7 2/3 mm: export use_mm/unuse_mm to modules

In reply to a message not in the archive

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

---
 mm/mmu_context.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
mm/mmu_context.c +3 -0
index ded9081..0777654 100644
@@ -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);
Signature · 1 line
1.6.5.2.143.g8cc62
author maintainer
#9 lore raw

PATCH v7 3/3 vhost_net: a kernel-level virtio server

In reply to a message not in the archive

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

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration, 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

---
 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
MAINTAINERS +9 -0
index 8824115..980a69b 100644
@@ -5619,6 +5619,15 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VIRTIO HOST (VHOST)
+M:	"Michael S. Tsirkin" <[email protected]>
+L:	[email protected]
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	drivers/vhost/
+F:	include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:	Roger Luethi <[email protected]>
 S:	Maintained
arch/x86/kvm/Kconfig +1 -0
index b84e571..94f44d9 100644
@@ -64,6 +64,7 @@ config KVM_AMD
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
drivers/Makefile +1 -0
index 6ee53c7..81e3659 100644
@@ -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/
drivers/vhost/Kconfig new file +11 -0
new file mode 100644
index 0000000..d955406
@@ -0,0 +1,11 @@
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.
+
drivers/vhost/Makefile new file +2 -0
new file mode 100644
index 0000000..72dd020
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
drivers/vhost/net.c new file +633 -0

633 lines not on this page · raw message

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

970 lines not on this page · raw message

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

158 lines not on this page · raw message

include/linux/Kbuild +1 -0
index 3f384d4..b6335c6 100644
@@ -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
include/linux/miscdevice.h +1 -0
index adaf3c1..8b5f7cc 100644
@@ -30,6 +30,7 @@
 #define HPET_MINOR		228
 #define FUSE_MINOR		229
 #define KVM_MINOR		232
+#define VHOST_NET_MINOR		233
 #define MISC_DYNAMIC_MINOR	255
 
 struct device;
include/linux/vhost.h new file +126 -0

126 lines not on this page · raw message

Signature · 7 lines
1.6.5.2.143.g8cc62

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

PATCH v7 3/3 vhost_net: a kernel-level virtio server

In reply to a message not in the archive

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

There's similarity with vringfd, with some differences and reduced scope
- uses eventfd for signalling
- structures can be moved around in memory at any time (good for migration, 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

---
 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
MAINTAINERS +9 -0
index 8824115..980a69b 100644
@@ -5619,6 +5619,15 @@ S:	Maintained
 F:	Documentation/filesystems/vfat.txt
 F:	fs/fat/
 
+VIRTIO HOST (VHOST)
+M:	"Michael S. Tsirkin" <[email protected]>
+L:	[email protected]
+L:	[email protected]
+L:	[email protected]
+S:	Maintained
+F:	drivers/vhost/
+F:	include/linux/vhost.h
+
 VIA RHINE NETWORK DRIVER
 M:	Roger Luethi <[email protected]>
 S:	Maintained
arch/x86/kvm/Kconfig +1 -0
index b84e571..94f44d9 100644
@@ -64,6 +64,7 @@ config KVM_AMD
 
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
+source drivers/vhost/Kconfig
 source drivers/lguest/Kconfig
 source drivers/virtio/Kconfig
 
drivers/Makefile +1 -0
index 6ee53c7..81e3659 100644
@@ -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/
drivers/vhost/Kconfig new file +11 -0
new file mode 100644
index 0000000..d955406
@@ -0,0 +1,11 @@
+config VHOST_NET
+	tristate "Host kernel accelerator for virtio net"
+	depends on NET && EVENTFD
+	---help---
+	  This kernel module can be loaded in host kernel to accelerate
+	  guest networking with virtio_net. Not to be confused with virtio_net
+	  module itself which needs to be loaded in guest kernel.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called vhost_net.
+
drivers/vhost/Makefile new file +2 -0
new file mode 100644
index 0000000..72dd020
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VHOST_NET) += vhost_net.o
+vhost_net-y := vhost.o net.o
drivers/vhost/net.c new file +633 -0

633 lines not on this page · raw message

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

970 lines not on this page · raw message

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

158 lines not on this page · raw message

include/linux/Kbuild +1 -0
index 3f384d4..b6335c6 100644
@@ -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
include/linux/miscdevice.h +1 -0
index adaf3c1..8b5f7cc 100644
@@ -30,6 +30,7 @@
 #define HPET_MINOR		228
 #define FUSE_MINOR		229
 #define KVM_MINOR		232
+#define VHOST_NET_MINOR		233
 #define MISC_DYNAMIC_MINOR	255
 
 struct device;
include/linux/vhost.h new file +126 -0

126 lines not on this page · raw message

Signature · 1 line
1.6.5.2.143.g8cc62
Acked-by on v7 2/3
#6 lore raw

Re: [PATCHv7 2/3] mm: export use_mm/unuse_mm to modules

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

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

I need this too:

Quoted 29 lines
---
 mm/mmu_context.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
mm/mmu_context.c +3 -0
index ded9081..0777654 100644
@@ -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);
Acked-by on v7 2/3
#7 lore raw

Re: [PATCHv7 2/3] mm: export use_mm/unuse_mm to modules

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

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

I need this too:

Quoted 25 lines
---
 mm/mmu_context.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
mm/mmu_context.c +2 -0
index ded9081..0777654 100644
@@ -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

mm/mmu_context.c void unuse_mm(struct mm_struct *mm) · line 61

Quoted 4 lines
mm/mmu_context.c +1 -0
@@ -56,3 +58,4 @@ void unuse_mm(struct mm_struct *mm)
 	enter_lazy_tlb(mm, tsk);
 	task_unlock(tsk);
 }
+EXPORT_SYMBOL_GPL(unuse_mm);

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#10 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+		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 [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#47 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

#11 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 32 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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

#44 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 32 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#12 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 44 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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 ;)

Quoted 8 lines

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

#43 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 44 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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 ;)

Quoted 8 lines

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

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#13 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 48 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 8 lines
Quoted 3 lines

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 [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#22 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 48 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 8 lines
Quoted 3 lines

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.

#14 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 28 lines · Eric Dumazet
Quoted 27 lines · Gregory Haskins
Quoted 16 lines · Gregory Haskins
Quoted 5 lines · Eric Dumazet

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.

Quoted 7 lines

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 ;)

Quoted 8 lines

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:

Quoted 8 lines
Quoted 2 lines

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

#15 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 28 lines · Eric Dumazet
Quoted 27 lines · Gregory Haskins
Quoted 16 lines · Gregory Haskins
Quoted 5 lines · Eric Dumazet

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.

Quoted 7 lines

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 ;)

Quoted 8 lines

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:

Quoted 8 lines
Quoted 2 lines

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

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

author maintainer
#45 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 32 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 6 lines

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 ([email protected]) 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 [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

author maintainer
#46 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 32 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 6 lines

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 ([email protected]) as well. There are many ways to use RCU not all of which involve read_rcu_lock.

author maintainer
#16 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 63 lines · Eric Dumazet
Quoted 49 lines · Gregory Haskins
Quoted 48 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 8 lines
Quoted 3 lines

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.

Quoted 6 lines

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?

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 63 lines · Eric Dumazet
Quoted 49 lines · Gregory Haskins
Quoted 48 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 8 lines
Quoted 3 lines

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.

Quoted 6 lines

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?

Signature · 1 line
MST
#17 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

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

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?

So you believe I am over-reacting to this dubious use of RCU ?

RCU documentation is already very complex, we dont need to add yet another subtle use, and makes it less readable.

It seems you use 'RCU api' in drivers/vhost/net.c as convenient macros :

#define rcu_dereference(p)     ({ \
                                typeof(p) _________p1 = ACCESS_ONCE(p); \
                                smp_read_barrier_depends(); \
                                (_________p1); \
                                })
#define rcu_assign_pointer(p, v) \
        ({ \
                if (!__builtin_constant_p(v) || \
                    ((v) != NULL)) \
                        smp_wmb(); \
                (p) = (v); \
        })

There are plenty regular uses of smp_wmb() in kernel, not related to Read Copy Update, there is nothing wrong to use barriers with appropriate comments.

(And you already use mb(), wmb(), rmb(), smp_wmb() in your patch)

BTW there is at least one locking bug in vhost_net_set_features()

Apparently, mutex_unlock() doesnt trigger a fault if mutex is not locked by current thread... even with DEBUG_MUTEXES / DEBUG_LOCK_ALLOC

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);
}

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

#20 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

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

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?

So you believe I am over-reacting to this dubious use of RCU ?

RCU documentation is already very complex, we dont need to add yet another subtle use, and makes it less readable.

It seems you use 'RCU api' in drivers/vhost/net.c as convenient macros :

#define rcu_dereference(p)     ({ \
                                typeof(p) _________p1 = ACCESS_ONCE(p); \
                                smp_read_barrier_depends(); \
                                (_________p1); \
                                })
#define rcu_assign_pointer(p, v) \
        ({ \
                if (!__builtin_constant_p(v) || \
                    ((v) != NULL)) \
                        smp_wmb(); \
                (p) = (v); \
        })

There are plenty regular uses of smp_wmb() in kernel, not related to Read Copy Update, there is nothing wrong to use barriers with appropriate comments.

(And you already use mb(), wmb(), rmb(), smp_wmb() in your patch)

BTW there is at least one locking bug in vhost_net_set_features()

Apparently, mutex_unlock() doesnt trigger a fault if mutex is not locked by current thread... even with DEBUG_MUTEXES / DEBUG_LOCK_ALLOC

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);
}
#23 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.

So what is the story? Using synchronize_irq() or some such?

Thanx, Paul

#42 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Gregory Haskins
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.

So what is the story? Using synchronize_irq() or some such?

Thanx, Paul

#48 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin

"Michael S. Tsirkin" <[email protected]> writes:

Haven't really read the whole thing, just noticed something at a glance.

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

drivers/vhost/net.c line 119

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	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);

I haven't gone over all this code in detail, but that isolated reference count use looks suspicious. What prevents the mm from going away before you increment, if it's not the current one?

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#65 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin

"Michael S. Tsirkin" <[email protected]> writes:

Haven't really read the whole thing, just noticed something at a glance.

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

drivers/vhost/net.c line 119

Quoted 10 lines
drivers/vhost/net.c new file +10 -0
+	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);

I haven't gone over all this code in detail, but that isolated reference count use looks suspicious. What prevents the mm from going away before you increment, if it's not the current one?

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
author maintainer
#24 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 67 lines · Paul E. McKenney
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

Quoted 6 lines

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.
So what is the story? Using synchronize_irq() or some such?

Thanx, Paul

No, there has been no change (I won't be able to use a mutex in an interrupt handler, will I?). handle_tx is still called in the context of a work queue: either from handle_tx_kick or from handle_tx_net which are work queue items.

Can you ack this usage please?

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 67 lines · Paul E. McKenney
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

Quoted 6 lines

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.
So what is the story? Using synchronize_irq() or some such?

Thanx, Paul

No, there has been no change (I won't be able to use a mutex in an interrupt handler, will I?). handle_tx is still called in the context of a work queue: either from handle_tx_kick or from handle_tx_net which are work queue items.

Can you ack this usage please?

Signature · 1 line
MST
author maintainer
#18 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 30 lines · Eric Dumazet
Quoted 6 lines · Michael S. Tsirkin

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?

So you believe I am over-reacting to this dubious use of RCU ?

RCU documentation is already very complex, we dont need to add yet another subtle use, and makes it less readable.

It seems you use 'RCU api' in drivers/vhost/net.c as convenient macros :

#define rcu_dereference(p)     ({ \
                                typeof(p) _________p1 = ACCESS_ONCE(p); \
                                smp_read_barrier_depends(); \
                                (_________p1); \
                                })
#define rcu_assign_pointer(p, v) \
        ({ \
                if (!__builtin_constant_p(v) || \
                    ((v) != NULL)) \
                        smp_wmb(); \
                (p) = (v); \
        })
Quoted 2 lines

There are plenty regular uses of smp_wmb() in kernel, not related to Read Copy Update, there is nothing wrong to use barriers with appropriate comments.

Well, what I do has classic RCU characteristics: readers do not take locks, writers take a lock and flush after update. This is why I believe rcu_dereference and rcu_assign_pointer are more appropriate here than open-coding barriers.

Before deciding whether it's a good idea to open-code barriers instead, I would like to hear Paul's opinion.

Quoted 2 lines

(And you already use mb(), wmb(), rmb(), smp_wmb() in your patch)

Yes, virtio guest pretty much forces this, there's no way to share a lock with the guest.

Quoted 7 lines

BTW there is at least one locking bug in vhost_net_set_features()

Apparently, mutex_unlock() doesnt trigger a fault if mutex is not locked by current thread... even with DEBUG_MUTEXES / DEBUG_LOCK_ALLOC

static void vhost_net_set_features(struct vhost_net *n, u64 features)

Quoted 15 lines
{
       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);
}

Thanks very much for spotting this! Will fix.

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Eric Dumazet
Quoted 30 lines · Eric Dumazet
Quoted 6 lines · Michael S. Tsirkin

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?

So you believe I am over-reacting to this dubious use of RCU ?

RCU documentation is already very complex, we dont need to add yet another subtle use, and makes it less readable.

It seems you use 'RCU api' in drivers/vhost/net.c as convenient macros :

#define rcu_dereference(p)     ({ \
                                typeof(p) _________p1 = ACCESS_ONCE(p); \
                                smp_read_barrier_depends(); \
                                (_________p1); \
                                })
#define rcu_assign_pointer(p, v) \
        ({ \
                if (!__builtin_constant_p(v) || \
                    ((v) != NULL)) \
                        smp_wmb(); \
                (p) = (v); \
        })
Quoted 2 lines

There are plenty regular uses of smp_wmb() in kernel, not related to Read Copy Update, there is nothing wrong to use barriers with appropriate comments.

Well, what I do has classic RCU characteristics: readers do not take locks, writers take a lock and flush after update. This is why I believe rcu_dereference and rcu_assign_pointer are more appropriate here than open-coding barriers.

Before deciding whether it's a good idea to open-code barriers instead, I would like to hear Paul's opinion.

Quoted 2 lines

(And you already use mb(), wmb(), rmb(), smp_wmb() in your patch)

Yes, virtio guest pretty much forces this, there's no way to share a lock with the guest.

Quoted 7 lines

BTW there is at least one locking bug in vhost_net_set_features()

Apparently, mutex_unlock() doesnt trigger a fault if mutex is not locked by current thread... even with DEBUG_MUTEXES / DEBUG_LOCK_ALLOC

static void vhost_net_set_features(struct vhost_net *n, u64 features)

Quoted 15 lines
{
       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);
}

Thanks very much for spotting this! Will fix.

Signature · 1 line
MST
author maintainer
#49 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 26 lines · Andi Kleen

"Michael S. Tsirkin" <[email protected]> writes:

Haven't really read the whole thing, just noticed something at a glance.

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

drivers/vhost/net.c line 119

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	if (wmem >= sock->sk->sk_sndbuf)
+		return;
+
+	use_mm(net->dev.mm);

I haven't gone over all this code in detail, but that isolated reference count use looks suspicious. What prevents the mm from going away before you increment, if it's not the current one?

We take a reference to it before we start any virtqueues, and stop all virtqueues before we drop the reference:
/* 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;
}

And
vhost_dev_cleanup:
....

        if (dev->mm)
                mmput(dev->mm);
        dev->mm = NULL;
}

Fine?

Quoted 4 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.

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

author maintainer
#64 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 26 lines · Andi Kleen

"Michael S. Tsirkin" <[email protected]> writes:

Haven't really read the whole thing, just noticed something at a glance.

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

drivers/vhost/net.c line 119

Quoted 4 lines
drivers/vhost/net.c new file +4 -0
+	if (wmem >= sock->sk->sk_sndbuf)
+		return;
+
+	use_mm(net->dev.mm);

I haven't gone over all this code in detail, but that isolated reference count use looks suspicious. What prevents the mm from going away before you increment, if it's not the current one?

We take a reference to it before we start any virtqueues, and stop all virtqueues before we drop the reference:
/* 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;
}

And
vhost_dev_cleanup:
....

        if (dev->mm)
                mmput(dev->mm);
        dev->mm = NULL;
}

Fine?

Quoted 4 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
author maintainer
#51 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 1 line

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Quoted 3 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.

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

author maintainer
#62 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 1 line

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Quoted 3 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#52 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

No the reference to the device, which owns the mm for you.

Quoted 11 lines
Quoted 2 lines

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

Quoted 3 lines

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Do you protect against another thread doing RESET_OWNER in parallel while RESET_OWNER runs?

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#61 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

No the reference to the device, which owns the mm for you.

Quoted 11 lines
Quoted 2 lines

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

Quoted 3 lines

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Do you protect against another thread doing RESET_OWNER in parallel while RESET_OWNER runs?

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
author maintainer
#53 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 9 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Quoted 11 lines
Quoted 11 lines
Quoted 2 lines

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

Quoted 6 lines
Quoted 3 lines

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Do you protect against another thread doing RESET_OWNER in parallel while RESET_OWNER runs?

Yes, I have a mutex in the device for that. Same with SET_BACKEND.

Quoted 4 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.

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

author maintainer
#60 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 9 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Quoted 11 lines
Quoted 11 lines
Quoted 2 lines

(as in do you hold a reference to it?)

By design I think I always have a reference to mm before I use it.

This works like this:
ioctl SET_OWNER - calls get_task_mm, I think this gets a reference to mm ioctl SET_BACKEND - checks that SET_OWNER was run, starts virtqueue ioctl RESET_OWNER - stops virtqueues, drops the reference to mm file close - stops virtqueues, if we still have it then drops mm

Quoted 6 lines
Quoted 3 lines

This is why I think I can call use_mm/unuse_mm while virtqueue is running, safely.
Makes sense?

Do you protect against another thread doing RESET_OWNER in parallel while RESET_OWNER runs?

Yes, I have a mutex in the device for that. Same with SET_BACKEND.

Quoted 4 lines

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#54 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

I guess it would be a good way to confuse memory accounting schemes or administrators @)

It would be all saner if this was all a single atomic step.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#59 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

I guess it would be a good way to confuse memory accounting schemes or administrators @)

It would be all saner if this was all a single atomic step.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
author maintainer
#55 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 24 lines · Andi Kleen
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

Quoted 5 lines

I guess it would be a good way to confuse memory accounting schemes or administrators @)
It would be all saner if this was all a single atomic step.

-Andi

I have this atomic actually. A child process will first thing do SET_OWNER: this is required before any other operation.

SET_OWNER atomically (under mutex) does two things:
- check that there is no other owner
- get mm and set current process as owner

I hope this addresses your concern?

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Andi Kleen
Quoted 24 lines · Andi Kleen
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

Quoted 5 lines

I guess it would be a good way to confuse memory accounting schemes or administrators @)
It would be all saner if this was all a single atomic step.

-Andi

I have this atomic actually. A child process will first thing do SET_OWNER: this is required before any other operation.

SET_OWNER atomically (under mutex) does two things:
- check that there is no other owner
- get mm and set current process as owner

I hope this addresses your concern?

Signature · 1 line
MST
author maintainer
#56 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 31 lines · Michael S. Tsirkin
Quoted 24 lines · Andi Kleen
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

Quoted 5 lines

I guess it would be a good way to confuse memory accounting schemes or administrators @)
It would be all saner if this was all a single atomic step.

-Andi

Quoted 8 lines

I have this atomic actually. A child process will first thing do SET_OWNER: this is required before any other operation.

SET_OWNER atomically (under mutex) does two things:
- check that there is no other owner
- get mm and set current process as owner

I hope this addresses your concern?

Andrea, since you looked at this design at the early stages, maybe you can provide feedback on the following question:

vhost has an ioctl to do get_task_mm and store the mm in per-file device structure. mmput is called when file is closed. vhost is careful not to reference the mm after is has been put. There is also an atomic mutual exclusion mechanism to ensure that vhost does not allow one process to access another's mm, even if they share a vhost file descriptor. But, this still means that mm structure can outlive the task if the file descriptor is shared with another process.

Other drivers, such as kvm, have the same property.

Do you think this is OK?

Thanks!

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 31 lines · Michael S. Tsirkin
Quoted 24 lines · Andi Kleen
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines · Andi Kleen
Quoted 6 lines · Michael S. Tsirkin
Quoted 3 lines · Andi Kleen
Quoted 1 line

Fine?

I cannot say -- are there paths that could drop the device beforehand?

Do you mean drop the mm reference?

Quoted 7 lines
Quoted 1 line

No the reference to the device, which owns the mm for you.

The device is created when file is open and destroyed when file is closed. So I think the fs code handles the reference counting for me: it won't call file cleanup callback while some userspace process has the file open. Right?

Yes.

But the semantics when someone inherits such a fd through exec or through file descriptor passing would be surely "interesting" You would still do IO on the old VM.

Quoted 5 lines

I guess it would be a good way to confuse memory accounting schemes or administrators @)
It would be all saner if this was all a single atomic step.

-Andi

Quoted 8 lines

I have this atomic actually. A child process will first thing do SET_OWNER: this is required before any other operation.

SET_OWNER atomically (under mutex) does two things:
- check that there is no other owner
- get mm and set current process as owner

I hope this addresses your concern?

Andrea, since you looked at this design at the early stages, maybe you can provide feedback on the following question:

vhost has an ioctl to do get_task_mm and store the mm in per-file device structure. mmput is called when file is closed. vhost is careful not to reference the mm after is has been put. There is also an atomic mutual exclusion mechanism to ensure that vhost does not allow one process to access another's mm, even if they share a vhost file descriptor. But, this still means that mm structure can outlive the task if the file descriptor is shared with another process.

Other drivers, such as kvm, have the same property.

Do you think this is OK?

Thanks!

Signature · 1 line
MST
#25 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 73 lines · Michael S. Tsirkin
Quoted 72 lines · Paul E. McKenney
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.
So what is the story? Using synchronize_irq() or some such?

Quoted 6 lines
Quoted 1 line

Thanx, Paul

No, there has been no change (I won't be able to use a mutex in an interrupt handler, will I?). handle_tx is still called in the context of a work queue: either from handle_tx_kick or from handle_tx_net which are work queue items.

Ah, my mistake -- I was looking at 2.6.31 rather than latest git with your patches.

Quoted 1 line

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

I, Paul E. McKenney, maintainer of the RCU implmentation embodied in the Linux kernel and co-inventor of RCU, being of sound mind and body, notwithstanding the wear and tear inherent in my numerous decades sojourn on this planet, hereby declare that the following usage of work queues constitutes a valid RCU implementation:

1. Execution of a full workqueue item being substituted
for a conventional RCU read-side critical section, so that the start of execution of the function specified to INIT_WORK() corresponds to rcu_read_lock(), and the end of this self-same function corresponds to rcu_read_unlock().

2. Execution of flush_workqueue() being substituted for
the conventional synchronize_rcu().

The kernel developer availing himself or herself of this declaration must observe the following caveats:

a. The function specified to INIT_WORK() may only be
invoked via the workqueue mechanism. Invoking said function directly renders this declaration null and void, as it prevents the flush_workqueue() function from delivering the fundamental guarantee inherent in RCU.

b. At some point in the future, said developer may be
required to apply some gcc attribute or sparse annotation
to the function passed to INIT_WORK(). Beyond that
point, failure to comply will render this declaration null and void, as such failure would render inoperative some potential RCU-validation tools, as duly noted by Eric Dumazet.

c. This declaration in no way relieves the developer of
the responsibility to use this and other synchronization mechanisms correctly, again, as duly noted by Eric Dumazet.

(Sorry, but, as always, I could not resist!)

Thanx, Paul

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

#40 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 73 lines · Michael S. Tsirkin
Quoted 72 lines · Paul E. McKenney
Quoted 50 lines · Gregory Haskins
Quoted 49 lines · Gregory Haskins
Quoted 31 lines · Eric Dumazet
Quoted 17 lines · Michael S. Tsirkin
drivers/vhost/net.c new file +17 -0
+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)

drivers/vhost/net.c line 122

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

Quoted 7 lines

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.

Quoted 7 lines
Quoted 3 lines

Kind Regards,
-Greg

Here it is:

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

What was happening in that case was that the rcu_dereference() was being used in a workqueue item. The role of rcu_read_lock() was taken on be the start of execution of the workqueue item, of rcu_read_unlock() by the end of execution of the workqueue item, and of synchronize_rcu() by flush_workqueue(). This does work, at least assuming that flush_workqueue() operates as advertised, which it appears to at first glance.

The above code looks somewhat different, however -- I don't see handle_tx() being executed in the context of a work queue. Instead it appears to be in an interrupt handler.
So what is the story? Using synchronize_irq() or some such?

Quoted 6 lines
Quoted 1 line

Thanx, Paul

No, there has been no change (I won't be able to use a mutex in an interrupt handler, will I?). handle_tx is still called in the context of a work queue: either from handle_tx_kick or from handle_tx_net which are work queue items.

Ah, my mistake -- I was looking at 2.6.31 rather than latest git with your patches.

Quoted 1 line

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

I, Paul E. McKenney, maintainer of the RCU implmentation embodied in the Linux kernel and co-inventor of RCU, being of sound mind and body, notwithstanding the wear and tear inherent in my numerous decades sojourn on this planet, hereby declare that the following usage of work queues constitutes a valid RCU implementation:

1. Execution of a full workqueue item being substituted
for a conventional RCU read-side critical section, so that the start of execution of the function specified to INIT_WORK() corresponds to rcu_read_lock(), and the end of this self-same function corresponds to rcu_read_unlock().

2. Execution of flush_workqueue() being substituted for
the conventional synchronize_rcu().

The kernel developer availing himself or herself of this declaration must observe the following caveats:

a. The function specified to INIT_WORK() may only be
invoked via the workqueue mechanism. Invoking said function directly renders this declaration null and void, as it prevents the flush_workqueue() function from delivering the fundamental guarantee inherent in RCU.

b. At some point in the future, said developer may be
required to apply some gcc attribute or sparse annotation
to the function passed to INIT_WORK(). Beyond that
point, failure to comply will render this declaration null and void, as such failure would render inoperative some potential RCU-validation tools, as duly noted by Eric Dumazet.

c. This declaration in no way relieves the developer of
the responsibility to use this and other synchronization mechanisms correctly, again, as duly noted by Eric Dumazet.

(Sorry, but, as always, I could not resist!)

Thanx, Paul

#26 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 2 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Yesssss :)

Thanks Paul for this masterpiece of diplomatic "Acked-by" ;)

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

#27 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 2 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Yesssss :)

Thanks Paul for this masterpiece of diplomatic "Acked-by" ;)

author maintainer
#28 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 3 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Thanx, Paul

Thanks Paul!
Jonathan: are you reading this?
Another one for your quotes of the week collection :)

Signature · 7 lines
MST

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

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 3 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Thanx, Paul

Thanks Paul!
Jonathan: are you reading this?
Another one for your quotes of the week collection :)

Signature · 1 line
MST
#29 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 9 lines · Michael S. Tsirkin
Quoted 3 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Thanx, Paul

Thanks Paul!
Jonathan: are you reading this?
Another one for your quotes of the week collection :)

I second that.

#30 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Michael S. Tsirkin
Quoted 9 lines · Michael S. Tsirkin
Quoted 3 lines · Paul E. McKenney

(Sorry, but, as always, I could not resist!)

Thanx, Paul

Thanks Paul!
Jonathan: are you reading this?
Another one for your quotes of the week collection :)

I second that.

_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/virtualization

#32 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 5 lines · Paul E. McKenney
Quoted 1 line · Michael S. Tsirkin

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

<snip verbose super-ack with qualifications>

That's great guys. And yes, this is a kind of read-copy-update. And no, there's nothing wrong with it.

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

Cheers,
Rusty.

#39 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 5 lines · Paul E. McKenney
Quoted 1 line · Michael S. Tsirkin

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

<snip verbose super-ack with qualifications>

That's great guys. And yes, this is a kind of read-copy-update. And no, there's nothing wrong with it.

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

Cheers,
Rusty.

#33 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 7 lines · Rusty Russell
Quoted 5 lines · Paul E. McKenney
Quoted 1 line · Michael S. Tsirkin

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

Quoted 8 lines

<snip verbose super-ack with qualifications>

That's great guys. And yes, this is a kind of read-copy-update. And no, there's nothing wrong with it.

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

Thanx, Paul

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

#38 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 7 lines · Rusty Russell
Quoted 5 lines · Paul E. McKenney
Quoted 1 line · Michael S. Tsirkin

Can you ack this usage please?

I thought I had done so in my paragraph above, but if you would like something a bit more formal...

Quoted 8 lines

<snip verbose super-ack with qualifications>

That's great guys. And yes, this is a kind of read-copy-update. And no, there's nothing wrong with it.

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

Thanx, Paul

#34 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 10 lines · Paul E. McKenney
Quoted 3 lines · Rusty Russell

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

You read correctly. If we get a second user, creating an API makes sense.

Thanks,
Rusty.

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

#37 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Paul E. McKenney
Quoted 10 lines · Paul E. McKenney
Quoted 3 lines · Rusty Russell

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

You read correctly. If we get a second user, creating an API makes sense.

Thanks,
Rusty.

#35 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 6 lines · Rusty Russell
Quoted 5 lines · Paul E. McKenney
Quoted 3 lines · Rusty Russell

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

Quoted 7 lines
Quoted 5 lines

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

You read correctly. If we get a second user, creating an API makes sense.

Makes sense to me as well. Which does provide some time to come up with a primitive designed to answer the question "Am I currently executing in the context of a workqueue item?". ;-)

Thanx, Paul

#36 lore raw

Re: [PATCHv7 3/3] vhost_net: a kernel-level virtio server

In reply to Rusty Russell
Quoted 6 lines · Rusty Russell
Quoted 5 lines · Paul E. McKenney
Quoted 3 lines · Rusty Russell

But it's still nasty to use half an API. If it were a few places I would have open-coded it with a comment, or wrapped it. As it is, I don't think that would be a win.

Quoted 7 lines
Quoted 5 lines

So would it help to have a rcu_read_lock_workqueue() and rcu_read_unlock_workqueue() that checked nesting and whether they were actually running in the context of a workqueue item? Or did you have something else in mind? Or am I misjudging the level of sarcasm in your reply? ;-)

You read correctly. If we get a second user, creating an API makes sense.

Makes sense to me as well. Which does provide some time to come up with a primitive designed to answer the question "Am I currently executing in the context of a workqueue item?". ;-)

Thanx, Paul