static int nbd_send_cmd()

in nbd.c [550:694]


static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
{
	struct request *req = blk_mq_rq_from_pdu(cmd);
	struct nbd_config *config = nbd->config;
	struct nbd_sock *nsock = config->socks[index];
	int result;
	struct nbd_request request = {.magic = htonl(NBD_REQUEST_MAGIC)};
	struct kvec iov = {.iov_base = &request, .iov_len = sizeof(request)};
	struct iov_iter from;
	unsigned long size = blk_rq_bytes(req);
	struct bio *bio;
	u64 handle;
	u32 type;
	u32 nbd_cmd_flags = 0;
	int sent = nsock->sent, skip = 0;

	iov_iter_kvec(&from, WRITE, &iov, 1, sizeof(request));

	type = req_to_nbd_cmd_type(req);
	if (type == U32_MAX)
		return -EIO;

	if (rq_data_dir(req) == WRITE &&
	    (config->flags & NBD_FLAG_READ_ONLY)) {
		dev_err_ratelimited(disk_to_dev(nbd->disk),
				    "Write on read-only\n");
		return -EIO;
	}

	if (req->cmd_flags & REQ_FUA)
		nbd_cmd_flags |= NBD_CMD_FLAG_FUA;

	/* We did a partial send previously, and we at least sent the whole
	 * request struct, so just go and send the rest of the pages in the
	 * request.
	 */
	if (sent) {
		if (sent >= sizeof(request)) {
			skip = sent - sizeof(request);

			/* initialize handle for tracing purposes */
			handle = nbd_cmd_handle(cmd);

			goto send_pages;
		}
		iov_iter_advance(&from, sent);
	} else {
		cmd->cmd_cookie++;
	}
	cmd->index = index;
	cmd->cookie = nsock->cookie;
	cmd->retries = 0;
	request.type = htonl(type | nbd_cmd_flags);
	if (type != NBD_CMD_FLUSH) {
		request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
		request.len = htonl(size);
	}
	handle = nbd_cmd_handle(cmd);
	memcpy(request.handle, &handle, sizeof(handle));

	trace_nbd_send_request(&request, nbd->index, blk_mq_rq_from_pdu(cmd));

	dev_dbg(nbd_to_dev(nbd), "request %p: sending control (%s@%llu,%uB)\n",
		req, nbdcmd_to_ascii(type),
		(unsigned long long)blk_rq_pos(req) << 9, blk_rq_bytes(req));
	result = sock_xmit(nbd, index, 1, &from,
			(type == NBD_CMD_WRITE) ? MSG_MORE : 0, &sent);
	trace_nbd_header_sent(req, handle);
	if (result < 0) {
		if (was_interrupted(result)) {
			/* If we havne't sent anything we can just return BUSY,
			 * however if we have sent something we need to make
			 * sure we only allow this req to be sent until we are
			 * completely done.
			 */
			if (sent) {
				nsock->pending = req;
				nsock->sent = sent;
			}
			set_bit(NBD_CMD_REQUEUED, &cmd->flags);
			return BLK_STS_RESOURCE;
		}
		dev_err_ratelimited(disk_to_dev(nbd->disk),
			"Send control failed (result %d)\n", result);
		return -EAGAIN;
	}
send_pages:
	if (type != NBD_CMD_WRITE)
		goto out;

	bio = req->bio;
	while (bio) {
		struct bio *next = bio->bi_next;
		struct bvec_iter iter;
		struct bio_vec bvec;

		bio_for_each_segment(bvec, bio, iter) {
			bool is_last = !next && bio_iter_last(bvec, iter);
			int flags = is_last ? 0 : MSG_MORE;

			dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
				req, bvec.bv_len);
			iov_iter_bvec(&from, WRITE, &bvec, 1, bvec.bv_len);
			if (skip) {
				if (skip >= iov_iter_count(&from)) {
					skip -= iov_iter_count(&from);
					continue;
				}
				iov_iter_advance(&from, skip);
				skip = 0;
			}
			result = sock_xmit(nbd, index, 1, &from, flags, &sent);
			if (result < 0) {
				if (was_interrupted(result)) {
					/* We've already sent the header, we
					 * have no choice but to set pending and
					 * return BUSY.
					 */
					nsock->pending = req;
					nsock->sent = sent;
					set_bit(NBD_CMD_REQUEUED, &cmd->flags);
					return BLK_STS_RESOURCE;
				}
				dev_err(disk_to_dev(nbd->disk),
					"Send data failed (result %d)\n",
					result);
				return -EAGAIN;
			}
			/*
			 * The completion might already have come in,
			 * so break for the last one instead of letting
			 * the iterator do it. This prevents use-after-free
			 * of the bio.
			 */
			if (is_last)
				break;
		}
		bio = next;
	}
out:
	trace_nbd_payload_sent(req, handle);
	nsock->pending = NULL;
	nsock->sent = 0;
	return 0;
}