static bool pvcalls_conn_back_write()

in pvcalls-back.c [167:226]


static bool pvcalls_conn_back_write(struct sock_mapping *map)
{
	struct pvcalls_data_intf *intf = map->ring;
	struct pvcalls_data *data = &map->data;
	struct msghdr msg;
	struct kvec vec[2];
	RING_IDX cons, prod, size, array_size;
	int ret;

	cons = intf->out_cons;
	prod = intf->out_prod;
	/* read the indexes before dealing with the data */
	virt_mb();

	array_size = XEN_FLEX_RING_SIZE(map->ring_order);
	size = pvcalls_queued(prod, cons, array_size);
	if (size == 0)
		return false;

	memset(&msg, 0, sizeof(msg));
	msg.msg_flags |= MSG_DONTWAIT;
	if (pvcalls_mask(prod, array_size) > pvcalls_mask(cons, array_size)) {
		vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
		vec[0].iov_len = size;
		iov_iter_kvec(&msg.msg_iter, READ, vec, 1, size);
	} else {
		vec[0].iov_base = data->out + pvcalls_mask(cons, array_size);
		vec[0].iov_len = array_size - pvcalls_mask(cons, array_size);
		vec[1].iov_base = data->out;
		vec[1].iov_len = size - vec[0].iov_len;
		iov_iter_kvec(&msg.msg_iter, READ, vec, 2, size);
	}

	atomic_set(&map->write, 0);
	ret = inet_sendmsg(map->sock, &msg, size);
	if (ret == -EAGAIN) {
		atomic_inc(&map->write);
		atomic_inc(&map->io);
		return true;
	}

	/* write the data, then update the indexes */
	virt_wmb();
	if (ret < 0) {
		intf->out_error = ret;
	} else {
		intf->out_error = 0;
		intf->out_cons = cons + ret;
		prod = intf->out_prod;
	}
	/* update the indexes, then notify the other end */
	virt_wmb();
	if (prod != cons + ret) {
		atomic_inc(&map->write);
		atomic_inc(&map->io);
	}
	notify_remote_via_irq(map->irq);

	return true;
}