Blob Blame History Raw
From: Varun Prakash <varun@chelsio.com>
Date: Sat, 29 Jul 2017 21:01:49 +0530
Subject: cxgbit: fix sg_nents calculation
Git-commit: d96adb9b076a12d30500347e2e667689062f44a0
Patch-mainline: v4.13-rc5
References: bsc#1046545

The current logic of calculating sg_nents can fail
if data_offset % PAGE_SIZE is not zero.

For example -
PAGE_SIZE = 4096
data_len = 3072
data_offset = 3072

As per current logic
sg_nents = max(1UL, DIV_ROUND_UP(data_len, PAGE_SIZE));
sg_nents = max(1UL, DIV_ROUND_UP(3072, 4096));
sg_nents = 1

But as data_offset % PAGE_SIZE = 3072 we should skip 3072 bytes
skip = 3K
sg_nents = max(1UL, DIV_ROUND_UP(3K(skip) + 3K(data_len), 4K(PAGE_SIZE));
sg_nents = 2;

This patch fixes this issue by adding skip to data_len.

Signed-off-by: Varun Prakash <varun@chelsio.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Acked-by: Lee Duncan <lduncan@suse.com>
---
 drivers/target/iscsi/cxgbit/cxgbit_target.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c
index dda13f1af38e..514986b57c2d 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_target.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c
@@ -827,7 +827,7 @@ static int cxgbit_set_params(struct iscsi_conn *conn)
 
 static void
 cxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg,
-		      unsigned int nents)
+		      unsigned int nents, u32 skip)
 {
 	struct skb_seq_state st;
 	const u8 *buf;
@@ -846,7 +846,7 @@ static int cxgbit_set_params(struct iscsi_conn *conn)
 		}
 
 		consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf,
-						 buf_len, consumed);
+						 buf_len, skip + consumed);
 	}
 }
 
@@ -912,7 +912,7 @@ static struct iscsi_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk)
 		struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0];
 		u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE));
 
-		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents);
+		cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0);
 	}
 
 	cmd->write_data_done += pdu_cb->dlen;
@@ -1069,11 +1069,13 @@ static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk)
 		  cmd->se_cmd.data_length);
 
 	if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) {
+		u32 skip = data_offset % PAGE_SIZE;
+
 		sg_off = data_offset / PAGE_SIZE;
 		sg_start = &cmd->se_cmd.t_data_sg[sg_off];
-		sg_nents = max(1UL, DIV_ROUND_UP(data_len, PAGE_SIZE));
+		sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE));
 
-		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents);
+		cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip);
 	}
 
 check_payload: