diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-05-30 01:37:28 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-05 19:12:25 -0400 |
commit | 3219e5294150aee7d389e19029f49b44fb6b5c9f (patch) | |
tree | 44236fd9f2eb40d5622cadb126e9f2672b129486 /drivers | |
parent | 040515f53c09047c76ad074dc6a280984dc84b04 (diff) |
[SCSI] iscsi: fix writepsace race
We can race and misset the suspend bit if iscsi_write_space is
called then iscsi_send returns with a failure indicating
there is no space.
To handle this this patch returns a error upwards allowing xmitworker
to decide if we need to try and transmit again. For the no
write space case xmitworker will not retry, and instead
let iscsi_write_space queue it back up if needed (this relies
on the work queue code to properly requeue us if needed).
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 182 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 31 |
2 files changed, 120 insertions, 93 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2abda804a924..7fa85937a99f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -1006,7 +1006,6 @@ iscsi_write_space(struct sock *sk) | |||
1006 | 1006 | ||
1007 | tcp_conn->old_write_space(sk); | 1007 | tcp_conn->old_write_space(sk); |
1008 | debug_tcp("iscsi_write_space: cid %d\n", conn->id); | 1008 | debug_tcp("iscsi_write_space: cid %d\n", conn->id); |
1009 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1010 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1009 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
1011 | } | 1010 | } |
1012 | 1011 | ||
@@ -1056,7 +1055,7 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) | |||
1056 | { | 1055 | { |
1057 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1056 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1058 | struct socket *sk = tcp_conn->sock; | 1057 | struct socket *sk = tcp_conn->sock; |
1059 | int offset = buf->sg.offset + buf->sent; | 1058 | int offset = buf->sg.offset + buf->sent, res; |
1060 | 1059 | ||
1061 | /* | 1060 | /* |
1062 | * if we got use_sg=0 or are sending something we kmallocd | 1061 | * if we got use_sg=0 or are sending something we kmallocd |
@@ -1067,10 +1066,22 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) | |||
1067 | * slab case. | 1066 | * slab case. |
1068 | */ | 1067 | */ |
1069 | if (buf->use_sendmsg) | 1068 | if (buf->use_sendmsg) |
1070 | return sock_no_sendpage(sk, buf->sg.page, offset, size, flags); | 1069 | res = sock_no_sendpage(sk, buf->sg.page, offset, size, flags); |
1071 | else | 1070 | else |
1072 | return tcp_conn->sendpage(sk, buf->sg.page, offset, size, | 1071 | res = tcp_conn->sendpage(sk, buf->sg.page, offset, size, flags); |
1073 | flags); | 1072 | |
1073 | if (res >= 0) { | ||
1074 | conn->txdata_octets += res; | ||
1075 | buf->sent += res; | ||
1076 | return res; | ||
1077 | } | ||
1078 | |||
1079 | tcp_conn->sendpage_failures_cnt++; | ||
1080 | if (res == -EAGAIN) | ||
1081 | res = -ENOBUFS; | ||
1082 | else | ||
1083 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1084 | return res; | ||
1074 | } | 1085 | } |
1075 | 1086 | ||
1076 | /** | 1087 | /** |
@@ -1085,7 +1096,6 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) | |||
1085 | static inline int | 1096 | static inline int |
1086 | iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) | 1097 | iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) |
1087 | { | 1098 | { |
1088 | struct iscsi_tcp_conn *tcp_conn; | ||
1089 | int flags = 0; /* MSG_DONTWAIT; */ | 1099 | int flags = 0; /* MSG_DONTWAIT; */ |
1090 | int res, size; | 1100 | int res, size; |
1091 | 1101 | ||
@@ -1097,17 +1107,10 @@ iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) | |||
1097 | res = iscsi_send(conn, buf, size, flags); | 1107 | res = iscsi_send(conn, buf, size, flags); |
1098 | debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res); | 1108 | debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res); |
1099 | if (res >= 0) { | 1109 | if (res >= 0) { |
1100 | conn->txdata_octets += res; | ||
1101 | buf->sent += res; | ||
1102 | if (size != res) | 1110 | if (size != res) |
1103 | return -EAGAIN; | 1111 | return -EAGAIN; |
1104 | return 0; | 1112 | return 0; |
1105 | } else if (res == -EAGAIN) { | 1113 | } |
1106 | tcp_conn = conn->dd_data; | ||
1107 | tcp_conn->sendpage_failures_cnt++; | ||
1108 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1109 | } else if (res == -EPIPE) | ||
1110 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1111 | 1114 | ||
1112 | return res; | 1115 | return res; |
1113 | } | 1116 | } |
@@ -1126,7 +1129,6 @@ static inline int | |||
1126 | iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, | 1129 | iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, |
1127 | int *count, int *sent) | 1130 | int *count, int *sent) |
1128 | { | 1131 | { |
1129 | struct iscsi_tcp_conn *tcp_conn; | ||
1130 | int flags = 0; /* MSG_DONTWAIT; */ | 1132 | int flags = 0; /* MSG_DONTWAIT; */ |
1131 | int res, size; | 1133 | int res, size; |
1132 | 1134 | ||
@@ -1141,19 +1143,12 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, | |||
1141 | debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n", | 1143 | debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n", |
1142 | size, buf->sent, *count, *sent, res); | 1144 | size, buf->sent, *count, *sent, res); |
1143 | if (res >= 0) { | 1145 | if (res >= 0) { |
1144 | conn->txdata_octets += res; | ||
1145 | buf->sent += res; | ||
1146 | *count -= res; | 1146 | *count -= res; |
1147 | *sent += res; | 1147 | *sent += res; |
1148 | if (size != res) | 1148 | if (size != res) |
1149 | return -EAGAIN; | 1149 | return -EAGAIN; |
1150 | return 0; | 1150 | return 0; |
1151 | } else if (res == -EAGAIN) { | 1151 | } |
1152 | tcp_conn = conn->dd_data; | ||
1153 | tcp_conn->sendpage_failures_cnt++; | ||
1154 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1155 | } else if (res == -EPIPE) | ||
1156 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1157 | 1152 | ||
1158 | return res; | 1153 | return res; |
1159 | } | 1154 | } |
@@ -1342,6 +1337,7 @@ static int | |||
1342 | iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | 1337 | iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) |
1343 | { | 1338 | { |
1344 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; | 1339 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; |
1340 | int rc; | ||
1345 | 1341 | ||
1346 | debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", | 1342 | debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", |
1347 | conn->id, tcp_mtask->xmstate, mtask->itt); | 1343 | conn->id, tcp_mtask->xmstate, mtask->itt); |
@@ -1355,12 +1351,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | |||
1355 | conn->hdrdgst_en) | 1351 | conn->hdrdgst_en) |
1356 | iscsi_hdr_digest(conn, &tcp_mtask->headbuf, | 1352 | iscsi_hdr_digest(conn, &tcp_mtask->headbuf, |
1357 | (u8*)tcp_mtask->hdrext); | 1353 | (u8*)tcp_mtask->hdrext); |
1358 | if (iscsi_sendhdr(conn, &tcp_mtask->headbuf, | 1354 | rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf, |
1359 | mtask->data_count)) { | 1355 | mtask->data_count); |
1356 | if (rc) { | ||
1360 | tcp_mtask->xmstate |= XMSTATE_IMM_HDR; | 1357 | tcp_mtask->xmstate |= XMSTATE_IMM_HDR; |
1361 | if (mtask->data_count) | 1358 | if (mtask->data_count) |
1362 | tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA; | 1359 | tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA; |
1363 | return -EAGAIN; | 1360 | return rc; |
1364 | } | 1361 | } |
1365 | } | 1362 | } |
1366 | 1363 | ||
@@ -1371,10 +1368,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | |||
1371 | * Virtual buffer could be spreaded across multiple pages... | 1368 | * Virtual buffer could be spreaded across multiple pages... |
1372 | */ | 1369 | */ |
1373 | do { | 1370 | do { |
1374 | if (iscsi_sendpage(conn, &tcp_mtask->sendbuf, | 1371 | int rc; |
1375 | &mtask->data_count, &tcp_mtask->sent)) { | 1372 | |
1373 | rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf, | ||
1374 | &mtask->data_count, &tcp_mtask->sent); | ||
1375 | if (rc) { | ||
1376 | tcp_mtask->xmstate |= XMSTATE_IMM_DATA; | 1376 | tcp_mtask->xmstate |= XMSTATE_IMM_DATA; |
1377 | return -EAGAIN; | 1377 | return rc; |
1378 | } | 1378 | } |
1379 | } while (mtask->data_count); | 1379 | } while (mtask->data_count); |
1380 | } | 1380 | } |
@@ -1396,16 +1396,19 @@ static inline int | |||
1396 | handle_xmstate_r_hdr(struct iscsi_conn *conn, | 1396 | handle_xmstate_r_hdr(struct iscsi_conn *conn, |
1397 | struct iscsi_tcp_cmd_task *tcp_ctask) | 1397 | struct iscsi_tcp_cmd_task *tcp_ctask) |
1398 | { | 1398 | { |
1399 | int rc; | ||
1400 | |||
1399 | tcp_ctask->xmstate &= ~XMSTATE_R_HDR; | 1401 | tcp_ctask->xmstate &= ~XMSTATE_R_HDR; |
1400 | if (conn->hdrdgst_en) | 1402 | if (conn->hdrdgst_en) |
1401 | iscsi_hdr_digest(conn, &tcp_ctask->headbuf, | 1403 | iscsi_hdr_digest(conn, &tcp_ctask->headbuf, |
1402 | (u8*)tcp_ctask->hdrext); | 1404 | (u8*)tcp_ctask->hdrext); |
1403 | if (!iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0)) { | 1405 | rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0); |
1406 | if (!rc) { | ||
1404 | BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE); | 1407 | BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE); |
1405 | return 0; /* wait for Data-In */ | 1408 | return 0; /* wait for Data-In */ |
1406 | } | 1409 | } |
1407 | tcp_ctask->xmstate |= XMSTATE_R_HDR; | 1410 | tcp_ctask->xmstate |= XMSTATE_R_HDR; |
1408 | return -EAGAIN; | 1411 | return rc; |
1409 | } | 1412 | } |
1410 | 1413 | ||
1411 | static inline int | 1414 | static inline int |
@@ -1413,16 +1416,16 @@ handle_xmstate_w_hdr(struct iscsi_conn *conn, | |||
1413 | struct iscsi_cmd_task *ctask) | 1416 | struct iscsi_cmd_task *ctask) |
1414 | { | 1417 | { |
1415 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1418 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1419 | int rc; | ||
1416 | 1420 | ||
1417 | tcp_ctask->xmstate &= ~XMSTATE_W_HDR; | 1421 | tcp_ctask->xmstate &= ~XMSTATE_W_HDR; |
1418 | if (conn->hdrdgst_en) | 1422 | if (conn->hdrdgst_en) |
1419 | iscsi_hdr_digest(conn, &tcp_ctask->headbuf, | 1423 | iscsi_hdr_digest(conn, &tcp_ctask->headbuf, |
1420 | (u8*)tcp_ctask->hdrext); | 1424 | (u8*)tcp_ctask->hdrext); |
1421 | if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count)) { | 1425 | rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); |
1426 | if (rc) | ||
1422 | tcp_ctask->xmstate |= XMSTATE_W_HDR; | 1427 | tcp_ctask->xmstate |= XMSTATE_W_HDR; |
1423 | return -EAGAIN; | 1428 | return rc; |
1424 | } | ||
1425 | return 0; | ||
1426 | } | 1429 | } |
1427 | 1430 | ||
1428 | static inline int | 1431 | static inline int |
@@ -1430,17 +1433,19 @@ handle_xmstate_data_digest(struct iscsi_conn *conn, | |||
1430 | struct iscsi_cmd_task *ctask) | 1433 | struct iscsi_cmd_task *ctask) |
1431 | { | 1434 | { |
1432 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1435 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1436 | int rc; | ||
1433 | 1437 | ||
1434 | tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST; | 1438 | tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST; |
1435 | debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest); | 1439 | debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest); |
1436 | if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, | 1440 | rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, |
1437 | &tcp_ctask->datadigest, 0)) { | 1441 | &tcp_ctask->datadigest, 0); |
1442 | if (rc) { | ||
1438 | tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST; | 1443 | tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST; |
1439 | debug_tcp("resent data digest 0x%x fail!\n", | 1444 | debug_tcp("resent data digest 0x%x fail!\n", |
1440 | tcp_ctask->datadigest); | 1445 | tcp_ctask->datadigest); |
1441 | return -EAGAIN; | ||
1442 | } | 1446 | } |
1443 | return 0; | 1447 | |
1448 | return rc; | ||
1444 | } | 1449 | } |
1445 | 1450 | ||
1446 | static inline int | 1451 | static inline int |
@@ -1448,6 +1453,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1448 | { | 1453 | { |
1449 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1454 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1450 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1455 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1456 | int rc; | ||
1451 | 1457 | ||
1452 | BUG_ON(!ctask->imm_count); | 1458 | BUG_ON(!ctask->imm_count); |
1453 | tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA; | 1459 | tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA; |
@@ -1458,8 +1464,9 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1458 | } | 1464 | } |
1459 | 1465 | ||
1460 | for (;;) { | 1466 | for (;;) { |
1461 | if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &ctask->imm_count, | 1467 | rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, |
1462 | &tcp_ctask->sent)) { | 1468 | &ctask->imm_count, &tcp_ctask->sent); |
1469 | if (rc) { | ||
1463 | tcp_ctask->xmstate |= XMSTATE_IMM_DATA; | 1470 | tcp_ctask->xmstate |= XMSTATE_IMM_DATA; |
1464 | if (conn->datadgst_en) { | 1471 | if (conn->datadgst_en) { |
1465 | crypto_digest_final(tcp_conn->data_tx_tfm, | 1472 | crypto_digest_final(tcp_conn->data_tx_tfm, |
@@ -1467,7 +1474,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1467 | debug_tcp("tx imm sendpage fail 0x%x\n", | 1474 | debug_tcp("tx imm sendpage fail 0x%x\n", |
1468 | tcp_ctask->datadigest); | 1475 | tcp_ctask->datadigest); |
1469 | } | 1476 | } |
1470 | return -EAGAIN; | 1477 | return rc; |
1471 | } | 1478 | } |
1472 | if (conn->datadgst_en) | 1479 | if (conn->datadgst_en) |
1473 | crypto_digest_update(tcp_conn->data_tx_tfm, | 1480 | crypto_digest_update(tcp_conn->data_tx_tfm, |
@@ -1480,11 +1487,12 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1480 | } | 1487 | } |
1481 | 1488 | ||
1482 | if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { | 1489 | if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { |
1483 | if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, | 1490 | rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf, |
1484 | &tcp_ctask->immdigest, 1)) { | 1491 | &tcp_ctask->immdigest, 1); |
1492 | if (rc) { | ||
1485 | debug_tcp("sending imm digest 0x%x fail!\n", | 1493 | debug_tcp("sending imm digest 0x%x fail!\n", |
1486 | tcp_ctask->immdigest); | 1494 | tcp_ctask->immdigest); |
1487 | return -EAGAIN; | 1495 | return rc; |
1488 | } | 1496 | } |
1489 | debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest); | 1497 | debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest); |
1490 | } | 1498 | } |
@@ -1497,6 +1505,7 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1497 | { | 1505 | { |
1498 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1506 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1499 | struct iscsi_data_task *dtask; | 1507 | struct iscsi_data_task *dtask; |
1508 | int rc; | ||
1500 | 1509 | ||
1501 | tcp_ctask->xmstate |= XMSTATE_UNS_DATA; | 1510 | tcp_ctask->xmstate |= XMSTATE_UNS_DATA; |
1502 | if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) { | 1511 | if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) { |
@@ -1507,10 +1516,12 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1507 | (u8*)dtask->hdrext); | 1516 | (u8*)dtask->hdrext); |
1508 | tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT; | 1517 | tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT; |
1509 | } | 1518 | } |
1510 | if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count)) { | 1519 | |
1520 | rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count); | ||
1521 | if (rc) { | ||
1511 | tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; | 1522 | tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; |
1512 | tcp_ctask->xmstate |= XMSTATE_UNS_HDR; | 1523 | tcp_ctask->xmstate |= XMSTATE_UNS_HDR; |
1513 | return -EAGAIN; | 1524 | return rc; |
1514 | } | 1525 | } |
1515 | 1526 | ||
1516 | debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n", | 1527 | debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n", |
@@ -1524,6 +1535,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1524 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1535 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1525 | struct iscsi_data_task *dtask = tcp_ctask->dtask; | 1536 | struct iscsi_data_task *dtask = tcp_ctask->dtask; |
1526 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1537 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1538 | int rc; | ||
1527 | 1539 | ||
1528 | BUG_ON(!ctask->data_count); | 1540 | BUG_ON(!ctask->data_count); |
1529 | tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; | 1541 | tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA; |
@@ -1536,8 +1548,9 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1536 | for (;;) { | 1548 | for (;;) { |
1537 | int start = tcp_ctask->sent; | 1549 | int start = tcp_ctask->sent; |
1538 | 1550 | ||
1539 | if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, | 1551 | rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, |
1540 | &ctask->data_count, &tcp_ctask->sent)) { | 1552 | &ctask->data_count, &tcp_ctask->sent); |
1553 | if (rc) { | ||
1541 | ctask->unsol_count -= tcp_ctask->sent - start; | 1554 | ctask->unsol_count -= tcp_ctask->sent - start; |
1542 | tcp_ctask->xmstate |= XMSTATE_UNS_DATA; | 1555 | tcp_ctask->xmstate |= XMSTATE_UNS_DATA; |
1543 | /* will continue with this ctask later.. */ | 1556 | /* will continue with this ctask later.. */ |
@@ -1547,7 +1560,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1547 | debug_tcp("tx uns data fail 0x%x\n", | 1560 | debug_tcp("tx uns data fail 0x%x\n", |
1548 | dtask->digest); | 1561 | dtask->digest); |
1549 | } | 1562 | } |
1550 | return -EAGAIN; | 1563 | return rc; |
1551 | } | 1564 | } |
1552 | 1565 | ||
1553 | BUG_ON(tcp_ctask->sent > ctask->total_length); | 1566 | BUG_ON(tcp_ctask->sent > ctask->total_length); |
@@ -1574,12 +1587,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1574 | */ | 1587 | */ |
1575 | if (ctask->unsol_count) { | 1588 | if (ctask->unsol_count) { |
1576 | if (conn->datadgst_en) { | 1589 | if (conn->datadgst_en) { |
1577 | if (iscsi_digest_final_send(conn, ctask, | 1590 | rc = iscsi_digest_final_send(conn, ctask, |
1578 | &dtask->digestbuf, | 1591 | &dtask->digestbuf, |
1579 | &dtask->digest, 1)) { | 1592 | &dtask->digest, 1); |
1593 | if (rc) { | ||
1580 | debug_tcp("send uns digest 0x%x fail\n", | 1594 | debug_tcp("send uns digest 0x%x fail\n", |
1581 | dtask->digest); | 1595 | dtask->digest); |
1582 | return -EAGAIN; | 1596 | return rc; |
1583 | } | 1597 | } |
1584 | debug_tcp("sending uns digest 0x%x, more uns\n", | 1598 | debug_tcp("sending uns digest 0x%x, more uns\n", |
1585 | dtask->digest); | 1599 | dtask->digest); |
@@ -1589,12 +1603,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1589 | } | 1603 | } |
1590 | 1604 | ||
1591 | if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { | 1605 | if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) { |
1592 | if (iscsi_digest_final_send(conn, ctask, | 1606 | rc = iscsi_digest_final_send(conn, ctask, |
1593 | &dtask->digestbuf, | 1607 | &dtask->digestbuf, |
1594 | &dtask->digest, 1)) { | 1608 | &dtask->digest, 1); |
1609 | if (rc) { | ||
1595 | debug_tcp("send last uns digest 0x%x fail\n", | 1610 | debug_tcp("send last uns digest 0x%x fail\n", |
1596 | dtask->digest); | 1611 | dtask->digest); |
1597 | return -EAGAIN; | 1612 | return rc; |
1598 | } | 1613 | } |
1599 | debug_tcp("sending uns digest 0x%x\n",dtask->digest); | 1614 | debug_tcp("sending uns digest 0x%x\n",dtask->digest); |
1600 | } | 1615 | } |
@@ -1610,7 +1625,7 @@ handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1610 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1625 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1611 | struct iscsi_r2t_info *r2t = tcp_ctask->r2t; | 1626 | struct iscsi_r2t_info *r2t = tcp_ctask->r2t; |
1612 | struct iscsi_data_task *dtask = &r2t->dtask; | 1627 | struct iscsi_data_task *dtask = &r2t->dtask; |
1613 | int left; | 1628 | int left, rc; |
1614 | 1629 | ||
1615 | tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; | 1630 | tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; |
1616 | tcp_ctask->dtask = dtask; | 1631 | tcp_ctask->dtask = dtask; |
@@ -1626,7 +1641,8 @@ solicit_again: | |||
1626 | if (!r2t->data_count) | 1641 | if (!r2t->data_count) |
1627 | goto data_out_done; | 1642 | goto data_out_done; |
1628 | 1643 | ||
1629 | if (iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent)) { | 1644 | rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent); |
1645 | if (rc) { | ||
1630 | tcp_ctask->xmstate |= XMSTATE_SOL_DATA; | 1646 | tcp_ctask->xmstate |= XMSTATE_SOL_DATA; |
1631 | /* will continue with this ctask later.. */ | 1647 | /* will continue with this ctask later.. */ |
1632 | if (conn->datadgst_en) { | 1648 | if (conn->datadgst_en) { |
@@ -1634,7 +1650,7 @@ solicit_again: | |||
1634 | (u8 *)&dtask->digest); | 1650 | (u8 *)&dtask->digest); |
1635 | debug_tcp("r2t data send fail 0x%x\n", dtask->digest); | 1651 | debug_tcp("r2t data send fail 0x%x\n", dtask->digest); |
1636 | } | 1652 | } |
1637 | return -EAGAIN; | 1653 | return rc; |
1638 | } | 1654 | } |
1639 | 1655 | ||
1640 | BUG_ON(r2t->data_count < 0); | 1656 | BUG_ON(r2t->data_count < 0); |
@@ -1661,12 +1677,13 @@ data_out_done: | |||
1661 | left = r2t->data_length - r2t->sent; | 1677 | left = r2t->data_length - r2t->sent; |
1662 | if (left) { | 1678 | if (left) { |
1663 | if (conn->datadgst_en) { | 1679 | if (conn->datadgst_en) { |
1664 | if (iscsi_digest_final_send(conn, ctask, | 1680 | rc = iscsi_digest_final_send(conn, ctask, |
1665 | &dtask->digestbuf, | 1681 | &dtask->digestbuf, |
1666 | &dtask->digest, 1)) { | 1682 | &dtask->digest, 1); |
1683 | if (rc) { | ||
1667 | debug_tcp("send r2t data digest 0x%x" | 1684 | debug_tcp("send r2t data digest 0x%x" |
1668 | "fail\n", dtask->digest); | 1685 | "fail\n", dtask->digest); |
1669 | return -EAGAIN; | 1686 | return rc; |
1670 | } | 1687 | } |
1671 | debug_tcp("r2t data send digest 0x%x\n", | 1688 | debug_tcp("r2t data send digest 0x%x\n", |
1672 | dtask->digest); | 1689 | dtask->digest); |
@@ -1683,11 +1700,12 @@ data_out_done: | |||
1683 | */ | 1700 | */ |
1684 | BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0); | 1701 | BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0); |
1685 | if (conn->datadgst_en) { | 1702 | if (conn->datadgst_en) { |
1686 | if (iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, | 1703 | rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf, |
1687 | &dtask->digest, 1)) { | 1704 | &dtask->digest, 1); |
1705 | if (rc) { | ||
1688 | debug_tcp("send last r2t data digest 0x%x" | 1706 | debug_tcp("send last r2t data digest 0x%x" |
1689 | "fail\n", dtask->digest); | 1707 | "fail\n", dtask->digest); |
1690 | return -EAGAIN; | 1708 | return rc; |
1691 | } | 1709 | } |
1692 | debug_tcp("r2t done dout digest 0x%x\n", dtask->digest); | 1710 | debug_tcp("r2t done dout digest 0x%x\n", dtask->digest); |
1693 | } | 1711 | } |
@@ -1713,15 +1731,16 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1713 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1731 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; |
1714 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1732 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1715 | struct iscsi_data_task *dtask = tcp_ctask->dtask; | 1733 | struct iscsi_data_task *dtask = tcp_ctask->dtask; |
1716 | int sent; | 1734 | int sent, rc; |
1717 | 1735 | ||
1718 | tcp_ctask->xmstate &= ~XMSTATE_W_PAD; | 1736 | tcp_ctask->xmstate &= ~XMSTATE_W_PAD; |
1719 | iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, | 1737 | iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, |
1720 | tcp_ctask->pad_count); | 1738 | tcp_ctask->pad_count); |
1721 | if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, | 1739 | rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, |
1722 | &sent)) { | 1740 | &sent); |
1741 | if (rc) { | ||
1723 | tcp_ctask->xmstate |= XMSTATE_W_PAD; | 1742 | tcp_ctask->xmstate |= XMSTATE_W_PAD; |
1724 | return -EAGAIN; | 1743 | return rc; |
1725 | } | 1744 | } |
1726 | 1745 | ||
1727 | if (conn->datadgst_en) { | 1746 | if (conn->datadgst_en) { |
@@ -1729,22 +1748,24 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1729 | &tcp_ctask->sendbuf.sg, 1); | 1748 | &tcp_ctask->sendbuf.sg, 1); |
1730 | /* imm data? */ | 1749 | /* imm data? */ |
1731 | if (!dtask) { | 1750 | if (!dtask) { |
1732 | if (iscsi_digest_final_send(conn, ctask, | 1751 | rc = iscsi_digest_final_send(conn, ctask, |
1733 | &tcp_ctask->immbuf, | 1752 | &tcp_ctask->immbuf, |
1734 | &tcp_ctask->immdigest, 1)) { | 1753 | &tcp_ctask->immdigest, 1); |
1754 | if (rc) { | ||
1735 | debug_tcp("send padding digest 0x%x" | 1755 | debug_tcp("send padding digest 0x%x" |
1736 | "fail!\n", tcp_ctask->immdigest); | 1756 | "fail!\n", tcp_ctask->immdigest); |
1737 | return -EAGAIN; | 1757 | return rc; |
1738 | } | 1758 | } |
1739 | debug_tcp("done with padding, digest 0x%x\n", | 1759 | debug_tcp("done with padding, digest 0x%x\n", |
1740 | tcp_ctask->datadigest); | 1760 | tcp_ctask->datadigest); |
1741 | } else { | 1761 | } else { |
1742 | if (iscsi_digest_final_send(conn, ctask, | 1762 | rc = iscsi_digest_final_send(conn, ctask, |
1743 | &dtask->digestbuf, | 1763 | &dtask->digestbuf, |
1744 | &dtask->digest, 1)) { | 1764 | &dtask->digest, 1); |
1765 | if (rc) { | ||
1745 | debug_tcp("send padding digest 0x%x" | 1766 | debug_tcp("send padding digest 0x%x" |
1746 | "fail\n", dtask->digest); | 1767 | "fail\n", dtask->digest); |
1747 | return -EAGAIN; | 1768 | return rc; |
1748 | } | 1769 | } |
1749 | debug_tcp("done with padding, digest 0x%x\n", | 1770 | debug_tcp("done with padding, digest 0x%x\n", |
1750 | dtask->digest); | 1771 | dtask->digest); |
@@ -1769,10 +1790,8 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
1769 | if (ctask->mtask) | 1790 | if (ctask->mtask) |
1770 | return rc; | 1791 | return rc; |
1771 | 1792 | ||
1772 | if (tcp_ctask->xmstate & XMSTATE_R_HDR) { | 1793 | if (tcp_ctask->xmstate & XMSTATE_R_HDR) |
1773 | rc = handle_xmstate_r_hdr(conn, tcp_ctask); | 1794 | return handle_xmstate_r_hdr(conn, tcp_ctask); |
1774 | return rc; | ||
1775 | } | ||
1776 | 1795 | ||
1777 | if (tcp_ctask->xmstate & XMSTATE_W_HDR) { | 1796 | if (tcp_ctask->xmstate & XMSTATE_W_HDR) { |
1778 | rc = handle_xmstate_w_hdr(conn, ctask); | 1797 | rc = handle_xmstate_w_hdr(conn, ctask); |
@@ -1824,10 +1843,11 @@ solicit_head_again: | |||
1824 | if (conn->hdrdgst_en) | 1843 | if (conn->hdrdgst_en) |
1825 | iscsi_hdr_digest(conn, &r2t->headbuf, | 1844 | iscsi_hdr_digest(conn, &r2t->headbuf, |
1826 | (u8*)r2t->dtask.hdrext); | 1845 | (u8*)r2t->dtask.hdrext); |
1827 | if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) { | 1846 | rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count); |
1847 | if (rc) { | ||
1828 | tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; | 1848 | tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; |
1829 | tcp_ctask->xmstate |= XMSTATE_SOL_HDR; | 1849 | tcp_ctask->xmstate |= XMSTATE_SOL_HDR; |
1830 | return -EAGAIN; | 1850 | return rc; |
1831 | } | 1851 | } |
1832 | 1852 | ||
1833 | debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n", | 1853 | debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n", |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 256b87a85978..2673a11a9495 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -513,10 +513,11 @@ EXPORT_SYMBOL_GPL(iscsi_conn_failure); | |||
513 | static int iscsi_data_xmit(struct iscsi_conn *conn) | 513 | static int iscsi_data_xmit(struct iscsi_conn *conn) |
514 | { | 514 | { |
515 | struct iscsi_transport *tt; | 515 | struct iscsi_transport *tt; |
516 | int rc = 0; | ||
516 | 517 | ||
517 | if (unlikely(conn->suspend_tx)) { | 518 | if (unlikely(conn->suspend_tx)) { |
518 | debug_scsi("conn %d Tx suspended!\n", conn->id); | 519 | debug_scsi("conn %d Tx suspended!\n", conn->id); |
519 | return 0; | 520 | return -ENODATA; |
520 | } | 521 | } |
521 | tt = conn->session->tt; | 522 | tt = conn->session->tt; |
522 | 523 | ||
@@ -536,13 +537,15 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
536 | BUG_ON(conn->ctask && conn->mtask); | 537 | BUG_ON(conn->ctask && conn->mtask); |
537 | 538 | ||
538 | if (conn->ctask) { | 539 | if (conn->ctask) { |
539 | if (tt->xmit_cmd_task(conn, conn->ctask)) | 540 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
541 | if (rc) | ||
540 | goto again; | 542 | goto again; |
541 | /* done with this in-progress ctask */ | 543 | /* done with this in-progress ctask */ |
542 | conn->ctask = NULL; | 544 | conn->ctask = NULL; |
543 | } | 545 | } |
544 | if (conn->mtask) { | 546 | if (conn->mtask) { |
545 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 547 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
548 | if (rc) | ||
546 | goto again; | 549 | goto again; |
547 | /* done with this in-progress mtask */ | 550 | /* done with this in-progress mtask */ |
548 | conn->mtask = NULL; | 551 | conn->mtask = NULL; |
@@ -556,7 +559,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
556 | list_add_tail(&conn->mtask->running, | 559 | list_add_tail(&conn->mtask->running, |
557 | &conn->mgmt_run_list); | 560 | &conn->mgmt_run_list); |
558 | spin_unlock_bh(&conn->session->lock); | 561 | spin_unlock_bh(&conn->session->lock); |
559 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 562 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
563 | if (rc) | ||
560 | goto again; | 564 | goto again; |
561 | } | 565 | } |
562 | /* done with this mtask */ | 566 | /* done with this mtask */ |
@@ -574,7 +578,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
574 | if (list_empty(&conn->ctask->running)) | 578 | if (list_empty(&conn->ctask->running)) |
575 | list_add_tail(&conn->ctask->running, &conn->run_list); | 579 | list_add_tail(&conn->ctask->running, &conn->run_list); |
576 | spin_unlock_bh(&conn->session->lock); | 580 | spin_unlock_bh(&conn->session->lock); |
577 | if (tt->xmit_cmd_task(conn, conn->ctask)) | 581 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
582 | if (rc) | ||
578 | goto again; | 583 | goto again; |
579 | } | 584 | } |
580 | /* done with this ctask */ | 585 | /* done with this ctask */ |
@@ -588,32 +593,34 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
588 | list_add_tail(&conn->mtask->running, | 593 | list_add_tail(&conn->mtask->running, |
589 | &conn->mgmt_run_list); | 594 | &conn->mgmt_run_list); |
590 | spin_unlock_bh(&conn->session->lock); | 595 | spin_unlock_bh(&conn->session->lock); |
591 | if (tt->xmit_mgmt_task(conn, conn->mtask)) | 596 | rc = tt->xmit_mgmt_task(conn, conn->mtask); |
597 | if (rc) | ||
592 | goto again; | 598 | goto again; |
593 | } | 599 | } |
594 | /* done with this mtask */ | 600 | /* done with this mtask */ |
595 | conn->mtask = NULL; | 601 | conn->mtask = NULL; |
596 | } | 602 | } |
597 | 603 | ||
598 | return 0; | 604 | return -ENODATA; |
599 | 605 | ||
600 | again: | 606 | again: |
601 | if (unlikely(conn->suspend_tx)) | 607 | if (unlikely(conn->suspend_tx)) |
602 | return 0; | 608 | return -ENODATA; |
603 | 609 | ||
604 | return -EAGAIN; | 610 | return rc; |
605 | } | 611 | } |
606 | 612 | ||
607 | static void iscsi_xmitworker(void *data) | 613 | static void iscsi_xmitworker(void *data) |
608 | { | 614 | { |
609 | struct iscsi_conn *conn = data; | 615 | struct iscsi_conn *conn = data; |
610 | 616 | int rc; | |
611 | /* | 617 | /* |
612 | * serialize Xmit worker on a per-connection basis. | 618 | * serialize Xmit worker on a per-connection basis. |
613 | */ | 619 | */ |
614 | mutex_lock(&conn->xmitmutex); | 620 | mutex_lock(&conn->xmitmutex); |
615 | if (iscsi_data_xmit(conn)) | 621 | do { |
616 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 622 | rc = iscsi_data_xmit(conn); |
623 | } while (rc >= 0 || rc == -EAGAIN); | ||
617 | mutex_unlock(&conn->xmitmutex); | 624 | mutex_unlock(&conn->xmitmutex); |
618 | } | 625 | } |
619 | 626 | ||