static int nvme_tcp_try_send_data()

in host/tcp.c [919:973]


static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
{
	struct nvme_tcp_queue *queue = req->queue;
	int req_data_len = req->data_len;

	while (true) {
		struct page *page = nvme_tcp_req_cur_page(req);
		size_t offset = nvme_tcp_req_cur_offset(req);
		size_t len = nvme_tcp_req_cur_length(req);
		bool last = nvme_tcp_pdu_last_send(req, len);
		int req_data_sent = req->data_sent;
		int ret, flags = MSG_DONTWAIT;

		if (last && !queue->data_digest && !nvme_tcp_queue_more(queue))
			flags |= MSG_EOR;
		else
			flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;

		if (sendpage_ok(page)) {
			ret = kernel_sendpage(queue->sock, page, offset, len,
					flags);
		} else {
			ret = sock_no_sendpage(queue->sock, page, offset, len,
					flags);
		}
		if (ret <= 0)
			return ret;

		if (queue->data_digest)
			nvme_tcp_ddgst_update(queue->snd_hash, page,
					offset, ret);

		/*
		 * update the request iterator except for the last payload send
		 * in the request where we don't want to modify it as we may
		 * compete with the RX path completing the request.
		 */
		if (req_data_sent + ret < req_data_len)
			nvme_tcp_advance_req(req, ret);

		/* fully successful last send in current PDU */
		if (last && ret == len) {
			if (queue->data_digest) {
				nvme_tcp_ddgst_final(queue->snd_hash,
					&req->ddgst);
				req->state = NVME_TCP_SEND_DDGST;
				req->offset = 0;
			} else {
				nvme_tcp_done_send_req(queue);
			}
			return 1;
		}
	}
	return -EAGAIN;
}