diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2006-01-14 03:05:47 +0300 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2006-01-14 19:55:18 +0300 |
commit | 7cae5159dd2623300cf9820865bfbf6dcdb7c1b9 (patch) | |
tree | 68cd331b75515e90f79f4902de0620b293adcfd4 /drivers/scsi | |
parent | 56851698c23430f0f291d6e50da344e6b414f3b9 (diff) | |
download | linux-7cae5159dd2623300cf9820865bfbf6dcdb7c1b9.tar.xz |
[SCSI] iscsi: add high mem support
From Mike Christie <michaelc@cs.wisc.edu> and FUJITA Tomonori <tomof@acm.org>:
We cannot use page_address becuase some pages could be highmem.
Instead, we can use sock_no_sendpage which does kmap for us.
Signed-off-by: Alex Aizman <itn780@yahoo.com>
Signed-off-by: Dmitry Yusupov <dmitry_yus@yahoo.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 84 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.h | 2 |
2 files changed, 31 insertions, 55 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 5e8b3135574c..0acc4b235d9b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -87,35 +87,32 @@ iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) { sg_init_one(&ibuf->sg, (u8 *)vbuf, size); ibuf->sent = 0; + ibuf->use_sendmsg = 0; } static inline void iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) { - ibuf->sg.page = (void*)vbuf; - ibuf->sg.offset = (unsigned int)-1; + ibuf->sg.page = virt_to_page(vbuf); + ibuf->sg.offset = offset_in_page(vbuf); ibuf->sg.length = size; ibuf->sent = 0; -} - -static inline void* -iscsi_buf_iov_base(struct iscsi_buf *ibuf) -{ - return (char*)ibuf->sg.page + ibuf->sent; + ibuf->use_sendmsg = 1; } static inline void iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) { + ibuf->sg.page = sg->page; + ibuf->sg.offset = sg->offset; + ibuf->sg.length = sg->length; /* * Fastpath: sg element fits into single page */ - if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) { - ibuf->sg.page = sg->page; - ibuf->sg.offset = sg->offset; - ibuf->sg.length = sg->length; - } else - iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length); + if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) + ibuf->use_sendmsg = 0; + else + ibuf->use_sendmsg = 1; ibuf->sent = 0; } @@ -1311,35 +1308,25 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn) * @buf: buffer to write from * @size: actual size to write * @flags: socket's flags - * - * Notes: - * depending on buffer will use tcp_sendpage() or tcp_sendmsg(). - * buf->sg.offset == -1 tells us that buffer is non S/G and forces - * to use tcp_sendmsg(). */ static inline int iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) { struct socket *sk = conn->sock; - int res; - - if ((int)buf->sg.offset >= 0) { - int offset = buf->sg.offset + buf->sent; - - res = conn->sendpage(sk, buf->sg.page, offset, size, flags); - } else { - struct msghdr msg; - - buf->iov.iov_base = iscsi_buf_iov_base(buf); - buf->iov.iov_len = size; - - memset(&msg, 0, sizeof(struct msghdr)); - - /* tcp_sendmsg */ - res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size); - } + int offset = buf->sg.offset + buf->sent; - return res; + /* + * if we got use_sg=0 or are sending something we kmallocd + * then we did not have to do kmap (kmap returns page_address) + * + * if we got use_sg > 0, but had to drop down, we do not + * set clustering so this should only happen for that + * slab case. + */ + if (buf->use_sendmsg) + return sock_no_sendpage(sk, buf->sg.page, offset, size, flags); + else + return conn->sendpage(sk, buf->sg.page, offset, size, flags); } /** @@ -1431,19 +1418,6 @@ iscsi_data_digest_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ctask->digest_count = 4; } -static inline void -iscsi_buf_data_digest_update(struct iscsi_conn *conn, struct iscsi_buf *buf) -{ - struct scatterlist sg; - - if (buf->sg.offset != -1) - crypto_digest_update(conn->data_tx_tfm, &buf->sg, 1); - else { - sg_init_one(&sg, (char *)buf->sg.page, buf->sg.length); - crypto_digest_update(conn->data_tx_tfm, &sg, 1); - } -} - static inline int iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_buf *buf, uint32_t *digest, int final) @@ -1806,7 +1780,8 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return -EAGAIN; } if (conn->datadgst_en) - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, + &ctask->sendbuf.sg, 1); if (!ctask->imm_count) break; @@ -1891,7 +1866,8 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) * so pass it */ if (conn->datadgst_en && ctask->sent - start > 0) - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, + &ctask->sendbuf.sg, 1); if (!ctask->data_count) break; @@ -1969,7 +1945,7 @@ solicit_again: BUG_ON(r2t->data_count < 0); if (conn->datadgst_en) - iscsi_buf_data_digest_update(conn, &r2t->sendbuf); + crypto_digest_update(conn->data_tx_tfm, &r2t->sendbuf.sg, 1); if (r2t->data_count) { BUG_ON(ctask->sc->use_sg == 0); @@ -2051,7 +2027,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (conn->datadgst_en) { - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, &ctask->sendbuf.sg, 1); /* imm data? */ if (!dtask) { if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf, diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index c8bb5b0bcb4b..f95e61b76f70 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -242,8 +242,8 @@ struct iscsi_session { struct iscsi_buf { struct scatterlist sg; - struct kvec iov; unsigned int sent; + char use_sendmsg; }; struct iscsi_data_task { |