in pvcalls-back.c [512:581]
static void __pvcalls_back_accept(struct work_struct *work)
{
struct sockpass_mapping *mappass = container_of(
work, struct sockpass_mapping, register_work);
struct sock_mapping *map;
struct pvcalls_ioworker *iow;
struct pvcalls_fedata *fedata;
struct socket *sock;
struct xen_pvcalls_response *rsp;
struct xen_pvcalls_request *req;
int notify;
int ret = -EINVAL;
unsigned long flags;
fedata = mappass->fedata;
/*
* __pvcalls_back_accept can race against pvcalls_back_accept.
* We only need to check the value of "cmd" on read. It could be
* done atomically, but to simplify the code on the write side, we
* use a spinlock.
*/
spin_lock_irqsave(&mappass->copy_lock, flags);
req = &mappass->reqcopy;
if (req->cmd != PVCALLS_ACCEPT) {
spin_unlock_irqrestore(&mappass->copy_lock, flags);
return;
}
spin_unlock_irqrestore(&mappass->copy_lock, flags);
sock = sock_alloc();
if (sock == NULL)
goto out_error;
sock->type = mappass->sock->type;
sock->ops = mappass->sock->ops;
ret = inet_accept(mappass->sock, sock, O_NONBLOCK, true);
if (ret == -EAGAIN) {
sock_release(sock);
return;
}
map = pvcalls_new_active_socket(fedata,
req->u.accept.id_new,
req->u.accept.ref,
req->u.accept.evtchn,
sock);
if (!map) {
ret = -EFAULT;
sock_release(sock);
goto out_error;
}
map->sockpass = mappass;
iow = &map->ioworker;
atomic_inc(&map->read);
atomic_inc(&map->io);
queue_work(iow->wq, &iow->register_work);
out_error:
rsp = RING_GET_RESPONSE(&fedata->ring, fedata->ring.rsp_prod_pvt++);
rsp->req_id = req->req_id;
rsp->cmd = req->cmd;
rsp->u.accept.id = req->u.accept.id;
rsp->ret = ret;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&fedata->ring, notify);
if (notify)
notify_remote_via_irq(fedata->irq);
mappass->reqcopy.cmd = 0;
}