From patchwork Thu Oct 26 19:11:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefano Stabellini X-Patchwork-Id: 10028739 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3163260375 for ; Thu, 26 Oct 2017 19:14:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 216E728EA0 for ; Thu, 26 Oct 2017 19:14:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 162AE28EA2; Thu, 26 Oct 2017 19:14:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8C16028EA0 for ; Thu, 26 Oct 2017 19:14:16 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e7nZQ-00050H-3h; Thu, 26 Oct 2017 19:12:00 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1e7nZO-0004wW-T0 for xen-devel@lists.xen.org; Thu, 26 Oct 2017 19:11:58 +0000 Received: from [193.109.254.147] by server-11.bemta-6.messagelabs.com id 61/87-20813-E7332F95; Thu, 26 Oct 2017 19:11:58 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpjkeJIrShJLcpLzFFi42I5NlE2WbfW+FO kwbX/1hZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa0bXo42sBStNK2bPm8LawLhEt4uRk0NIYB2T xLZ1MSA2i4CDxLXJF9m7GDk4GAViJB78sAYJMwqESUy+vIQVxGYTMJT4+2QTG4gtIiAtce3zZ cYuRi4OZoHJjBKv3/1iBkkIC9hLnO/5ywQxU1Xi3+FJYM28Aq4Sa1Y1M4LYEgJyEiePTQaLcw q4SUz7cJ0FZJCQQAujxLptvYwTGHkXMDKsYtQoTi0qSy3SNTbSSyrKTM8oyU3MzNE1NDDTy00 tLk5MT81JTCrWS87P3cQIDAcGINjBeHpd4CFGSQ4mJVFehj0fIoX4kvJTKjMSizPii0pzUosP McpwcChJ8P43/BQpJFiUmp5akZaZAwxMmLQEB4+SCK8xSJq3uCAxtzgzHSJ1itGS49imy3+YO Dpu3gWSz2a+bmAWYsnLz0uVEue9CtIgANKQUZoHNw4WPZcYZaWEeRmBDhTiKUgtys0sQZV/xS jOwagkzCtvBDSFJzOvBG7rK6CDmIAOalL9AHJQSSJCSqqBcZZoQk6J2av582xOp7WZHv7lMvv tibpX7cZZltb6eqc0Y+/d6K8yNhaLNnLZqrLsjK7O/xnXXNXmNl39K9KqfIzhsfPxotUTtcKD 7xyL3bxebtaG1qsKy54rvVj2KyRdujE85/alGO5LAiacSj3B6nHcnRxvEtiX1xwUPt032fjB7 x9OkgmKSizFGYmGWsxFxYkA6ibD4ZkCAAA= X-Env-Sender: sstabellini@kernel.org X-Msg-Ref: server-14.tower-27.messagelabs.com!1509045116!101159122!1 X-Originating-IP: [198.145.29.99] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 52707 invoked from network); 26 Oct 2017 19:11:57 -0000 Received: from mail.kernel.org (HELO mail.kernel.org) (198.145.29.99) by server-14.tower-27.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 26 Oct 2017 19:11:57 -0000 Received: from localhost.localdomain (162-198-228-35.lightspeed.wlfrct.sbcglobal.net [162.198.228.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 319952193B; Thu, 26 Oct 2017 19:11:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 319952193B From: Stefano Stabellini To: xen-devel@lists.xen.org Date: Thu, 26 Oct 2017 12:11:47 -0700 Message-Id: <1509045112-9807-8-git-send-email-sstabellini@kernel.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1509045112-9807-1-git-send-email-sstabellini@kernel.org> References: <1509045112-9807-1-git-send-email-sstabellini@kernel.org> Cc: jgross@suse.com, Stefano Stabellini , boris.ostrovsky@oracle.com, sstabellini@kernel.org, linux-kernel@vger.kernel.org Subject: [Xen-devel] [PATCH v7 08/13] xen/pvcalls: implement accept command X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Introduce a waitqueue to allow only one outstanding accept command at any given time and to implement polling on the passive socket. Introduce a flags field to keep track of in-flight accept and poll commands. Send PVCALLS_ACCEPT to the backend. Allocate a new active socket. Make sure that only one accept command is executed at any given time by setting PVCALLS_FLAG_ACCEPT_INFLIGHT and waiting on the inflight_accept_req waitqueue. Convert the new struct sock_mapping pointer into an uint64_t and use it as id for the new socket to pass to the backend. Check if the accept call is non-blocking: in that case after sending the ACCEPT command to the backend store the sock_mapping pointer of the new struct and the inflight req_id then return -EAGAIN (which will respond only when there is something to accept). Next time accept is called, we'll check if the ACCEPT command has been answered, if so we'll pick up where we left off, otherwise we return -EAGAIN again. Note that, differently from the other commands, we can use wait_event_interruptible (instead of wait_event) in the case of accept as we are able to track the req_id of the ACCEPT response that we are waiting. Signed-off-by: Stefano Stabellini Reviewed-by: Boris Ostrovsky CC: boris.ostrovsky@oracle.com CC: jgross@suse.com --- drivers/xen/pvcalls-front.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ drivers/xen/pvcalls-front.h | 3 + 2 files changed, 148 insertions(+) diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index a2d876e..f790abc 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -76,6 +76,16 @@ struct sock_mapping { #define PVCALLS_STATUS_BIND 1 #define PVCALLS_STATUS_LISTEN 2 uint8_t status; + /* + * Internal state-machine flags. + * Only one accept operation can be inflight for a socket. + * Only one poll operation can be inflight for a given socket. + */ +#define PVCALLS_FLAG_ACCEPT_INFLIGHT 0 + uint8_t flags; + uint32_t inflight_req_id; + struct sock_mapping *accept_map; + wait_queue_head_t inflight_accept_req; } passive; }; }; @@ -391,6 +401,8 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) memcpy(req->u.bind.addr, addr, sizeof(*addr)); req->u.bind.len = addr_len; + init_waitqueue_head(&map->passive.inflight_accept_req); + map->active_socket = false; bedata->ring.req_prod_pvt++; @@ -469,6 +481,139 @@ int pvcalls_front_listen(struct socket *sock, int backlog) return ret; } +int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct pvcalls_bedata *bedata; + struct sock_mapping *map; + struct sock_mapping *map2 = NULL; + struct xen_pvcalls_request *req; + int notify, req_id, ret, evtchn, nonblock; + + pvcalls_enter(); + if (!pvcalls_front_dev) { + pvcalls_exit(); + return -ENOTCONN; + } + bedata = dev_get_drvdata(&pvcalls_front_dev->dev); + + map = (struct sock_mapping *) sock->sk->sk_send_head; + if (!map) { + pvcalls_exit(); + return -ENOTSOCK; + } + + if (map->passive.status != PVCALLS_STATUS_LISTEN) { + pvcalls_exit(); + return -EINVAL; + } + + nonblock = flags & SOCK_NONBLOCK; + /* + * Backend only supports 1 inflight accept request, will return + * errors for the others + */ + if (test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags)) { + req_id = READ_ONCE(map->passive.inflight_req_id); + if (req_id != PVCALLS_INVALID_ID && + READ_ONCE(bedata->rsp[req_id].req_id) == req_id) { + map2 = map->passive.accept_map; + goto received; + } + if (nonblock) { + pvcalls_exit(); + return -EAGAIN; + } + if (wait_event_interruptible(map->passive.inflight_accept_req, + !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags))) { + pvcalls_exit(); + return -EINTR; + } + } + + spin_lock(&bedata->socket_lock); + ret = get_request(bedata, &req_id); + if (ret < 0) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); + pvcalls_exit(); + return ret; + } + map2 = kzalloc(sizeof(*map2), GFP_KERNEL); + if (map2 == NULL) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); + pvcalls_exit(); + return -ENOMEM; + } + ret = create_active(map2, &evtchn); + if (ret < 0) { + kfree(map2); + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + spin_unlock(&bedata->socket_lock); + pvcalls_exit(); + return ret; + } + list_add_tail(&map2->list, &bedata->socket_mappings); + + req = RING_GET_REQUEST(&bedata->ring, req_id); + req->req_id = req_id; + req->cmd = PVCALLS_ACCEPT; + req->u.accept.id = (uint64_t) map; + req->u.accept.ref = map2->active.ref; + req->u.accept.id_new = (uint64_t) map2; + req->u.accept.evtchn = evtchn; + map->passive.accept_map = map2; + + bedata->ring.req_prod_pvt++; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); + spin_unlock(&bedata->socket_lock); + if (notify) + notify_remote_via_irq(bedata->irq); + /* We could check if we have received a response before returning. */ + if (nonblock) { + WRITE_ONCE(map->passive.inflight_req_id, req_id); + pvcalls_exit(); + return -EAGAIN; + } + + if (wait_event_interruptible(bedata->inflight_req, + READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) { + pvcalls_exit(); + return -EINTR; + } + /* read req_id, then the content */ + smp_rmb(); + +received: + map2->sock = newsock; + newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL); + if (!newsock->sk) { + bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; + map->passive.inflight_req_id = PVCALLS_INVALID_ID; + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + pvcalls_front_free_map(bedata, map2); + pvcalls_exit(); + return -ENOMEM; + } + newsock->sk->sk_send_head = (void *)map2; + + ret = bedata->rsp[req_id].ret; + bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; + map->passive.inflight_req_id = PVCALLS_INVALID_ID; + + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); + wake_up(&map->passive.inflight_accept_req); + + pvcalls_exit(); + return ret; +} + static const struct xenbus_device_id pvcalls_front_ids[] = { { "pvcalls" }, { "" } diff --git a/drivers/xen/pvcalls-front.h b/drivers/xen/pvcalls-front.h index aa8fe10..ab4f1da 100644 --- a/drivers/xen/pvcalls-front.h +++ b/drivers/xen/pvcalls-front.h @@ -10,5 +10,8 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len); int pvcalls_front_listen(struct socket *sock, int backlog); +int pvcalls_front_accept(struct socket *sock, + struct socket *newsock, + int flags); #endif