diff options
Diffstat (limited to 'drivers/nvme/host/tcp.c')
| -rw-r--r-- | drivers/nvme/host/tcp.c | 40 | 
1 files changed, 25 insertions, 15 deletions
| diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index e2ab12f3f51c..4ae562d30d2b 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -274,6 +274,12 @@ static inline void nvme_tcp_send_all(struct nvme_tcp_queue *queue)  	} while (ret > 0);  } +static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue) +{ +	return !list_empty(&queue->send_list) || +		!llist_empty(&queue->req_list) || queue->more_requests; +} +  static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,  		bool sync, bool last)  { @@ -294,9 +300,10 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,  		nvme_tcp_send_all(queue);  		queue->more_requests = false;  		mutex_unlock(&queue->send_mutex); -	} else if (last) { -		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);  	} + +	if (last && nvme_tcp_queue_more(queue)) +		queue_work_on(queue->io_cpu, nvme_tcp_wq, &queue->io_work);  }  static void nvme_tcp_process_req_list(struct nvme_tcp_queue *queue) @@ -613,7 +620,7 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,  		cpu_to_le32(data->hdr.hlen + hdgst + req->pdu_len + ddgst);  	data->ttag = pdu->ttag;  	data->command_id = nvme_cid(rq); -	data->data_offset = cpu_to_le32(req->data_sent); +	data->data_offset = pdu->r2t_offset;  	data->data_length = cpu_to_le32(req->pdu_len);  	return 0;  } @@ -906,12 +913,6 @@ done:  	read_unlock_bh(&sk->sk_callback_lock);  } -static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue) -{ -	return !list_empty(&queue->send_list) || -		!llist_empty(&queue->req_list) || queue->more_requests; -} -  static inline void nvme_tcp_done_send_req(struct nvme_tcp_queue *queue)  {  	queue->request = NULL; @@ -925,12 +926,14 @@ static void nvme_tcp_fail_request(struct nvme_tcp_request *req)  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)) @@ -952,7 +955,15 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)  			nvme_tcp_ddgst_update(queue->snd_hash, page,  					offset, ret); -		/* fully successful last write*/ +		/* +		 * 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, @@ -964,7 +975,6 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)  			}  			return 1;  		} -		nvme_tcp_advance_req(req, ret);  	}  	return -EAGAIN;  } @@ -1040,10 +1050,11 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req)  static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)  {  	struct nvme_tcp_queue *queue = req->queue; +	size_t offset = req->offset;  	int ret;  	struct msghdr msg = { .msg_flags = MSG_DONTWAIT };  	struct kvec iov = { -		.iov_base = &req->ddgst + req->offset, +		.iov_base = (u8 *)&req->ddgst + req->offset,  		.iov_len = NVME_TCP_DIGEST_LENGTH - req->offset  	}; @@ -1056,7 +1067,7 @@ static int nvme_tcp_try_send_ddgst(struct nvme_tcp_request *req)  	if (unlikely(ret <= 0))  		return ret; -	if (req->offset + ret == NVME_TCP_DIGEST_LENGTH) { +	if (offset + ret == NVME_TCP_DIGEST_LENGTH) {  		nvme_tcp_done_send_req(queue);  		return 1;  	} @@ -1145,8 +1156,7 @@ static void nvme_tcp_io_work(struct work_struct *w)  				pending = true;  			else if (unlikely(result < 0))  				break; -		} else -			pending = !llist_empty(&queue->req_list); +		}  		result = nvme_tcp_try_recv(queue);  		if (result > 0) |