Commit e5a4b0bb authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 17836394
...@@ -1326,20 +1326,18 @@ static int iscsit_do_rx_data( ...@@ -1326,20 +1326,18 @@ 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",
......
...@@ -2651,17 +2651,10 @@ int skb_copy_datagram_iter(const struct sk_buff *from, int offset, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, ...@@ -794,7 +778,7 @@ int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment