switch memcpy_to_msg() and skb_copy{,_and_csum}_datagram_msg() to primitives
... making both non-draining. That means that tcp_recvmsg() becomes non-draining. And _that_ would break iscsit_do_rx_data() unless we a) make sure tcp_recvmsg() is uniformly non-draining (it is) b) make sure it copes with arbitrary (including shifted) iov_iter (it does, all it uses is iov_iter primitives) c) make iscsit_do_rx_data() initialize ->msg_iter only once. Fortunately, (c) is doable with minimal work and we are rid of one the two places where kernel send/recvmsg users would be unhappy with non-draining behaviour. Actually, that makes all but one of ->recvmsg() instances iov_iter-clean. The exception is skcipher_recvmsg() and it also isn't hard to convert to primitives (iov_iter_get_pages() is needed there). That'll wait a bit - there's some interplay with ->sendmsg() path for that one. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
17836394e5
commit
e5a4b0bb80
|
@ -1326,21 +1326,19 @@ static int iscsit_do_rx_data(
|
||||||
struct iscsi_conn *conn,
|
struct iscsi_conn *conn,
|
||||||
struct iscsi_data_count *count)
|
struct iscsi_data_count *count)
|
||||||
{
|
{
|
||||||
int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len;
|
int data = count->data_length, rx_loop = 0, total_rx = 0;
|
||||||
struct kvec *iov_p;
|
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
|
|
||||||
if (!conn || !conn->sock || !conn->conn_ops)
|
if (!conn || !conn->sock || !conn->conn_ops)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(&msg, 0, sizeof(struct msghdr));
|
memset(&msg, 0, sizeof(struct msghdr));
|
||||||
|
iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC,
|
||||||
iov_p = count->iov;
|
count->iov, count->iov_count, data);
|
||||||
iov_len = count->iov_count;
|
|
||||||
|
|
||||||
while (total_rx < data) {
|
while (total_rx < data) {
|
||||||
rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len,
|
rx_loop = sock_recvmsg(conn->sock, &msg,
|
||||||
(data - total_rx), MSG_WAITALL);
|
(data - total_rx), MSG_WAITALL);
|
||||||
if (rx_loop <= 0) {
|
if (rx_loop <= 0) {
|
||||||
pr_debug("rx_loop: %d total_rx: %d\n",
|
pr_debug("rx_loop: %d total_rx: %d\n",
|
||||||
rx_loop, total_rx);
|
rx_loop, total_rx);
|
||||||
|
|
|
@ -2651,17 +2651,10 @@ int skb_copy_datagram_iter(const struct sk_buff *from, int offset,
|
||||||
static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
|
static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset,
|
||||||
struct msghdr *msg, int size)
|
struct msghdr *msg, int size)
|
||||||
{
|
{
|
||||||
/* XXX: stripping const */
|
return skb_copy_datagram_iter(from, offset, &msg->msg_iter, size);
|
||||||
return skb_copy_datagram_iovec(from, offset, (struct iovec *)msg->msg_iter.iov, size);
|
|
||||||
}
|
|
||||||
int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen,
|
|
||||||
struct iovec *iov);
|
|
||||||
static inline int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
|
|
||||||
struct msghdr *msg)
|
|
||||||
{
|
|
||||||
/* XXX: stripping const */
|
|
||||||
return skb_copy_and_csum_datagram_iovec(skb, hlen, (struct iovec *)msg->msg_iter.iov);
|
|
||||||
}
|
}
|
||||||
|
int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen,
|
||||||
|
struct msghdr *msg);
|
||||||
int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
|
int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
|
||||||
struct iov_iter *from, int len);
|
struct iov_iter *from, int len);
|
||||||
int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
|
int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
|
||||||
|
@ -2697,8 +2690,7 @@ static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len)
|
||||||
|
|
||||||
static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
|
static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
|
||||||
{
|
{
|
||||||
/* XXX: stripping const */
|
return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
|
||||||
return memcpy_toiovec((struct iovec *)msg->msg_iter.iov, data, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct skb_checksum_ops {
|
struct skb_checksum_ops {
|
||||||
|
|
|
@ -615,27 +615,25 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
|
||||||
EXPORT_SYMBOL(zerocopy_sg_from_iter);
|
EXPORT_SYMBOL(zerocopy_sg_from_iter);
|
||||||
|
|
||||||
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
||||||
u8 __user *to, int len,
|
struct iov_iter *to, int len,
|
||||||
__wsum *csump)
|
__wsum *csump)
|
||||||
{
|
{
|
||||||
int start = skb_headlen(skb);
|
int start = skb_headlen(skb);
|
||||||
int i, copy = start - offset;
|
int i, copy = start - offset;
|
||||||
struct sk_buff *frag_iter;
|
struct sk_buff *frag_iter;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
int n;
|
||||||
|
|
||||||
/* Copy header. */
|
/* Copy header. */
|
||||||
if (copy > 0) {
|
if (copy > 0) {
|
||||||
int err = 0;
|
|
||||||
if (copy > len)
|
if (copy > len)
|
||||||
copy = len;
|
copy = len;
|
||||||
*csump = csum_and_copy_to_user(skb->data + offset, to, copy,
|
n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to);
|
||||||
*csump, &err);
|
if (n != copy)
|
||||||
if (err)
|
|
||||||
goto fault;
|
goto fault;
|
||||||
if ((len -= copy) == 0)
|
if ((len -= copy) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
offset += copy;
|
offset += copy;
|
||||||
to += copy;
|
|
||||||
pos = copy;
|
pos = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,26 +645,22 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
||||||
|
|
||||||
end = start + skb_frag_size(frag);
|
end = start + skb_frag_size(frag);
|
||||||
if ((copy = end - offset) > 0) {
|
if ((copy = end - offset) > 0) {
|
||||||
__wsum csum2;
|
__wsum csum2 = 0;
|
||||||
int err = 0;
|
|
||||||
u8 *vaddr;
|
|
||||||
struct page *page = skb_frag_page(frag);
|
struct page *page = skb_frag_page(frag);
|
||||||
|
u8 *vaddr = kmap(page);
|
||||||
|
|
||||||
if (copy > len)
|
if (copy > len)
|
||||||
copy = len;
|
copy = len;
|
||||||
vaddr = kmap(page);
|
n = csum_and_copy_to_iter(vaddr + frag->page_offset +
|
||||||
csum2 = csum_and_copy_to_user(vaddr +
|
offset - start, copy,
|
||||||
frag->page_offset +
|
&csum2, to);
|
||||||
offset - start,
|
|
||||||
to, copy, 0, &err);
|
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
if (err)
|
if (n != copy)
|
||||||
goto fault;
|
goto fault;
|
||||||
*csump = csum_block_add(*csump, csum2, pos);
|
*csump = csum_block_add(*csump, csum2, pos);
|
||||||
if (!(len -= copy))
|
if (!(len -= copy))
|
||||||
return 0;
|
return 0;
|
||||||
offset += copy;
|
offset += copy;
|
||||||
to += copy;
|
|
||||||
pos += copy;
|
pos += copy;
|
||||||
}
|
}
|
||||||
start = end;
|
start = end;
|
||||||
|
@ -691,7 +685,6 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
||||||
if ((len -= copy) == 0)
|
if ((len -= copy) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
offset += copy;
|
offset += copy;
|
||||||
to += copy;
|
|
||||||
pos += copy;
|
pos += copy;
|
||||||
}
|
}
|
||||||
start = end;
|
start = end;
|
||||||
|
@ -744,20 +737,19 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
|
||||||
EXPORT_SYMBOL(__skb_checksum_complete);
|
EXPORT_SYMBOL(__skb_checksum_complete);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* skb_copy_and_csum_datagram_iovec - Copy and checksum skb to user iovec.
|
* skb_copy_and_csum_datagram_msg - Copy and checksum skb to user iovec.
|
||||||
* @skb: skbuff
|
* @skb: skbuff
|
||||||
* @hlen: hardware length
|
* @hlen: hardware length
|
||||||
* @iov: io vector
|
* @msg: destination
|
||||||
*
|
*
|
||||||
* Caller _must_ check that skb will fit to this iovec.
|
* Caller _must_ check that skb will fit to this iovec.
|
||||||
*
|
*
|
||||||
* Returns: 0 - success.
|
* Returns: 0 - success.
|
||||||
* -EINVAL - checksum failure.
|
* -EINVAL - checksum failure.
|
||||||
* -EFAULT - fault during copy. Beware, in this case iovec
|
* -EFAULT - fault during copy.
|
||||||
* can be modified!
|
|
||||||
*/
|
*/
|
||||||
int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
|
int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
|
||||||
int hlen, struct iovec *iov)
|
int hlen, struct msghdr *msg)
|
||||||
{
|
{
|
||||||
__wsum csum;
|
__wsum csum;
|
||||||
int chunk = skb->len - hlen;
|
int chunk = skb->len - hlen;
|
||||||
|
@ -765,28 +757,20 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
|
||||||
if (!chunk)
|
if (!chunk)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Skip filled elements.
|
if (iov_iter_count(&msg->msg_iter) < chunk) {
|
||||||
* Pretty silly, look at memcpy_toiovec, though 8)
|
|
||||||
*/
|
|
||||||
while (!iov->iov_len)
|
|
||||||
iov++;
|
|
||||||
|
|
||||||
if (iov->iov_len < chunk) {
|
|
||||||
if (__skb_checksum_complete(skb))
|
if (__skb_checksum_complete(skb))
|
||||||
goto csum_error;
|
goto csum_error;
|
||||||
if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
|
if (skb_copy_datagram_msg(skb, hlen, msg, chunk))
|
||||||
goto fault;
|
goto fault;
|
||||||
} else {
|
} else {
|
||||||
csum = csum_partial(skb->data, hlen, skb->csum);
|
csum = csum_partial(skb->data, hlen, skb->csum);
|
||||||
if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base,
|
if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
|
||||||
chunk, &csum))
|
chunk, &csum))
|
||||||
goto fault;
|
goto fault;
|
||||||
if (csum_fold(csum))
|
if (csum_fold(csum))
|
||||||
goto csum_error;
|
goto csum_error;
|
||||||
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
||||||
netdev_rx_csum_fault(skb->dev);
|
netdev_rx_csum_fault(skb->dev);
|
||||||
iov->iov_len -= chunk;
|
|
||||||
iov->iov_base += chunk;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
csum_error:
|
csum_error:
|
||||||
|
@ -794,7 +778,7 @@ csum_error:
|
||||||
fault:
|
fault:
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
|
EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* datagram_poll - generic datagram poll
|
* datagram_poll - generic datagram poll
|
||||||
|
|
Loading…
Reference in New Issue