aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-03-21 17:41:47 -0400
committerDavid S. Miller <davem@davemloft.net>2017-03-21 17:41:47 -0400
commita59d376d9e4d2f9284e046a26dd7790a6781b00e (patch)
tree033d132eaa2822a9a133e571c65d4c5bfd033d1b
parent8a0f5ccfb33b0b8b51de65b7b3bf342ba10b4fb6 (diff)
parent380feae0def7e6a115124a3219c3ec9b654dca32 (diff)
Merge branch 'vsock-pkt-cancel'
Peng Tao says: ==================== vsock: cancel connect packets when failing to connect Currently, if a connect call fails on a signal or timeout (e.g., guest is still in the process of starting up), we'll just return to caller and leave the connect packet queued and they are sent even though the connection is considered a failure, which can confuse applications with unwanted false connect attempt. The patchset enables vsock (both host and guest) to cancel queued packets when a connect attempt is considered to fail. v5 changelog: - change virtio_vsock_pkt->cancel_token back to virtio_vsock_pkt->vsk v4 changelog: - drop two unnecessary void * cast - update new callback comment v3 changelog: - define cancel_pkt callback in struct vsock_transport rather than struct virtio_transport - rename virtio_vsock_pkt->vsk to virtio_vsock_pkt->cancel_token v2 changelog: - fix queued_replies counting and resume tx/rx when necessary ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/vhost/vsock.c41
-rw-r--r--include/linux/virtio_vsock.h3
-rw-r--r--include/net/af_vsock.h3
-rw-r--r--net/vmw_vsock/af_vsock.c14
-rw-r--r--net/vmw_vsock/virtio_transport.c42
-rw-r--r--net/vmw_vsock/virtio_transport_common.c7
6 files changed, 110 insertions, 0 deletions
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index ce5e63d2c66a..44eed8eb0725 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -223,6 +223,46 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt)
223 return len; 223 return len;
224} 224}
225 225
226static int
227vhost_transport_cancel_pkt(struct vsock_sock *vsk)
228{
229 struct vhost_vsock *vsock;
230 struct virtio_vsock_pkt *pkt, *n;
231 int cnt = 0;
232 LIST_HEAD(freeme);
233
234 /* Find the vhost_vsock according to guest context id */
235 vsock = vhost_vsock_get(vsk->remote_addr.svm_cid);
236 if (!vsock)
237 return -ENODEV;
238
239 spin_lock_bh(&vsock->send_pkt_list_lock);
240 list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) {
241 if (pkt->vsk != vsk)
242 continue;
243 list_move(&pkt->list, &freeme);
244 }
245 spin_unlock_bh(&vsock->send_pkt_list_lock);
246
247 list_for_each_entry_safe(pkt, n, &freeme, list) {
248 if (pkt->reply)
249 cnt++;
250 list_del(&pkt->list);
251 virtio_transport_free_pkt(pkt);
252 }
253
254 if (cnt) {
255 struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX];
256 int new_cnt;
257
258 new_cnt = atomic_sub_return(cnt, &vsock->queued_replies);
259 if (new_cnt + cnt >= tx_vq->num && new_cnt < tx_vq->num)
260 vhost_poll_queue(&tx_vq->poll);
261 }
262
263 return 0;
264}
265
226static struct virtio_vsock_pkt * 266static struct virtio_vsock_pkt *
227vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq, 267vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq,
228 unsigned int out, unsigned int in) 268 unsigned int out, unsigned int in)
@@ -675,6 +715,7 @@ static struct virtio_transport vhost_transport = {
675 .release = virtio_transport_release, 715 .release = virtio_transport_release,
676 .connect = virtio_transport_connect, 716 .connect = virtio_transport_connect,
677 .shutdown = virtio_transport_shutdown, 717 .shutdown = virtio_transport_shutdown,
718 .cancel_pkt = vhost_transport_cancel_pkt,
678 719
679 .dgram_enqueue = virtio_transport_dgram_enqueue, 720 .dgram_enqueue = virtio_transport_dgram_enqueue,
680 .dgram_dequeue = virtio_transport_dgram_dequeue, 721 .dgram_dequeue = virtio_transport_dgram_dequeue,
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index 9638bfeb0d1f..584f9a647ad4 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -48,6 +48,8 @@ struct virtio_vsock_pkt {
48 struct virtio_vsock_hdr hdr; 48 struct virtio_vsock_hdr hdr;
49 struct work_struct work; 49 struct work_struct work;
50 struct list_head list; 50 struct list_head list;
51 /* socket refcnt not held, only use for cancellation */
52 struct vsock_sock *vsk;
51 void *buf; 53 void *buf;
52 u32 len; 54 u32 len;
53 u32 off; 55 u32 off;
@@ -56,6 +58,7 @@ struct virtio_vsock_pkt {
56 58
57struct virtio_vsock_pkt_info { 59struct virtio_vsock_pkt_info {
58 u32 remote_cid, remote_port; 60 u32 remote_cid, remote_port;
61 struct vsock_sock *vsk;
59 struct msghdr *msg; 62 struct msghdr *msg;
60 u32 pkt_len; 63 u32 pkt_len;
61 u16 type; 64 u16 type;
diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h
index f2758964ce6f..f32ed9ac181a 100644
--- a/include/net/af_vsock.h
+++ b/include/net/af_vsock.h
@@ -100,6 +100,9 @@ struct vsock_transport {
100 void (*destruct)(struct vsock_sock *); 100 void (*destruct)(struct vsock_sock *);
101 void (*release)(struct vsock_sock *); 101 void (*release)(struct vsock_sock *);
102 102
103 /* Cancel all pending packets sent on vsock. */
104 int (*cancel_pkt)(struct vsock_sock *vsk);
105
103 /* Connections. */ 106 /* Connections. */
104 int (*connect)(struct vsock_sock *); 107 int (*connect)(struct vsock_sock *);
105 108
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 9f770f33c100..6f7f6757ceef 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -1102,10 +1102,19 @@ static const struct proto_ops vsock_dgram_ops = {
1102 .sendpage = sock_no_sendpage, 1102 .sendpage = sock_no_sendpage,
1103}; 1103};
1104 1104
1105static int vsock_transport_cancel_pkt(struct vsock_sock *vsk)
1106{
1107 if (!transport->cancel_pkt)
1108 return -EOPNOTSUPP;
1109
1110 return transport->cancel_pkt(vsk);
1111}
1112
1105static void vsock_connect_timeout(struct work_struct *work) 1113static void vsock_connect_timeout(struct work_struct *work)
1106{ 1114{
1107 struct sock *sk; 1115 struct sock *sk;
1108 struct vsock_sock *vsk; 1116 struct vsock_sock *vsk;
1117 int cancel = 0;
1109 1118
1110 vsk = container_of(work, struct vsock_sock, dwork.work); 1119 vsk = container_of(work, struct vsock_sock, dwork.work);
1111 sk = sk_vsock(vsk); 1120 sk = sk_vsock(vsk);
@@ -1116,8 +1125,11 @@ static void vsock_connect_timeout(struct work_struct *work)
1116 sk->sk_state = SS_UNCONNECTED; 1125 sk->sk_state = SS_UNCONNECTED;
1117 sk->sk_err = ETIMEDOUT; 1126 sk->sk_err = ETIMEDOUT;
1118 sk->sk_error_report(sk); 1127 sk->sk_error_report(sk);
1128 cancel = 1;
1119 } 1129 }
1120 release_sock(sk); 1130 release_sock(sk);
1131 if (cancel)
1132 vsock_transport_cancel_pkt(vsk);
1121 1133
1122 sock_put(sk); 1134 sock_put(sk);
1123} 1135}
@@ -1224,11 +1236,13 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr,
1224 err = sock_intr_errno(timeout); 1236 err = sock_intr_errno(timeout);
1225 sk->sk_state = SS_UNCONNECTED; 1237 sk->sk_state = SS_UNCONNECTED;
1226 sock->state = SS_UNCONNECTED; 1238 sock->state = SS_UNCONNECTED;
1239 vsock_transport_cancel_pkt(vsk);
1227 goto out_wait; 1240 goto out_wait;
1228 } else if (timeout == 0) { 1241 } else if (timeout == 0) {
1229 err = -ETIMEDOUT; 1242 err = -ETIMEDOUT;
1230 sk->sk_state = SS_UNCONNECTED; 1243 sk->sk_state = SS_UNCONNECTED;
1231 sock->state = SS_UNCONNECTED; 1244 sock->state = SS_UNCONNECTED;
1245 vsock_transport_cancel_pkt(vsk);
1232 goto out_wait; 1246 goto out_wait;
1233 } 1247 }
1234 1248
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 9d24c0e958b1..68675a151f22 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -213,6 +213,47 @@ virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt)
213 return len; 213 return len;
214} 214}
215 215
216static int
217virtio_transport_cancel_pkt(struct vsock_sock *vsk)
218{
219 struct virtio_vsock *vsock;
220 struct virtio_vsock_pkt *pkt, *n;
221 int cnt = 0;
222 LIST_HEAD(freeme);
223
224 vsock = virtio_vsock_get();
225 if (!vsock) {
226 return -ENODEV;
227 }
228
229 spin_lock_bh(&vsock->send_pkt_list_lock);
230 list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) {
231 if (pkt->vsk != vsk)
232 continue;
233 list_move(&pkt->list, &freeme);
234 }
235 spin_unlock_bh(&vsock->send_pkt_list_lock);
236
237 list_for_each_entry_safe(pkt, n, &freeme, list) {
238 if (pkt->reply)
239 cnt++;
240 list_del(&pkt->list);
241 virtio_transport_free_pkt(pkt);
242 }
243
244 if (cnt) {
245 struct virtqueue *rx_vq = vsock->vqs[VSOCK_VQ_RX];
246 int new_cnt;
247
248 new_cnt = atomic_sub_return(cnt, &vsock->queued_replies);
249 if (new_cnt + cnt >= virtqueue_get_vring_size(rx_vq) &&
250 new_cnt < virtqueue_get_vring_size(rx_vq))
251 queue_work(virtio_vsock_workqueue, &vsock->rx_work);
252 }
253
254 return 0;
255}
256
216static void virtio_vsock_rx_fill(struct virtio_vsock *vsock) 257static void virtio_vsock_rx_fill(struct virtio_vsock *vsock)
217{ 258{
218 int buf_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE; 259 int buf_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE;
@@ -462,6 +503,7 @@ static struct virtio_transport virtio_transport = {
462 .release = virtio_transport_release, 503 .release = virtio_transport_release,
463 .connect = virtio_transport_connect, 504 .connect = virtio_transport_connect,
464 .shutdown = virtio_transport_shutdown, 505 .shutdown = virtio_transport_shutdown,
506 .cancel_pkt = virtio_transport_cancel_pkt,
465 507
466 .dgram_bind = virtio_transport_dgram_bind, 508 .dgram_bind = virtio_transport_dgram_bind,
467 .dgram_dequeue = virtio_transport_dgram_dequeue, 509 .dgram_dequeue = virtio_transport_dgram_dequeue,
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 8d592a45b597..af087b44ceea 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -58,6 +58,7 @@ virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info,
58 pkt->len = len; 58 pkt->len = len;
59 pkt->hdr.len = cpu_to_le32(len); 59 pkt->hdr.len = cpu_to_le32(len);
60 pkt->reply = info->reply; 60 pkt->reply = info->reply;
61 pkt->vsk = info->vsk;
61 62
62 if (info->msg && len > 0) { 63 if (info->msg && len > 0) {
63 pkt->buf = kmalloc(len, GFP_KERNEL); 64 pkt->buf = kmalloc(len, GFP_KERNEL);
@@ -180,6 +181,7 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk,
180 struct virtio_vsock_pkt_info info = { 181 struct virtio_vsock_pkt_info info = {
181 .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE, 182 .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE,
182 .type = type, 183 .type = type,
184 .vsk = vsk,
183 }; 185 };
184 186
185 return virtio_transport_send_pkt_info(vsk, &info); 187 return virtio_transport_send_pkt_info(vsk, &info);
@@ -519,6 +521,7 @@ int virtio_transport_connect(struct vsock_sock *vsk)
519 struct virtio_vsock_pkt_info info = { 521 struct virtio_vsock_pkt_info info = {
520 .op = VIRTIO_VSOCK_OP_REQUEST, 522 .op = VIRTIO_VSOCK_OP_REQUEST,
521 .type = VIRTIO_VSOCK_TYPE_STREAM, 523 .type = VIRTIO_VSOCK_TYPE_STREAM,
524 .vsk = vsk,
522 }; 525 };
523 526
524 return virtio_transport_send_pkt_info(vsk, &info); 527 return virtio_transport_send_pkt_info(vsk, &info);
@@ -534,6 +537,7 @@ int virtio_transport_shutdown(struct vsock_sock *vsk, int mode)
534 VIRTIO_VSOCK_SHUTDOWN_RCV : 0) | 537 VIRTIO_VSOCK_SHUTDOWN_RCV : 0) |
535 (mode & SEND_SHUTDOWN ? 538 (mode & SEND_SHUTDOWN ?
536 VIRTIO_VSOCK_SHUTDOWN_SEND : 0), 539 VIRTIO_VSOCK_SHUTDOWN_SEND : 0),
540 .vsk = vsk,
537 }; 541 };
538 542
539 return virtio_transport_send_pkt_info(vsk, &info); 543 return virtio_transport_send_pkt_info(vsk, &info);
@@ -560,6 +564,7 @@ virtio_transport_stream_enqueue(struct vsock_sock *vsk,
560 .type = VIRTIO_VSOCK_TYPE_STREAM, 564 .type = VIRTIO_VSOCK_TYPE_STREAM,
561 .msg = msg, 565 .msg = msg,
562 .pkt_len = len, 566 .pkt_len = len,
567 .vsk = vsk,
563 }; 568 };
564 569
565 return virtio_transport_send_pkt_info(vsk, &info); 570 return virtio_transport_send_pkt_info(vsk, &info);
@@ -581,6 +586,7 @@ static int virtio_transport_reset(struct vsock_sock *vsk,
581 .op = VIRTIO_VSOCK_OP_RST, 586 .op = VIRTIO_VSOCK_OP_RST,
582 .type = VIRTIO_VSOCK_TYPE_STREAM, 587 .type = VIRTIO_VSOCK_TYPE_STREAM,
583 .reply = !!pkt, 588 .reply = !!pkt,
589 .vsk = vsk,
584 }; 590 };
585 591
586 /* Send RST only if the original pkt is not a RST pkt */ 592 /* Send RST only if the original pkt is not a RST pkt */
@@ -826,6 +832,7 @@ virtio_transport_send_response(struct vsock_sock *vsk,
826 .remote_cid = le64_to_cpu(pkt->hdr.src_cid), 832 .remote_cid = le64_to_cpu(pkt->hdr.src_cid),
827 .remote_port = le32_to_cpu(pkt->hdr.src_port), 833 .remote_port = le32_to_cpu(pkt->hdr.src_port),
828 .reply = true, 834 .reply = true,
835 .vsk = vsk,
829 }; 836 };
830 837
831 return virtio_transport_send_pkt_info(vsk, &info); 838 return virtio_transport_send_pkt_info(vsk, &info);