diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 0937aa76a..f73608b02 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -1407,7 +1407,7 @@ static void cmnd_prepare_get_rejected_immed_data(struct iscsi_cmnd *cmnd) struct iscsi_conn *conn = cmnd->conn; struct scatterlist *sg = cmnd->sg; char *addr; - u32 size; + u32 size, s, e; unsigned int i; TRACE_ENTRY(); @@ -1441,17 +1441,16 @@ static void cmnd_prepare_get_rejected_immed_data(struct iscsi_cmnd *cmnd) } addr = page_address(sg_page(&sg[0])); - conn->read_size = size; - for (i = 0; size > PAGE_SIZE; i++, size -= PAGE_SIZE) { + for (s = size, i = 0; s > 0; i++, s -= e) { /* We already checked pdu.datasize in check_segment_length() */ sBUG_ON(i >= ISCSI_CONN_IOV_MAX); conn->read_iov[i].iov_base = (void __force __user *)addr; - conn->read_iov[i].iov_len = PAGE_SIZE; + e = min_t(u32, s, PAGE_SIZE); + conn->read_iov[i].iov_len = e; } - conn->read_iov[i].iov_base = (void __force __user *)addr; - conn->read_iov[i].iov_len = size; conn->read_msg.msg_iov = conn->read_iov; - conn->read_msg.msg_iovlen = ++i; + conn->read_msg.msg_iovlen = i; + conn->read_size = size; out: TRACE_EXIT(); @@ -1532,6 +1531,7 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, struct scatterlist *sg = cmd->sg; unsigned int bufflen = cmd->bufflen; unsigned int idx, i, buff_offs; + const u32 read_size = size; int res = 0; TRACE_ENTRY(); @@ -1546,9 +1546,6 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, idx = offset >> PAGE_SHIFT; offset &= ~PAGE_MASK; - conn->read_msg.msg_iov = conn->read_iov; - conn->read_size = size; - i = 0; while (1) { unsigned int sg_len; @@ -1572,7 +1569,6 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, TRACE_DBG("idx=%d, i=%d, offset=%u, size=%d, addr=%p", idx, i, offset, size, addr); conn->read_iov[i].iov_len = size; - conn->read_msg.msg_iovlen = i+1; break; } conn->read_iov[i].iov_len = sg_len; @@ -1591,16 +1587,21 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, size); mark_conn_closed(conn); res = -EINVAL; - break; + goto out; } idx++; offset = 0; } - TRACE_DBG("msg_iov=%p, msg_iovlen=%zd", - conn->read_msg.msg_iov, conn->read_msg.msg_iovlen); + i++; + conn->read_msg.msg_iov = conn->read_iov; + conn->read_msg.msg_iovlen = i; + conn->read_size = read_size; + TRACE_DBG("msg_iov=%p, msg_iovlen=%u", conn->read_iov, i); + +out: TRACE_EXIT_RES(res); return res; } @@ -1740,7 +1741,6 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) size = cmnd->pdu.datasize; if (size) { - conn->read_msg.msg_iov = conn->read_iov; if (cmnd->pdu.bhs.itt != ISCSI_RESERVED_TAG) { struct scatterlist *sg; @@ -1764,7 +1764,6 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) (void __force __user *)(page_address(sg_page(&sg[i]))); tmp = min_t(u32, size, PAGE_SIZE); conn->read_iov[i].iov_len = tmp; - conn->read_size += tmp; size -= tmp; } sBUG_ON(size != 0); @@ -1779,7 +1778,6 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) (void __force __user *)(page_address(dummy_page)); tmp = min_t(u32, size, PAGE_SIZE); conn->read_iov[i].iov_len = tmp; - conn->read_size += tmp; size -= tmp; } @@ -1787,9 +1785,10 @@ static int nop_out_start(struct iscsi_cmnd *cmnd) sBUG_ON(size != 0); } + conn->read_msg.msg_iov = conn->read_iov; conn->read_msg.msg_iovlen = i; - TRACE_DBG("msg_iov=%p, msg_iovlen=%zd", conn->read_msg.msg_iov, - conn->read_msg.msg_iovlen); + conn->read_size = cmnd->pdu.datasize; + TRACE_DBG("msg_iov=%p, msg_iovlen=%d", conn->read_iov, i); } out: diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index f7fea7522..ff08181d6 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -680,8 +680,8 @@ static int do_recv(struct iscsi_conn *conn) { int res; mm_segment_t oldfs; - struct msghdr msg; - int first_len; + struct msghdr *msg; + int read_size; EXTRACHECKS_BUG_ON(conn->read_cmnd == NULL); @@ -697,45 +697,32 @@ static int do_recv(struct iscsi_conn *conn) */ restart: - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = conn->read_msg.msg_iov; - msg.msg_iovlen = conn->read_msg.msg_iovlen; - first_len = msg.msg_iov->iov_len; + msg = &conn->read_msg; + read_size = conn->read_size; oldfs = get_fs(); set_fs(get_ds()); - res = sock_recvmsg(conn->sock, &msg, conn->read_size, + res = sock_recvmsg(conn->sock, msg, read_size, MSG_DONTWAIT | MSG_NOSIGNAL); set_fs(oldfs); - TRACE_DBG("msg_iovlen %zd, first_len %d, read_size %d, res %d", - msg.msg_iovlen, first_len, conn->read_size, res); + TRACE_DBG("msg_iovlen %zd, read_size %d, res %d", msg->msg_iovlen, + read_size, res); if (res > 0) { /* - * To save some considerable effort and CPU power we - * suppose that TCP functions adjust - * conn->read_msg.msg_iov and conn->read_msg.msg_iovlen - * on amount of copied data. This BUG_ON is intended - * to catch if it is changed in the future. + * To save CPU cycles we suppose that sock_recvmsg() adjusts + * msg->msg_iov and msg->msg_iovlen. The BUG_ON() statement + * below verifies this. */ - sBUG_ON((res >= first_len) && - (conn->read_msg.msg_iov->iov_len != 0)); + /* To do: restore msg->msg_iov check. */ conn->read_size -= res; - if (conn->read_size != 0) { - if (res >= first_len) { - int done = 1 + ((res - first_len) >> PAGE_SHIFT); - TRACE_DBG("done %d", done); - conn->read_msg.msg_iov += done; - conn->read_msg.msg_iovlen -= done; - } - } res = conn->read_size; } else { switch (res) { case -EAGAIN: TRACE_DBG("EAGAIN received for conn %p", conn); - res = conn->read_size; + res = read_size; break; case -ERESTARTSYS: TRACE_DBG("ERESTARTSYS received for conn %p", conn); @@ -821,7 +808,7 @@ static int iscsi_rx_check_ddigest(struct iscsi_conn *conn) static int process_read_io(struct iscsi_conn *conn, int *closed) { struct iscsi_cmnd *cmnd = conn->read_cmnd; - int res; + int bytes_left, res; TRACE_ENTRY(); @@ -909,10 +896,11 @@ static int process_read_io(struct iscsi_conn *conn, int *closed) break; case RX_END: - if (unlikely(conn->read_size != 0)) { + bytes_left = conn->read_size; + if (unlikely(bytes_left != 0)) { PRINT_CRIT_ERROR("conn read_size !=0 on RX_END " "(conn %p, op %x, read_size %d)", conn, - cmnd_opcode(cmnd), conn->read_size); + cmnd_opcode(cmnd), bytes_left); sBUG(); } conn->read_cmnd = NULL;