static void __pvcalls_back_accept()

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;
}