[PATCH net,stable v4 0/3] vhost: fix a few skb leaks

2017-12-01 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

v4:
- fix zero iov iterator count in tap/tap_do_read()(Jason)
- don't put tun in case of EBADFD(Jason)
- Replace msg->msg_control with new 'skb' when calling tun/tap_do_read()

v3:
- move freeing skb from vhost to tun/tap recvmsg() to not
  confuse the callers.

v2:
- add Matthew as the reporter, thanks matthew.
- moving zero headcount check ahead instead of defer consuming skb
  due to jason and mst's comment.
- add freeing skb in favor of recvmsg() fails.

Wei Xu (3):
  vhost: fix skb leak in handle_rx()
  tun: free skb in early errors
  tap: free skb if flags error

 drivers/net/tap.c   | 14 ++
 drivers/net/tun.c   | 24 ++--
 drivers/vhost/net.c | 20 ++--
 3 files changed, 38 insertions(+), 20 deletions(-)

-- 
1.8.3.1



[PATCH 1/3] vhost: fix skb leak in handle_rx()

2017-12-01 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

Eventually we figured out that it was a skb leak in handle_rx()
when sending packets to the VM. This usually happens when a guest
can not drain out vq as fast as vhost fills in, afterwards it sets
off the traffic jam and leaks skb(s) which occurs as no headcount
to send on the vq from vhost side.

This can be avoided by making sure we have got enough headcount
before actually consuming a skb from the batched rx array while
transmitting, which is simply done by moving checking the zero
headcount a bit ahead.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 
---
 drivers/vhost/net.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 8d626d7..c7bdeb6 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -778,16 +778,6 @@ static void handle_rx(struct vhost_net *net)
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
goto out;
-   if (nvq->rx_array)
-   msg.msg_control = vhost_net_buf_consume(>rxq);
-   /* On overrun, truncate and discard */
-   if (unlikely(headcount > UIO_MAXIOV)) {
-   iov_iter_init(_iter, READ, vq->iov, 1, 1);
-   err = sock->ops->recvmsg(sock, ,
-1, MSG_DONTWAIT | MSG_TRUNC);
-   pr_debug("Discarded rx packet: len %zd\n", sock_len);
-   continue;
-   }
/* OK, now we need to know about added descriptors. */
if (!headcount) {
if (unlikely(vhost_enable_notify(>dev, vq))) {
@@ -800,6 +790,16 @@ static void handle_rx(struct vhost_net *net)
 * they refilled. */
goto out;
}
+   if (nvq->rx_array)
+   msg.msg_control = vhost_net_buf_consume(>rxq);
+   /* On overrun, truncate and discard */
+   if (unlikely(headcount > UIO_MAXIOV)) {
+   iov_iter_init(_iter, READ, vq->iov, 1, 1);
+   err = sock->ops->recvmsg(sock, ,
+1, MSG_DONTWAIT | MSG_TRUNC);
+   pr_debug("Discarded rx packet: len %zd\n", sock_len);
+   continue;
+   }
/* We don't need to be notified again. */
iov_iter_init(_iter, READ, vq->iov, in, vhost_len);
fixup = msg.msg_iter;
-- 
1.8.3.1



[PATCH 2/3] tun: free skb in early errors

2017-12-01 Thread wexu
From: Wei Xu 

tun_recvmsg() supports accepting skb by msg_control after
commit ac77cfd4258f ("tun: support receiving skb through msg_control"),
the skb if presented should be freed no matter how far it can go
along, otherwise it would be leaked.

This patch fixes several missed cases.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 

---
 drivers/net/tun.c | 24 ++--
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9574900..4f4a842 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1952,8 +1952,11 @@ static ssize_t tun_do_read(struct tun_struct *tun, 
struct tun_file *tfile,
 
tun_debug(KERN_INFO, tun, "tun_do_read\n");
 
-   if (!iov_iter_count(to))
+   if (!iov_iter_count(to)) {
+   if (skb)
+   kfree_skb(skb);
return 0;
+   }
 
if (!skb) {
/* Read frames from ring */
@@ -2069,22 +2072,24 @@ static int tun_recvmsg(struct socket *sock, struct 
msghdr *m, size_t total_len,
 {
struct tun_file *tfile = container_of(sock, struct tun_file, socket);
struct tun_struct *tun = tun_get(tfile);
+   struct sk_buff *skb = m->msg_control;
int ret;
 
-   if (!tun)
-   return -EBADFD;
+   if (!tun) {
+   ret = -EBADFD;
+   goto out_free_skb;
+   }
 
if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) {
ret = -EINVAL;
-   goto out;
+   goto out_put_tun;
}
if (flags & MSG_ERRQUEUE) {
ret = sock_recv_errqueue(sock->sk, m, total_len,
 SOL_PACKET, TUN_TX_TIMESTAMP);
goto out;
}
-   ret = tun_do_read(tun, tfile, >msg_iter, flags & MSG_DONTWAIT,
- m->msg_control);
+   ret = tun_do_read(tun, tfile, >msg_iter, flags & MSG_DONTWAIT, skb);
if (ret > (ssize_t)total_len) {
m->msg_flags |= MSG_TRUNC;
ret = flags & MSG_TRUNC ? ret : total_len;
@@ -2092,6 +2097,13 @@ static int tun_recvmsg(struct socket *sock, struct 
msghdr *m, size_t total_len,
 out:
tun_put(tun);
return ret;
+
+out_put_tun:
+   tun_put(tun);
+out_free_skb:
+   if (skb)
+   kfree_skb(skb);
+   return ret;
 }
 
 static int tun_peek_len(struct socket *sock)
-- 
1.8.3.1



[PATCH 3/3] tap: free skb if flags error

2017-12-01 Thread wexu
From: Wei Xu 

tap_recvmsg() supports accepting skb by msg_control after
commit 3b4ba04acca8 ("tap: support receiving skb from msg_control"),
the skb if presented should be freed within the function, otherwise
it would be leaked.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 

---
 drivers/net/tap.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index e9489b8..0a886fda 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -829,8 +829,11 @@ static ssize_t tap_do_read(struct tap_queue *q,
DEFINE_WAIT(wait);
ssize_t ret = 0;
 
-   if (!iov_iter_count(to))
+   if (!iov_iter_count(to)) {
+   if (skb)
+   kfree_skb(skb);
return 0;
+   }
 
if (skb)
goto put;
@@ -1154,11 +1157,14 @@ static int tap_recvmsg(struct socket *sock, struct 
msghdr *m,
   size_t total_len, int flags)
 {
struct tap_queue *q = container_of(sock, struct tap_queue, sock);
+   struct sk_buff *skb = m->msg_control;
int ret;
-   if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+   if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) {
+   if (skb)
+   kfree_skb(skb);
return -EINVAL;
-   ret = tap_do_read(q, >msg_iter, flags & MSG_DONTWAIT,
- m->msg_control);
+   }
+   ret = tap_do_read(q, >msg_iter, flags & MSG_DONTWAIT, skb);
if (ret > total_len) {
m->msg_flags |= MSG_TRUNC;
ret = flags & MSG_TRUNC ? ret : total_len;
-- 
1.8.3.1



[PATCH 3/3] tap: free skb if flags error

2017-11-30 Thread wexu
From: Wei Xu 

tap_recvmsg() supports accepting skb by msg_control after
commit 3b4ba04acca8 ("tap: support receiving skb from msg_control"),
the skb if presented should be freed within the function, otherwise
it would be leaked.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 
---
 drivers/net/tap.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index e9489b8..1c66b75 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -1154,9 +1154,13 @@ static int tap_recvmsg(struct socket *sock, struct 
msghdr *m,
   size_t total_len, int flags)
 {
struct tap_queue *q = container_of(sock, struct tap_queue, sock);
+   struct sk_buff *skb = m->msg_control;
int ret;
-   if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
+   if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) {
+   if (skb)
+   kfree_skb(skb);
return -EINVAL;
+   }
ret = tap_do_read(q, >msg_iter, flags & MSG_DONTWAIT,
  m->msg_control);
if (ret > total_len) {
-- 
1.8.3.1



[PATCH 1/3] vhost: fix skb leak in handle_rx()

2017-11-30 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

Eventually we figured out that it was a skb leak in handle_rx()
when sending packets to the VM. This usually happens when a guest
can not drain out vq as fast as vhost fills in, afterwards it sets
off the traffic jam and leaks skb(s) which occurs as no headcount
to send on the vq from vhost side.

This can be avoided by making sure we have got enough headcount
before actually consuming a skb from the batched rx array while
transmitting, which is simply done by moving checking the zero
headcount a bit ahead.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 
---
 drivers/vhost/net.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 8d626d7..c7bdeb6 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -778,16 +778,6 @@ static void handle_rx(struct vhost_net *net)
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
goto out;
-   if (nvq->rx_array)
-   msg.msg_control = vhost_net_buf_consume(>rxq);
-   /* On overrun, truncate and discard */
-   if (unlikely(headcount > UIO_MAXIOV)) {
-   iov_iter_init(_iter, READ, vq->iov, 1, 1);
-   err = sock->ops->recvmsg(sock, ,
-1, MSG_DONTWAIT | MSG_TRUNC);
-   pr_debug("Discarded rx packet: len %zd\n", sock_len);
-   continue;
-   }
/* OK, now we need to know about added descriptors. */
if (!headcount) {
if (unlikely(vhost_enable_notify(>dev, vq))) {
@@ -800,6 +790,16 @@ static void handle_rx(struct vhost_net *net)
 * they refilled. */
goto out;
}
+   if (nvq->rx_array)
+   msg.msg_control = vhost_net_buf_consume(>rxq);
+   /* On overrun, truncate and discard */
+   if (unlikely(headcount > UIO_MAXIOV)) {
+   iov_iter_init(_iter, READ, vq->iov, 1, 1);
+   err = sock->ops->recvmsg(sock, ,
+1, MSG_DONTWAIT | MSG_TRUNC);
+   pr_debug("Discarded rx packet: len %zd\n", sock_len);
+   continue;
+   }
/* We don't need to be notified again. */
iov_iter_init(_iter, READ, vq->iov, in, vhost_len);
fixup = msg.msg_iter;
-- 
1.8.3.1



[PATCH net,stable v3] vhost: fix a few skb leaks

2017-11-30 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

This is v3.

v3:
- move freeing skb from vhost to tun/tap recvmsg() to not
  confuse the callers.

v2:
- add Matthew as the reporter, thanks matthew.
- moving zero headcount check ahead instead of defer consuming skb
  due to jason and mst's comment.
- add freeing skb in favor of recvmsg() fails.

Wei Xu (3):
  vhost: fix skb leak in handle_rx()
  tun: free skb in early errors
  tap: free skb if flags error

 drivers/net/tap.c   |  6 +-
 drivers/net/tun.c   | 14 +++---
 drivers/vhost/net.c | 20 ++--
 3 files changed, 26 insertions(+), 14 deletions(-)

-- 
1.8.3.1



[PATCH 2/3] tun: free skb in early errors

2017-11-30 Thread wexu
From: Wei Xu 

tun_recvmsg() supports accepting skb by msg_control after
commit ac77cfd4258f ("tun: support receiving skb through msg_control"),
the skb if presented should be freed within the function, otherwise it
would be leaked.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 
---
 drivers/net/tun.c | 14 +++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 6a7bde9..5563430 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2067,14 +2067,17 @@ static int tun_recvmsg(struct socket *sock, struct 
msghdr *m, size_t total_len,
 {
struct tun_file *tfile = container_of(sock, struct tun_file, socket);
struct tun_struct *tun = tun_get(tfile);
+   struct sk_buff *skb = m->msg_control;
int ret;
 
-   if (!tun)
-   return -EBADFD;
+   if (!tun) {
+   ret = -EBADFD;
+   goto out_free_skb;
+   }
 
if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) {
ret = -EINVAL;
-   goto out;
+   goto out_free_skb;
}
if (flags & MSG_ERRQUEUE) {
ret = sock_recv_errqueue(sock->sk, m, total_len,
@@ -2087,6 +2090,11 @@ static int tun_recvmsg(struct socket *sock, struct 
msghdr *m, size_t total_len,
m->msg_flags |= MSG_TRUNC;
ret = flags & MSG_TRUNC ? ret : total_len;
}
+   goto out;
+
+out_free_skb:
+   if (skb)
+   kfree_skb(skb);
 out:
tun_put(tun);
return ret;
-- 
1.8.3.1



[PATCH net,stable v2] vhost: fix skb leak in handle_rx()

2017-11-29 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

Eventually we figured out that it was a skb leak in handle_rx()
when sending packets to the VM. This usually happens when a guest
can not drain out vq as fast as vhost fills in, afterwards it sets
off the traffic jam and leaks skb(s) which occurs as no headcount
to send on the vq from vhost side.

This can be avoided by making sure we have got enough headcount
before actually consuming a skb from the batched rx array while
transmitting, which is simply done by moving checking the zero
headcount a bit ahead.

Also strengthen the small possibility of leak in case of recvmsg()
fails by freeing the skb.

Signed-off-by: Wei Xu 
Reported-by: Matthew Rosato 
---
 drivers/vhost/net.c | 23 +--
 1 file changed, 13 insertions(+), 10 deletions(-)

v2:
- add Matthew as the reporter, thanks matthew.
- moving zero headcount check ahead instead of defer consuming skb
  due to jason and mst's comment.
- add freeing skb in favor of recvmsg() fails.

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 8d626d7..e302e08 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -778,16 +778,6 @@ static void handle_rx(struct vhost_net *net)
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
goto out;
-   if (nvq->rx_array)
-   msg.msg_control = vhost_net_buf_consume(>rxq);
-   /* On overrun, truncate and discard */
-   if (unlikely(headcount > UIO_MAXIOV)) {
-   iov_iter_init(_iter, READ, vq->iov, 1, 1);
-   err = sock->ops->recvmsg(sock, ,
-1, MSG_DONTWAIT | MSG_TRUNC);
-   pr_debug("Discarded rx packet: len %zd\n", sock_len);
-   continue;
-   }
/* OK, now we need to know about added descriptors. */
if (!headcount) {
if (unlikely(vhost_enable_notify(>dev, vq))) {
@@ -800,6 +790,18 @@ static void handle_rx(struct vhost_net *net)
 * they refilled. */
goto out;
}
+   if (nvq->rx_array)
+   msg.msg_control = vhost_net_buf_consume(>rxq);
+   /* On overrun, truncate and discard */
+   if (unlikely(headcount > UIO_MAXIOV)) {
+   iov_iter_init(_iter, READ, vq->iov, 1, 1);
+   err = sock->ops->recvmsg(sock, ,
+1, MSG_DONTWAIT | MSG_TRUNC);
+   if (unlikely(err != 1))
+   kfree_skb((struct sk_buff *)msg.msg_control);
+   pr_debug("Discarded rx packet: len %zd\n", sock_len);
+   continue;
+   }
/* We don't need to be notified again. */
iov_iter_init(_iter, READ, vq->iov, in, vhost_len);
fixup = msg.msg_iter;
@@ -818,6 +820,7 @@ static void handle_rx(struct vhost_net *net)
pr_debug("Discarded rx packet: "
 " len %d, expected %zd\n", err, sock_len);
vhost_discard_vq_desc(vq, headcount);
+   kfree_skb((struct sk_buff *)msg.msg_control);
continue;
}
/* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
-- 
1.8.3.1



[PATCH net,stable] vhost: fix skb leak in handle_rx()

2017-11-28 Thread wexu
From: Wei Xu 

Matthew found a roughly 40% tcp throughput regression with commit
c67df11f(vhost_net: try batch dequing from skb array) as discussed
in the following thread:
https://www.mail-archive.com/netdev@vger.kernel.org/msg187936.html

Eventually we figured out that it was a skb leak in handle_rx()
when sending packets to the VM. This usually happens when a guest
can not drain out vq as fast as vhost fills in, afterwards it sets
off the traffic jam and leaks skb(s) which occurs as no headcount
to send on the vq from vhost side.

This can be avoided by making sure we have got enough headcount
before actually consuming a skb from the batched rx array while
transmitting, which is simply done by deferring it a moment later
in this patch.

Signed-off-by: Wei Xu 
---
 drivers/vhost/net.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 8d626d7..e76535e 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -778,8 +778,6 @@ static void handle_rx(struct vhost_net *net)
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
goto out;
-   if (nvq->rx_array)
-   msg.msg_control = vhost_net_buf_consume(>rxq);
/* On overrun, truncate and discard */
if (unlikely(headcount > UIO_MAXIOV)) {
iov_iter_init(_iter, READ, vq->iov, 1, 1);
@@ -809,6 +807,8 @@ static void handle_rx(struct vhost_net *net)
 */
iov_iter_advance(_iter, vhost_hlen);
}
+   if (nvq->rx_array)
+   msg.msg_control = vhost_net_buf_consume(>rxq);
err = sock->ops->recvmsg(sock, ,
 sock_len, MSG_DONTWAIT | MSG_TRUNC);
/* Userspace might have consumed the packet meanwhile:
-- 
1.8.3.1