aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2006-07-24 16:47:39 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-07-28 12:49:34 -0400
commitc8dc1e523b0f1e6dd71cdabd8c7d7587c6dc27f9 (patch)
tree466efa148c152f4330c92f02f81bc72e8f395114
parent9aaa2b4621280b6de1ecfb6dd7cd5cbe59fd1264 (diff)
[SCSI] iscsi bugfixes: reduce memory allocations
We currently try to allocate a max_recv_data_segment_length which can be very large (default is 64K), and common uses are up to 1MB. It is very very difficult to allocte this much contiguous memory and it turns out we never even use it. We really only need a couple of pages, so this patch has us allocates just what we know what we need today. Later if vendors start adding vendor specific data and we need to handle large buffers we can do this, but for the last 4 years we have not seen anyone do this or request it. Signed-off-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/iscsi_tcp.c83
-rw-r--r--drivers/scsi/iscsi_tcp.h2
-rw-r--r--drivers/scsi/libiscsi.c10
-rw-r--r--include/scsi/libiscsi.h8
4 files changed, 38 insertions, 65 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index b6c68be6b866..aa20adc79f02 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -511,13 +511,28 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
511 break; 511 break;
512 case ISCSI_OP_LOGIN_RSP: 512 case ISCSI_OP_LOGIN_RSP:
513 case ISCSI_OP_TEXT_RSP: 513 case ISCSI_OP_TEXT_RSP:
514 case ISCSI_OP_LOGOUT_RSP:
515 case ISCSI_OP_NOOP_IN:
516 case ISCSI_OP_REJECT: 514 case ISCSI_OP_REJECT:
517 case ISCSI_OP_ASYNC_EVENT: 515 case ISCSI_OP_ASYNC_EVENT:
516 /*
517 * It is possible that we could get a PDU with a buffer larger
518 * than 8K, but there are no targets that currently do this.
519 * For now we fail until we find a vendor that needs it
520 */
521 if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
522 tcp_conn->in.datalen) {
523 printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
524 "but conn buffer is only %u (opcode %0x)\n",
525 tcp_conn->in.datalen,
526 DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
527 rc = ISCSI_ERR_PROTO;
528 break;
529 }
530
518 if (tcp_conn->in.datalen) 531 if (tcp_conn->in.datalen)
519 goto copy_hdr; 532 goto copy_hdr;
520 /* fall through */ 533 /* fall through */
534 case ISCSI_OP_LOGOUT_RSP:
535 case ISCSI_OP_NOOP_IN:
521 case ISCSI_OP_SCSI_TMFUNC_RSP: 536 case ISCSI_OP_SCSI_TMFUNC_RSP:
522 rc = iscsi_complete_pdu(conn, hdr, NULL, 0); 537 rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
523 break; 538 break;
@@ -625,9 +640,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
625 * byte counters. 640 * byte counters.
626 **/ 641 **/
627static inline int 642static inline int
628iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn) 643iscsi_tcp_copy(struct iscsi_conn *conn)
629{ 644{
630 void *buf = tcp_conn->data; 645 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
631 int buf_size = tcp_conn->in.datalen; 646 int buf_size = tcp_conn->in.datalen;
632 int buf_left = buf_size - tcp_conn->data_copied; 647 int buf_left = buf_size - tcp_conn->data_copied;
633 int size = min(tcp_conn->in.copy, buf_left); 648 int size = min(tcp_conn->in.copy, buf_left);
@@ -638,7 +653,7 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
638 BUG_ON(size <= 0); 653 BUG_ON(size <= 0);
639 654
640 rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, 655 rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
641 (char*)buf + tcp_conn->data_copied, size); 656 (char*)conn->data + tcp_conn->data_copied, size);
642 BUG_ON(rc); 657 BUG_ON(rc);
643 658
644 tcp_conn->in.offset += size; 659 tcp_conn->in.offset += size;
@@ -785,22 +800,21 @@ iscsi_data_recv(struct iscsi_conn *conn)
785 spin_unlock(&conn->session->lock); 800 spin_unlock(&conn->session->lock);
786 case ISCSI_OP_TEXT_RSP: 801 case ISCSI_OP_TEXT_RSP:
787 case ISCSI_OP_LOGIN_RSP: 802 case ISCSI_OP_LOGIN_RSP:
788 case ISCSI_OP_NOOP_IN:
789 case ISCSI_OP_ASYNC_EVENT: 803 case ISCSI_OP_ASYNC_EVENT:
790 case ISCSI_OP_REJECT: 804 case ISCSI_OP_REJECT:
791 /* 805 /*
792 * Collect data segment to the connection's data 806 * Collect data segment to the connection's data
793 * placeholder 807 * placeholder
794 */ 808 */
795 if (iscsi_tcp_copy(tcp_conn)) { 809 if (iscsi_tcp_copy(conn)) {
796 rc = -EAGAIN; 810 rc = -EAGAIN;
797 goto exit; 811 goto exit;
798 } 812 }
799 813
800 rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data, 814 rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
801 tcp_conn->in.datalen); 815 tcp_conn->in.datalen);
802 if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP) 816 if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
803 iscsi_recv_digest_update(tcp_conn, tcp_conn->data, 817 iscsi_recv_digest_update(tcp_conn, conn->data,
804 tcp_conn->in.datalen); 818 tcp_conn->in.datalen);
805 break; 819 break;
806 default: 820 default:
@@ -1911,21 +1925,9 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
1911 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; 1925 tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
1912 /* initial operational parameters */ 1926 /* initial operational parameters */
1913 tcp_conn->hdr_size = sizeof(struct iscsi_hdr); 1927 tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
1914 tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
1915
1916 /* allocate initial PDU receive place holder */
1917 if (tcp_conn->data_size <= PAGE_SIZE)
1918 tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL);
1919 else
1920 tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL,
1921 get_order(tcp_conn->data_size));
1922 if (!tcp_conn->data)
1923 goto max_recv_dlenght_alloc_fail;
1924 1928
1925 return cls_conn; 1929 return cls_conn;
1926 1930
1927max_recv_dlenght_alloc_fail:
1928 kfree(tcp_conn);
1929tcp_conn_alloc_fail: 1931tcp_conn_alloc_fail:
1930 iscsi_conn_teardown(cls_conn); 1932 iscsi_conn_teardown(cls_conn);
1931 return NULL; 1933 return NULL;
@@ -1973,12 +1975,6 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
1973 crypto_free_tfm(tcp_conn->data_rx_tfm); 1975 crypto_free_tfm(tcp_conn->data_rx_tfm);
1974 } 1976 }
1975 1977
1976 /* free conn->data, size = MaxRecvDataSegmentLength */
1977 if (tcp_conn->data_size <= PAGE_SIZE)
1978 kfree(tcp_conn->data);
1979 else
1980 free_pages((unsigned long)tcp_conn->data,
1981 get_order(tcp_conn->data_size));
1982 kfree(tcp_conn); 1978 kfree(tcp_conn);
1983} 1979}
1984 1980
@@ -2131,39 +2127,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
2131 int value; 2127 int value;
2132 2128
2133 switch(param) { 2129 switch(param) {
2134 case ISCSI_PARAM_MAX_RECV_DLENGTH: {
2135 char *saveptr = tcp_conn->data;
2136 gfp_t flags = GFP_KERNEL;
2137
2138 sscanf(buf, "%d", &value);
2139 if (tcp_conn->data_size >= value) {
2140 iscsi_set_param(cls_conn, param, buf, buflen);
2141 break;
2142 }
2143
2144 spin_lock_bh(&session->lock);
2145 if (conn->stop_stage == STOP_CONN_RECOVER)
2146 flags = GFP_ATOMIC;
2147 spin_unlock_bh(&session->lock);
2148
2149 if (value <= PAGE_SIZE)
2150 tcp_conn->data = kmalloc(value, flags);
2151 else
2152 tcp_conn->data = (void*)__get_free_pages(flags,
2153 get_order(value));
2154 if (tcp_conn->data == NULL) {
2155 tcp_conn->data = saveptr;
2156 return -ENOMEM;
2157 }
2158 if (tcp_conn->data_size <= PAGE_SIZE)
2159 kfree(saveptr);
2160 else
2161 free_pages((unsigned long)saveptr,
2162 get_order(tcp_conn->data_size));
2163 iscsi_set_param(cls_conn, param, buf, buflen);
2164 tcp_conn->data_size = value;
2165 break;
2166 }
2167 case ISCSI_PARAM_HDRDGST_EN: 2130 case ISCSI_PARAM_HDRDGST_EN:
2168 iscsi_set_param(cls_conn, param, buf, buflen); 2131 iscsi_set_param(cls_conn, param, buf, buflen);
2169 tcp_conn->hdr_size = sizeof(struct iscsi_hdr); 2132 tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 808302832e68..6a4ee704e46e 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -78,8 +78,6 @@ struct iscsi_tcp_conn {
78 char hdrext[4*sizeof(__u16) + 78 char hdrext[4*sizeof(__u16) +
79 sizeof(__u32)]; 79 sizeof(__u32)];
80 int data_copied; 80 int data_copied;
81 char *data; /* data placeholder */
82 int data_size; /* actual recv_dlength */
83 int stop_stage; /* conn_stop() flag: * 81 int stop_stage; /* conn_stop() flag: *
84 * stop to recover, * 82 * stop to recover, *
85 * stop to terminate */ 83 * stop to terminate */
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index c989bc6180b3..03b3dee49009 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -360,6 +360,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
360 360
361 switch(opcode) { 361 switch(opcode) {
362 case ISCSI_OP_LOGOUT_RSP: 362 case ISCSI_OP_LOGOUT_RSP:
363 if (datalen) {
364 rc = ISCSI_ERR_PROTO;
365 break;
366 }
363 conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 367 conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
364 /* fall through */ 368 /* fall through */
365 case ISCSI_OP_LOGIN_RSP: 369 case ISCSI_OP_LOGIN_RSP:
@@ -383,7 +387,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
383 iscsi_tmf_rsp(conn, hdr); 387 iscsi_tmf_rsp(conn, hdr);
384 break; 388 break;
385 case ISCSI_OP_NOOP_IN: 389 case ISCSI_OP_NOOP_IN:
386 if (hdr->ttt != ISCSI_RESERVED_TAG) { 390 if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
387 rc = ISCSI_ERR_PROTO; 391 rc = ISCSI_ERR_PROTO;
388 break; 392 break;
389 } 393 }
@@ -1405,7 +1409,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
1405 data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); 1409 data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
1406 if (!data) 1410 if (!data)
1407 goto login_mtask_data_alloc_fail; 1411 goto login_mtask_data_alloc_fail;
1408 conn->login_mtask->data = data; 1412 conn->login_mtask->data = conn->data = data;
1409 1413
1410 init_timer(&conn->tmabort_timer); 1414 init_timer(&conn->tmabort_timer);
1411 mutex_init(&conn->xmitmutex); 1415 mutex_init(&conn->xmitmutex);
@@ -1477,7 +1481,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
1477 } 1481 }
1478 1482
1479 spin_lock_bh(&session->lock); 1483 spin_lock_bh(&session->lock);
1480 kfree(conn->login_mtask->data); 1484 kfree(conn->data);
1481 __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 1485 __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
1482 sizeof(void*)); 1486 sizeof(void*));
1483 list_del(&conn->item); 1487 list_del(&conn->item);
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 3f69f7e58f89..41904f611d12 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -135,6 +135,14 @@ struct iscsi_conn {
135 int id; /* CID */ 135 int id; /* CID */
136 struct list_head item; /* maintains list of conns */ 136 struct list_head item; /* maintains list of conns */
137 int c_stage; /* connection state */ 137 int c_stage; /* connection state */
138 /*
139 * Preallocated buffer for pdus that have data but do not
140 * originate from scsi-ml. We never have two pdus using the
141 * buffer at the same time. It is only allocated to
142 * the default max recv size because the pdus we support
143 * should always fit in this buffer
144 */
145 char *data;
138 struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */ 146 struct iscsi_mgmt_task *login_mtask; /* mtask used for login/text */
139 struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */ 147 struct iscsi_mgmt_task *mtask; /* xmit mtask in progress */
140 struct iscsi_cmd_task *ctask; /* xmit ctask in progress */ 148 struct iscsi_cmd_task *ctask; /* xmit ctask in progress */