[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>
This commit is contained in:
committed by
James Bottomley
parent
56851698c2
commit
7cae5159dd
@@ -87,35 +87,32 @@ iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size)
|
|||||||
{
|
{
|
||||||
sg_init_one(&ibuf->sg, (u8 *)vbuf, size);
|
sg_init_one(&ibuf->sg, (u8 *)vbuf, size);
|
||||||
ibuf->sent = 0;
|
ibuf->sent = 0;
|
||||||
|
ibuf->use_sendmsg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
|
iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
|
||||||
{
|
{
|
||||||
ibuf->sg.page = (void*)vbuf;
|
ibuf->sg.page = virt_to_page(vbuf);
|
||||||
ibuf->sg.offset = (unsigned int)-1;
|
ibuf->sg.offset = offset_in_page(vbuf);
|
||||||
ibuf->sg.length = size;
|
ibuf->sg.length = size;
|
||||||
ibuf->sent = 0;
|
ibuf->sent = 0;
|
||||||
}
|
ibuf->use_sendmsg = 1;
|
||||||
|
|
||||||
static inline void*
|
|
||||||
iscsi_buf_iov_base(struct iscsi_buf *ibuf)
|
|
||||||
{
|
|
||||||
return (char*)ibuf->sg.page + ibuf->sent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
|
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
|
* Fastpath: sg element fits into single page
|
||||||
*/
|
*/
|
||||||
if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) {
|
if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2)
|
||||||
ibuf->sg.page = sg->page;
|
ibuf->use_sendmsg = 0;
|
||||||
ibuf->sg.offset = sg->offset;
|
else
|
||||||
ibuf->sg.length = sg->length;
|
ibuf->use_sendmsg = 1;
|
||||||
} else
|
|
||||||
iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length);
|
|
||||||
ibuf->sent = 0;
|
ibuf->sent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1311,35 +1308,25 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn)
|
|||||||
* @buf: buffer to write from
|
* @buf: buffer to write from
|
||||||
* @size: actual size to write
|
* @size: actual size to write
|
||||||
* @flags: socket's flags
|
* @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
|
static inline int
|
||||||
iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
|
iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
|
||||||
{
|
{
|
||||||
struct socket *sk = conn->sock;
|
struct socket *sk = conn->sock;
|
||||||
int res;
|
int offset = buf->sg.offset + buf->sent;
|
||||||
|
|
||||||
if ((int)buf->sg.offset >= 0) {
|
/*
|
||||||
int offset = buf->sg.offset + buf->sent;
|
* if we got use_sg=0 or are sending something we kmallocd
|
||||||
|
* then we did not have to do kmap (kmap returns page_address)
|
||||||
res = conn->sendpage(sk, buf->sg.page, offset, size, flags);
|
*
|
||||||
} else {
|
* if we got use_sg > 0, but had to drop down, we do not
|
||||||
struct msghdr msg;
|
* set clustering so this should only happen for that
|
||||||
|
* slab case.
|
||||||
buf->iov.iov_base = iscsi_buf_iov_base(buf);
|
*/
|
||||||
buf->iov.iov_len = size;
|
if (buf->use_sendmsg)
|
||||||
|
return sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
|
||||||
memset(&msg, 0, sizeof(struct msghdr));
|
else
|
||||||
|
return conn->sendpage(sk, buf->sg.page, offset, size, flags);
|
||||||
/* tcp_sendmsg */
|
|
||||||
res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1431,19 +1418,6 @@ iscsi_data_digest_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
|
|||||||
ctask->digest_count = 4;
|
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
|
static inline int
|
||||||
iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
|
iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
|
||||||
struct iscsi_buf *buf, uint32_t *digest, int final)
|
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;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (conn->datadgst_en)
|
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)
|
if (!ctask->imm_count)
|
||||||
break;
|
break;
|
||||||
@@ -1891,7 +1866,8 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
|
|||||||
* so pass it
|
* so pass it
|
||||||
*/
|
*/
|
||||||
if (conn->datadgst_en && ctask->sent - start > 0)
|
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)
|
if (!ctask->data_count)
|
||||||
break;
|
break;
|
||||||
@@ -1969,7 +1945,7 @@ solicit_again:
|
|||||||
|
|
||||||
BUG_ON(r2t->data_count < 0);
|
BUG_ON(r2t->data_count < 0);
|
||||||
if (conn->datadgst_en)
|
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) {
|
if (r2t->data_count) {
|
||||||
BUG_ON(ctask->sc->use_sg == 0);
|
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) {
|
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? */
|
/* imm data? */
|
||||||
if (!dtask) {
|
if (!dtask) {
|
||||||
if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf,
|
if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf,
|
||||||
|
@@ -242,8 +242,8 @@ struct iscsi_session {
|
|||||||
|
|
||||||
struct iscsi_buf {
|
struct iscsi_buf {
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
struct kvec iov;
|
|
||||||
unsigned int sent;
|
unsigned int sent;
|
||||||
|
char use_sendmsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iscsi_data_task {
|
struct iscsi_data_task {
|
||||||
|
Reference in New Issue
Block a user