aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Stabellini <sstabellini@kernel.org>2017-10-30 18:41:02 -0400
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-10-31 09:05:53 -0400
commit235a71c5390316429e2c7823119c5ea439816beb (patch)
tree20ab8b2a3827d6dbce43bf026121e4bb36cfc908
parent5842c83596fcfa742978ec2840440ab56c7fdf79 (diff)
xen/pvcalls: implement release command
Send PVCALLS_RELEASE to the backend and wait for a reply. Take both in_mutex and out_mutex to avoid concurrent accesses. Then, free the socket. For passive sockets, check whether we have already pre-allocated an active socket for the purpose of being accepted. If so, free that as well. Signed-off-by: Stefano Stabellini <stefano@aporeto.com> Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> CC: boris.ostrovsky@oracle.com CC: jgross@suse.com Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
-rw-r--r--drivers/xen/pvcalls-front.c98
-rw-r--r--drivers/xen/pvcalls-front.h1
2 files changed, 99 insertions, 0 deletions
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c
index c7d4251c3678..0c1ec6894cc4 100644
--- a/drivers/xen/pvcalls-front.c
+++ b/drivers/xen/pvcalls-front.c
@@ -199,6 +199,21 @@ again:
199static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, 199static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
200 struct sock_mapping *map) 200 struct sock_mapping *map)
201{ 201{
202 int i;
203
204 unbind_from_irqhandler(map->active.irq, map);
205
206 spin_lock(&bedata->socket_lock);
207 if (!list_empty(&map->list))
208 list_del_init(&map->list);
209 spin_unlock(&bedata->socket_lock);
210
211 for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
212 gnttab_end_foreign_access(map->active.ring->ref[i], 0, 0);
213 gnttab_end_foreign_access(map->active.ref, 0, 0);
214 free_page((unsigned long)map->active.ring);
215
216 kfree(map);
202} 217}
203 218
204static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map) 219static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
@@ -972,6 +987,89 @@ unsigned int pvcalls_front_poll(struct file *file, struct socket *sock,
972 return ret; 987 return ret;
973} 988}
974 989
990int pvcalls_front_release(struct socket *sock)
991{
992 struct pvcalls_bedata *bedata;
993 struct sock_mapping *map;
994 int req_id, notify, ret;
995 struct xen_pvcalls_request *req;
996
997 if (sock->sk == NULL)
998 return 0;
999
1000 pvcalls_enter();
1001 if (!pvcalls_front_dev) {
1002 pvcalls_exit();
1003 return -EIO;
1004 }
1005
1006 bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
1007
1008 map = (struct sock_mapping *) sock->sk->sk_send_head;
1009 if (map == NULL) {
1010 pvcalls_exit();
1011 return 0;
1012 }
1013
1014 spin_lock(&bedata->socket_lock);
1015 ret = get_request(bedata, &req_id);
1016 if (ret < 0) {
1017 spin_unlock(&bedata->socket_lock);
1018 pvcalls_exit();
1019 return ret;
1020 }
1021 sock->sk->sk_send_head = NULL;
1022
1023 req = RING_GET_REQUEST(&bedata->ring, req_id);
1024 req->req_id = req_id;
1025 req->cmd = PVCALLS_RELEASE;
1026 req->u.release.id = (uintptr_t)map;
1027
1028 bedata->ring.req_prod_pvt++;
1029 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
1030 spin_unlock(&bedata->socket_lock);
1031 if (notify)
1032 notify_remote_via_irq(bedata->irq);
1033
1034 wait_event(bedata->inflight_req,
1035 READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
1036
1037 if (map->active_socket) {
1038 /*
1039 * Set in_error and wake up inflight_conn_req to force
1040 * recvmsg waiters to exit.
1041 */
1042 map->active.ring->in_error = -EBADF;
1043 wake_up_interruptible(&map->active.inflight_conn_req);
1044
1045 /*
1046 * Wait until there are no more waiters on the mutexes.
1047 * We know that no new waiters can be added because sk_send_head
1048 * is set to NULL -- we only need to wait for the existing
1049 * waiters to return.
1050 */
1051 while (!mutex_trylock(&map->active.in_mutex) ||
1052 !mutex_trylock(&map->active.out_mutex))
1053 cpu_relax();
1054
1055 pvcalls_front_free_map(bedata, map);
1056 } else {
1057 spin_lock(&bedata->socket_lock);
1058 list_del(&map->list);
1059 spin_unlock(&bedata->socket_lock);
1060 if (READ_ONCE(map->passive.inflight_req_id) !=
1061 PVCALLS_INVALID_ID) {
1062 pvcalls_front_free_map(bedata,
1063 map->passive.accept_map);
1064 }
1065 kfree(map);
1066 }
1067 WRITE_ONCE(bedata->rsp[req_id].req_id, PVCALLS_INVALID_ID);
1068
1069 pvcalls_exit();
1070 return 0;
1071}
1072
975static const struct xenbus_device_id pvcalls_front_ids[] = { 1073static const struct xenbus_device_id pvcalls_front_ids[] = {
976 { "pvcalls" }, 1074 { "pvcalls" },
977 { "" } 1075 { "" }
diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h
index 25e05b8f2d72..3332978f4fcd 100644
--- a/drivers/xen/pvcalls-front.h
+++ b/drivers/xen/pvcalls-front.h
@@ -23,5 +23,6 @@ int pvcalls_front_recvmsg(struct socket *sock,
23unsigned int pvcalls_front_poll(struct file *file, 23unsigned int pvcalls_front_poll(struct file *file,
24 struct socket *sock, 24 struct socket *sock,
25 poll_table *wait); 25 poll_table *wait);
26int pvcalls_front_release(struct socket *sock);
26 27
27#endif 28#endif