* [PATCH v3 01/18] netlink: make the check for "send from tx_ring" deterministic
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
As it is, zero msg_iovlen means that the first iovec in the kernel
array of iovecs is left uninitialized, so checking if its ->iov_base
is NULL is random. Since the real users of that thing are doing
sendto(fd, NULL, 0, ...), they are getting msg_iovlen = 1 and
msg_iov[0] = {NULL, 0}, which is what this test is trying to catch.
As suggested by davem, let's just check that msg_iovlen was 1 and
msg_iov[0].iov_base was NULL - _that_ is well-defined and it catches
what we want to catch.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/netlink/af_netlink.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a36777b..4fd38a6 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2298,7 +2298,12 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto out;
}
+ /* It's a really convoluted way for userland to ask for mmaped
+ * sendmsg(), but that's what we've got...
+ */
if (netlink_tx_is_mmaped(sk) &&
+ msg->msg_iter.type == ITER_IOVEC &&
+ msg->msg_iter.nr_segs == 1 &&
msg->msg_iter.iov->iov_base == NULL) {
err = netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group,
&scm);
--
2.1.4
^ permalink raw reply related
* [PATCH v3 03/18] ipv6: rawv6_send_hdrinc(): pass msghdr
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Switch from passing msg->iov_iter.iov to passing msg itself
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/ipv6/raw.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index ee25631..0dbb328 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -609,7 +609,7 @@ out:
return err;
}
-static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
+static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
struct flowi6 *fl6, struct dst_entry **dstp,
unsigned int flags)
{
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
skb->ip_summed = CHECKSUM_NONE;
skb->transport_header = skb->network_header;
- err = memcpy_fromiovecend((void *)iph, from, 0, length);
+ err = memcpy_fromiovecend((void *)iph, msg->msg_iter.iov, 0, length);
if (err)
goto error_fault;
@@ -886,8 +886,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
back_from_confirm:
if (inet->hdrincl)
- /* XXX: stripping const */
- err = rawv6_send_hdrinc(sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags);
+ err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags);
else {
lock_sock(sk);
err = ip6_append_data(sk, raw6_getfrag, &rfv,
--
2.1.4
^ permalink raw reply related
* [PATCH v3 02/18] ipv4: raw_send_hdrinc(): pass msghdr
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Switch from passing msg->iov_iter.iov to passing msg itself
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/ipv4/raw.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 0bb68df..2c9d252 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -337,7 +337,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
}
static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
- void *from, size_t length,
+ struct msghdr *msg, size_t length,
struct rtable **rtp,
unsigned int flags)
{
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
skb->transport_header = skb->network_header;
err = -EFAULT;
- if (memcpy_fromiovecend((void *)iph, from, 0, length))
+ if (memcpy_fromiovecend((void *)iph, msg->msg_iter.iov, 0, length))
goto error_free;
iphlen = iph->ihl * 4;
@@ -625,8 +625,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
back_from_confirm:
if (inet->hdrincl)
- /* XXX: stripping const */
- err = raw_send_hdrinc(sk, &fl4, (struct iovec *)msg->msg_iter.iov, len,
+ err = raw_send_hdrinc(sk, &fl4, msg, len,
&rt, msg->msg_flags);
else {
--
2.1.4
^ permalink raw reply related
* [PATCH v3 04/18] vmci: propagate msghdr all way down to __qp_memcpy_to_queue()
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Switch from passing msg->iov_iter.iov to passing msg itself
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
drivers/misc/vmw_vmci/vmci_queue_pair.c | 16 ++++++++--------
include/linux/vmw_vmci_api.h | 2 +-
net/vmw_vsock/vmci_transport.c | 3 +--
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 7aaaf51..35f19a6 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
to_copy = size - bytes_copied;
if (is_iovec) {
- struct iovec *iov = (struct iovec *)src;
+ struct msghdr *msg = (struct msghdr *)src;
int err;
/* The iovec will track bytes_copied internally. */
- err = memcpy_fromiovec((u8 *)va + page_offset,
- iov, to_copy);
+ err = memcpy_from_msg((u8 *)va + page_offset,
+ msg, to_copy);
if (err != 0) {
if (kernel_if->host)
kunmap(kernel_if->u.h.page[page_index]);
@@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest,
*/
static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,
u64 queue_offset,
- const void *src,
+ const void *msg,
size_t src_offset, size_t size)
{
@@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,
* We ignore src_offset because src is really a struct iovec * and will
* maintain offset internally.
*/
- return __qp_memcpy_to_queue(queue, queue_offset, src, size, true);
+ return __qp_memcpy_to_queue(queue, queue_offset, msg, size, true);
}
/*
@@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek);
* of bytes enqueued or < 0 on error.
*/
ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
- void *iov,
+ struct msghdr *msg,
size_t iov_size,
int buf_type)
{
ssize_t result;
- if (!qpair || !iov)
+ if (!qpair)
return VMCI_ERROR_INVALID_ARGS;
qp_lock(qpair);
@@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
result = qp_enqueue_locked(qpair->produce_q,
qpair->consume_q,
qpair->produce_q_size,
- iov, iov_size,
+ msg, iov_size,
qp_memcpy_to_queue_iov);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
diff --git a/include/linux/vmw_vmci_api.h b/include/linux/vmw_vmci_api.h
index 5691f75..63df3a2a 100644
--- a/include/linux/vmw_vmci_api.h
+++ b/include/linux/vmw_vmci_api.h
@@ -74,7 +74,7 @@ ssize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
ssize_t vmci_qpair_peek(struct vmci_qp *qpair, void *buf, size_t buf_size,
int mode);
ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
- void *iov, size_t iov_size, int mode);
+ struct msghdr *msg, size_t iov_size, int mode);
ssize_t vmci_qpair_dequev(struct vmci_qp *qpair,
struct msghdr *msg, size_t iov_size, int mode);
ssize_t vmci_qpair_peekv(struct vmci_qp *qpair, struct msghdr *msg, size_t iov_size,
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 02d2e52..7f32550 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -1850,8 +1850,7 @@ static ssize_t vmci_transport_stream_enqueue(
struct msghdr *msg,
size_t len)
{
- /* XXX: stripping const */
- return vmci_qpair_enquev(vmci_trans(vsk)->qpair, (struct iovec *)msg->msg_iter.iov, len, 0);
+ return vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg, len, 0);
}
static s64 vmci_transport_stream_has_data(struct vsock_sock *vsk)
--
2.1.4
^ permalink raw reply related
* [PATCH v3 06/18] rxrpc: make the users of rxrpc_kernel_send_data() set kvec-backed msg_iter properly
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Use iov_iter_kvec() there, get rid of set_fs() games - now that
rxrpc_send_data() uses iov_iter primitives, it'll handle ITER_KVEC just
fine.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/afs/rxrpc.c | 14 +++++++-------
net/rxrpc/ar-output.c | 3 ---
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 06e14bf..dbc732e 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -306,8 +306,8 @@ static int afs_send_pages(struct afs_call *call, struct msghdr *msg,
_debug("- range %u-%u%s",
offset, to, msg->msg_flags ? " [more]" : "");
- iov_iter_init(&msg->msg_iter, WRITE,
- (struct iovec *) iov, 1, to - offset);
+ iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC,
+ iov, 1, to - offset);
/* have to change the state *before* sending the last
* packet as RxRPC might give us the reply before it
@@ -384,7 +384,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_init(&msg.msg_iter, WRITE, (struct iovec *)iov, 1,
+ iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1,
call->request_size);
msg.msg_control = NULL;
msg.msg_controllen = 0;
@@ -770,7 +770,7 @@ static int afs_deliver_cm_op_id(struct afs_call *call, struct sk_buff *skb,
void afs_send_empty_reply(struct afs_call *call)
{
struct msghdr msg;
- struct iovec iov[1];
+ struct kvec iov[1];
_enter("");
@@ -778,7 +778,7 @@ void afs_send_empty_reply(struct afs_call *call)
iov[0].iov_len = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_init(&msg.msg_iter, WRITE, iov, 0, 0); /* WTF? */
+ iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 0, 0); /* WTF? */
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
@@ -805,7 +805,7 @@ void afs_send_empty_reply(struct afs_call *call)
void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
{
struct msghdr msg;
- struct iovec iov[1];
+ struct kvec iov[1];
int n;
_enter("");
@@ -814,7 +814,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
iov[0].iov_len = len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
- iov_iter_init(&msg.msg_iter, WRITE, iov, 1, len);
+ iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, iov, 1, len);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c
index 963a5b9..8331c95 100644
--- a/net/rxrpc/ar-output.c
+++ b/net/rxrpc/ar-output.c
@@ -232,10 +232,7 @@ int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,
call->state != RXRPC_CALL_SERVER_SEND_REPLY) {
ret = -EPROTO; /* request phase complete for this client call */
} else {
- mm_segment_t oldfs = get_fs();
- set_fs(KERNEL_DS);
ret = rxrpc_send_data(NULL, call->socket, call, msg, len);
- set_fs(oldfs);
}
release_sock(&call->socket->sk);
--
2.1.4
^ permalink raw reply related
* [PATCH v3 05/18] rxrpc: switch rxrpc_send_data() to iov_iter primitives
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Convert skb_add_data() to iov_iter; allows to get rid of the explicit
messing with iovec in its only caller - skb_add_data() will keep advancing
->msg_iter for us, so there's no need to similate that manually.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/skbuff.h | 11 +++++------
net/rxrpc/ar-output.c | 43 ++++++++++---------------------------------
2 files changed, 15 insertions(+), 39 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 85ab7d7..9a8bafe 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2484,19 +2484,18 @@ static inline int skb_put_padto(struct sk_buff *skb, unsigned int len)
}
static inline int skb_add_data(struct sk_buff *skb,
- char __user *from, int copy)
+ struct iov_iter *from, int copy)
{
const int off = skb->len;
if (skb->ip_summed == CHECKSUM_NONE) {
- int err = 0;
- __wsum csum = csum_and_copy_from_user(from, skb_put(skb, copy),
- copy, 0, &err);
- if (!err) {
+ __wsum csum = 0;
+ if (csum_and_copy_from_iter(skb_put(skb, copy), copy,
+ &csum, from) == copy) {
skb->csum = csum_block_add(skb->csum, csum, off);
return 0;
}
- } else if (!copy_from_user(skb_put(skb, copy), from, copy))
+ } else if (copy_from_iter(skb_put(skb, copy), copy, from) == copy)
return 0;
__skb_trim(skb, off);
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c
index e1a9373..963a5b9 100644
--- a/net/rxrpc/ar-output.c
+++ b/net/rxrpc/ar-output.c
@@ -529,13 +529,11 @@ static int rxrpc_send_data(struct kiocb *iocb,
struct msghdr *msg, size_t len)
{
struct rxrpc_skb_priv *sp;
- unsigned char __user *from;
struct sk_buff *skb;
- const struct iovec *iov;
struct sock *sk = &rx->sk;
long timeo;
bool more;
- int ret, ioc, segment, copied;
+ int ret, copied;
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
@@ -545,25 +543,17 @@ static int rxrpc_send_data(struct kiocb *iocb,
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
return -EPIPE;
- iov = msg->msg_iter.iov;
- ioc = msg->msg_iter.nr_segs - 1;
- from = iov->iov_base;
- segment = iov->iov_len;
- iov++;
more = msg->msg_flags & MSG_MORE;
skb = call->tx_pending;
call->tx_pending = NULL;
copied = 0;
- do {
+ if (len > iov_iter_count(&msg->msg_iter))
+ len = iov_iter_count(&msg->msg_iter);
+ while (len) {
int copy;
- if (segment > len)
- segment = len;
-
- _debug("SEGMENT %d @%p", segment, from);
-
if (!skb) {
size_t size, chunk, max, space;
@@ -631,13 +621,13 @@ static int rxrpc_send_data(struct kiocb *iocb,
/* append next segment of data to the current buffer */
copy = skb_tailroom(skb);
ASSERTCMP(copy, >, 0);
- if (copy > segment)
- copy = segment;
+ if (copy > len)
+ copy = len;
if (copy > sp->remain)
copy = sp->remain;
_debug("add");
- ret = skb_add_data(skb, from, copy);
+ ret = skb_add_data(skb, &msg->msg_iter, copy);
_debug("added");
if (ret < 0)
goto efault;
@@ -646,18 +636,6 @@ static int rxrpc_send_data(struct kiocb *iocb,
copied += copy;
len -= copy;
- segment -= copy;
- from += copy;
- while (segment == 0 && ioc > 0) {
- from = iov->iov_base;
- segment = iov->iov_len;
- iov++;
- ioc--;
- }
- if (len == 0) {
- segment = 0;
- ioc = 0;
- }
/* check for the far side aborting the call or a network error
* occurring */
@@ -665,7 +643,7 @@ static int rxrpc_send_data(struct kiocb *iocb,
goto call_aborted;
/* add the packet to the send queue if it's now full */
- if (sp->remain <= 0 || (segment == 0 && !more)) {
+ if (sp->remain <= 0 || (!len && !more)) {
struct rxrpc_connection *conn = call->conn;
uint32_t seq;
size_t pad;
@@ -711,11 +689,10 @@ static int rxrpc_send_data(struct kiocb *iocb,
memcpy(skb->head, &sp->hdr,
sizeof(struct rxrpc_header));
- rxrpc_queue_packet(call, skb, segment == 0 && !more);
+ rxrpc_queue_packet(call, skb, !iov_iter_count(&msg->msg_iter) && !more);
skb = NULL;
}
-
- } while (segment > 0);
+ }
success:
ret = copied;
--
2.1.4
^ permalink raw reply related
* [PATCH v3 07/18] ip: stash a pointer to msghdr in struct ping_fakehdr
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
... instead of storing its ->mgs_iter.iov there
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/net/ping.h | 2 +-
net/ipv4/ping.c | 7 +++----
net/ipv6/ping.c | 3 +--
3 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/include/net/ping.h b/include/net/ping.h
index f074060..cc16d41 100644
--- a/include/net/ping.h
+++ b/include/net/ping.h
@@ -59,7 +59,7 @@ extern struct pingv6_ops pingv6_ops;
struct pingfakehdr {
struct icmphdr icmph;
- struct iovec *iov;
+ struct msghdr *msg;
sa_family_t family;
__wsum wcheck;
};
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 2a3720f..9e15ba7 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -602,14 +602,14 @@ int ping_getfrag(void *from, char *to,
if (fraglen < sizeof(struct icmphdr))
BUG();
if (csum_partial_copy_fromiovecend(to + sizeof(struct icmphdr),
- pfh->iov, 0, fraglen - sizeof(struct icmphdr),
+ pfh->msg->msg_iter.iov, 0, fraglen - sizeof(struct icmphdr),
&pfh->wcheck))
return -EFAULT;
} else if (offset < sizeof(struct icmphdr)) {
BUG();
} else {
if (csum_partial_copy_fromiovecend
- (to, pfh->iov, offset - sizeof(struct icmphdr),
+ (to, pfh->msg->msg_iter.iov, offset - sizeof(struct icmphdr),
fraglen, &pfh->wcheck))
return -EFAULT;
}
@@ -811,8 +811,7 @@ back_from_confirm:
pfh.icmph.checksum = 0;
pfh.icmph.un.echo.id = inet->inet_sport;
pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence;
- /* XXX: stripping const */
- pfh.iov = (struct iovec *)msg->msg_iter.iov;
+ pfh.msg = msg;
pfh.wcheck = 0;
pfh.family = AF_INET;
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 2d31483..bd46f73 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -163,8 +163,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
pfh.icmph.checksum = 0;
pfh.icmph.un.echo.id = inet->inet_sport;
pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence;
- /* XXX: stripping const */
- pfh.iov = (struct iovec *)msg->msg_iter.iov;
+ pfh.msg = msg;
pfh.wcheck = 0;
pfh.family = AF_INET6;
--
2.1.4
^ permalink raw reply related
* [PATCH v3 09/18] net: switch memcpy_fromiovec()/memcpy_fromiovecend() users to copy_from_iter()
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
That takes care of the majority of ->sendmsg() instances - most of them
via memcpy_to_msg() or assorted getfrag() callbacks. One place where we
still keep memcpy_fromiovecend() is tipc - there we potentially read the
same data over and over; separate patch, that...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/skbuff.h | 3 +--
include/net/udplite.h | 3 +--
net/ipv4/ip_output.c | 6 ++----
net/ipv4/ping.c | 14 +++++++-------
net/ipv4/raw.c | 2 +-
net/ipv4/tcp_input.c | 2 +-
net/ipv6/raw.c | 2 +-
7 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9a8bafe..b349c96 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2692,8 +2692,7 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci);
static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len)
{
- /* XXX: stripping const */
- return memcpy_fromiovec(data, (struct iovec *)msg->msg_iter.iov, len);
+ return copy_from_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT;
}
static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len)
diff --git a/include/net/udplite.h b/include/net/udplite.h
index ae7c8d1..8076193 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -20,8 +20,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
struct msghdr *msg = from;
- /* XXX: stripping const */
- return memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len);
+ return copy_from_iter(to, len, &msg->msg_iter) != len ? -EFAULT : 0;
}
/* Designate sk as UDP-Lite socket */
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b50861b2..f998bc8 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -755,13 +755,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk
struct msghdr *msg = from;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- /* XXX: stripping const */
- if (memcpy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len) < 0)
+ if (copy_from_iter(to, len, &msg->msg_iter) != len)
return -EFAULT;
} else {
__wsum csum = 0;
- /* XXX: stripping const */
- if (csum_partial_copy_fromiovecend(to, (struct iovec *)msg->msg_iter.iov, offset, len, &csum) < 0)
+ if (csum_and_copy_from_iter(to, len, &csum, &msg->msg_iter) != len)
return -EFAULT;
skb->csum = csum_block_add(skb->csum, csum, odd);
}
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 9e15ba7..e9f66e1 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -599,18 +599,18 @@ int ping_getfrag(void *from, char *to,
struct pingfakehdr *pfh = (struct pingfakehdr *)from;
if (offset == 0) {
- if (fraglen < sizeof(struct icmphdr))
+ fraglen -= sizeof(struct icmphdr);
+ if (fraglen < 0)
BUG();
- if (csum_partial_copy_fromiovecend(to + sizeof(struct icmphdr),
- pfh->msg->msg_iter.iov, 0, fraglen - sizeof(struct icmphdr),
- &pfh->wcheck))
+ if (csum_and_copy_from_iter(to + sizeof(struct icmphdr),
+ fraglen, &pfh->wcheck,
+ &pfh->msg->msg_iter) != fraglen)
return -EFAULT;
} else if (offset < sizeof(struct icmphdr)) {
BUG();
} else {
- if (csum_partial_copy_fromiovecend
- (to, pfh->msg->msg_iter.iov, offset - sizeof(struct icmphdr),
- fraglen, &pfh->wcheck))
+ if (csum_and_copy_from_iter(to, fraglen, &pfh->wcheck,
+ &pfh->msg->msg_iter) != fraglen)
return -EFAULT;
}
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 2c9d252..f027a70 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -382,7 +382,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
skb->transport_header = skb->network_header;
err = -EFAULT;
- if (memcpy_fromiovecend((void *)iph, msg->msg_iter.iov, 0, length))
+ if (memcpy_from_msg(iph, msg, length))
goto error_free;
iphlen = iph->ihl * 4;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 93c7482..71fb37c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
goto err_free;
- if (copy_from_iter(skb_put(skb, size), size, &msg->msg_iter) != size)
+ if (memcpy_from_msg(skb_put(skb, size), msg, size))
goto err_free;
TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 0dbb328..dae7f1a 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
skb->ip_summed = CHECKSUM_NONE;
skb->transport_header = skb->network_header;
- err = memcpy_fromiovecend((void *)iph, msg->msg_iter.iov, 0, length);
+ err = memcpy_from_msg(iph, msg, length);
if (err)
goto error_fault;
--
2.1.4
^ permalink raw reply related
* [PATCH v3 14/18] net: switch sockets to ->read_iter/->write_iter
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/socket.c | 56 +++++++++++++++++++++++++++-----------------------------
1 file changed, 27 insertions(+), 29 deletions(-)
diff --git a/net/socket.c b/net/socket.c
index 4d08b50..bbedbfc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -113,10 +113,8 @@ unsigned int sysctl_net_busy_read __read_mostly;
unsigned int sysctl_net_busy_poll __read_mostly;
#endif
-static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos);
-static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos);
+static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to);
+static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);
static int sock_mmap(struct file *file, struct vm_area_struct *vma);
static int sock_close(struct inode *inode, struct file *file);
@@ -142,8 +140,10 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
static const struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .aio_read = sock_aio_read,
- .aio_write = sock_aio_write,
+ .read = new_sync_read,
+ .write = new_sync_write,
+ .read_iter = sock_read_iter,
+ .write_iter = sock_write_iter,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT
@@ -845,49 +845,47 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
return sock->ops->splice_read(sock, ppos, pipe, len, flags);
}
-static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
+static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct file *file = iocb->ki_filp;
struct socket *sock = file->private_data;
- struct msghdr msg;
+ struct msghdr msg = {.msg_iter = *to};
+ ssize_t res;
+
+ if (file->f_flags & O_NONBLOCK)
+ msg.msg_flags = MSG_DONTWAIT;
- if (pos != 0)
+ if (iocb->ki_pos != 0)
return -ESPIPE;
if (iocb->ki_nbytes == 0) /* Match SYS5 behaviour */
return 0;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- iov_iter_init(&msg.msg_iter, READ, iov, nr_segs, iocb->ki_nbytes);
- msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
-
- return __sock_recvmsg(iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags);
+ res = __sock_recvmsg(iocb, sock, &msg,
+ iocb->ki_nbytes, msg.msg_flags);
+ *to = msg.msg_iter;
+ return res;
}
-static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
+static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct socket *sock = file->private_data;
- struct msghdr msg;
+ struct msghdr msg = {.msg_iter = *from};
+ ssize_t res;
- if (pos != 0)
+ if (iocb->ki_pos != 0)
return -ESPIPE;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- iov_iter_init(&msg.msg_iter, WRITE, iov, nr_segs, iocb->ki_nbytes);
- msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+ if (file->f_flags & O_NONBLOCK)
+ msg.msg_flags = MSG_DONTWAIT;
+
if (sock->type == SOCK_SEQPACKET)
msg.msg_flags |= MSG_EOR;
- return __sock_sendmsg(iocb, sock, &msg, iocb->ki_nbytes);
+ res = __sock_sendmsg(iocb, sock, &msg, iocb->ki_nbytes);
+ *from = msg.msg_iter;
+ return res;
}
/*
--
2.1.4
^ permalink raw reply related
* [PATCH v3 13/18] net/socket.c: fold do_sock_{read,write} into callers
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/socket.c | 56 +++++++++++++++++++++-----------------------------------
1 file changed, 21 insertions(+), 35 deletions(-)
diff --git a/net/socket.c b/net/socket.c
index 3326d67..4d08b50 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -845,25 +845,11 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
return sock->ops->splice_read(sock, ppos, pipe, len, flags);
}
-static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, const struct iovec *iov,
- unsigned long nr_segs)
-{
- struct socket *sock = file->private_data;
-
- msg->msg_name = NULL;
- msg->msg_namelen = 0;
- msg->msg_control = NULL;
- msg->msg_controllen = 0;
- iov_iter_init(&msg->msg_iter, READ, iov, nr_segs, iocb->ki_nbytes);
- msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
-
- return __sock_recvmsg(iocb, sock, msg, iocb->ki_nbytes, msg->msg_flags);
-}
-
static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
+ struct file *file = iocb->ki_filp;
+ struct socket *sock = file->private_data;
struct msghdr msg;
if (pos != 0)
@@ -872,36 +858,36 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
if (iocb->ki_nbytes == 0) /* Match SYS5 behaviour */
return 0;
- return do_sock_read(&msg, iocb, iocb->ki_filp, iov, nr_segs);
-}
-
-static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, const struct iovec *iov,
- unsigned long nr_segs)
-{
- struct socket *sock = file->private_data;
-
- msg->msg_name = NULL;
- msg->msg_namelen = 0;
- msg->msg_control = NULL;
- msg->msg_controllen = 0;
- iov_iter_init(&msg->msg_iter, WRITE, iov, nr_segs, iocb->ki_nbytes);
- msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
- if (sock->type == SOCK_SEQPACKET)
- msg->msg_flags |= MSG_EOR;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ iov_iter_init(&msg.msg_iter, READ, iov, nr_segs, iocb->ki_nbytes);
+ msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
- return __sock_sendmsg(iocb, sock, msg, iocb->ki_nbytes);
+ return __sock_recvmsg(iocb, sock, &msg, iocb->ki_nbytes, msg.msg_flags);
}
static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
+ struct file *file = iocb->ki_filp;
+ struct socket *sock = file->private_data;
struct msghdr msg;
if (pos != 0)
return -ESPIPE;
- return do_sock_write(&msg, iocb, iocb->ki_filp, iov, nr_segs);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ iov_iter_init(&msg.msg_iter, WRITE, iov, nr_segs, iocb->ki_nbytes);
+ msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+ if (sock->type == SOCK_SEQPACKET)
+ msg.msg_flags |= MSG_EOR;
+
+ return __sock_sendmsg(iocb, sock, &msg, iocb->ki_nbytes);
}
/*
--
2.1.4
^ permalink raw reply related
* [PATCH v3 11/18] net: bury net/core/iovec.c - nothing in there is used anymore
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/linux/socket.h | 7 ---
net/core/Makefile | 2 +-
net/core/iovec.c | 137 -------------------------------------------------
3 files changed, 1 insertion(+), 145 deletions(-)
delete mode 100644 net/core/iovec.c
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6e49a14..5c19cba 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -318,13 +318,6 @@ struct ucred {
/* IPX options */
#define IPX_TYPE 1
-extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
- struct iovec *iov,
- int offset,
- unsigned int len, __wsum *csump);
-extern unsigned long iov_pages(const struct iovec *iov, int offset,
- unsigned long nr_segs);
-
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
diff --git a/net/core/Makefile b/net/core/Makefile
index 235e6c5..fec0856 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Linux networking core.
#
-obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
+obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \
gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
diff --git a/net/core/iovec.c b/net/core/iovec.c
deleted file mode 100644
index dcbe98b..0000000
--- a/net/core/iovec.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * iovec manipulation routines.
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Fixes:
- * Andrew Lunn : Errors in iovec copying.
- * Pedro Roque : Added memcpy_fromiovecend and
- * csum_..._fromiovecend.
- * Andi Kleen : fixed error handling for 2.1
- * Alexey Kuznetsov: 2.1 optimisations
- * Andi Kleen : Fix csum*fromiovecend for IPv6.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/net.h>
-#include <linux/in6.h>
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-#include <net/checksum.h>
-#include <net/sock.h>
-
-/*
- * And now for the all-in-one: copy and checksum from a user iovec
- * directly to a datagram
- * Calls to csum_partial but the last must be in 32 bit chunks
- *
- * ip_build_xmit must ensure that when fragmenting only the last
- * call to this function will be unaligned also.
- */
-int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
- int offset, unsigned int len, __wsum *csump)
-{
- __wsum csum = *csump;
- int partial_cnt = 0, err = 0;
-
- /* Skip over the finished iovecs */
- while (offset >= iov->iov_len) {
- offset -= iov->iov_len;
- iov++;
- }
-
- while (len > 0) {
- u8 __user *base = iov->iov_base + offset;
- int copy = min_t(unsigned int, len, iov->iov_len - offset);
-
- offset = 0;
-
- /* There is a remnant from previous iov. */
- if (partial_cnt) {
- int par_len = 4 - partial_cnt;
-
- /* iov component is too short ... */
- if (par_len > copy) {
- if (copy_from_user(kdata, base, copy))
- goto out_fault;
- kdata += copy;
- base += copy;
- partial_cnt += copy;
- len -= copy;
- iov++;
- if (len)
- continue;
- *csump = csum_partial(kdata - partial_cnt,
- partial_cnt, csum);
- goto out;
- }
- if (copy_from_user(kdata, base, par_len))
- goto out_fault;
- csum = csum_partial(kdata - partial_cnt, 4, csum);
- kdata += par_len;
- base += par_len;
- copy -= par_len;
- len -= par_len;
- partial_cnt = 0;
- }
-
- if (len > copy) {
- partial_cnt = copy % 4;
- if (partial_cnt) {
- copy -= partial_cnt;
- if (copy_from_user(kdata + copy, base + copy,
- partial_cnt))
- goto out_fault;
- }
- }
-
- if (copy) {
- csum = csum_and_copy_from_user(base, kdata, copy,
- csum, &err);
- if (err)
- goto out;
- }
- len -= copy + partial_cnt;
- kdata += copy + partial_cnt;
- iov++;
- }
- *csump = csum;
-out:
- return err;
-
-out_fault:
- err = -EFAULT;
- goto out;
-}
-EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
-
-unsigned long iov_pages(const struct iovec *iov, int offset,
- unsigned long nr_segs)
-{
- unsigned long seg, base;
- int pages = 0, len, size;
-
- while (nr_segs && (offset >= iov->iov_len)) {
- offset -= iov->iov_len;
- ++iov;
- --nr_segs;
- }
-
- for (seg = 0; seg < nr_segs; seg++) {
- base = (unsigned long)iov[seg].iov_base + offset;
- len = iov[seg].iov_len - offset;
- size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT;
- pages += size;
- offset = 0;
- }
-
- return pages;
-}
-EXPORT_SYMBOL(iov_pages);
--
2.1.4
^ permalink raw reply related
* [PATCH v3 12/18] crypto: switch af_alg_make_sg() to iov_iter
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-crypto
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
With that, all ->sendmsg() instances are converted to iov_iter primitives
and are agnostic wrt the kind of iov_iter they are working with.
So's the last remaining ->recvmsg() instance that wasn't kind-agnostic yet.
All ->sendmsg() and ->recvmsg() advance ->msg_iter by the amount actually
copied and none of them modifies the underlying iovec, etc.
Cc: linux-crypto@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
crypto/af_alg.c | 40 ++++++++------------------
crypto/algif_hash.c | 45 ++++++++++++------------------
crypto/algif_skcipher.c | 74 ++++++++++++++++++++++---------------------------
include/crypto/if_alg.h | 3 +-
4 files changed, 62 insertions(+), 100 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 4665b79c..eb78fe8 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -338,49 +338,31 @@ static const struct net_proto_family alg_family = {
.owner = THIS_MODULE,
};
-int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
- int write)
+int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len)
{
- unsigned long from = (unsigned long)addr;
- unsigned long npages;
- unsigned off;
- int err;
- int i;
-
- err = -EFAULT;
- if (!access_ok(write ? VERIFY_READ : VERIFY_WRITE, addr, len))
- goto out;
-
- off = from & ~PAGE_MASK;
- npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
- if (npages > ALG_MAX_PAGES)
- npages = ALG_MAX_PAGES;
+ size_t off;
+ ssize_t n;
+ int npages, i;
- err = get_user_pages_fast(from, npages, write, sgl->pages);
- if (err < 0)
- goto out;
+ n = iov_iter_get_pages(iter, sgl->pages, len, ALG_MAX_PAGES, &off);
+ if (n < 0)
+ return n;
- npages = err;
- err = -EINVAL;
+ npages = PAGE_ALIGN(off + n);
if (WARN_ON(npages == 0))
- goto out;
-
- err = 0;
+ return -EINVAL;
sg_init_table(sgl->sg, npages);
- for (i = 0; i < npages; i++) {
+ for (i = 0, len = n; i < npages; i++) {
int plen = min_t(int, len, PAGE_SIZE - off);
sg_set_page(sgl->sg + i, sgl->pages[i], plen, off);
off = 0;
len -= plen;
- err += plen;
}
-
-out:
- return err;
+ return n;
}
EXPORT_SYMBOL_GPL(af_alg_make_sg);
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 01f56eb..01da360 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -41,8 +41,6 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct hash_ctx *ctx = ask->private;
- unsigned long iovlen;
- const struct iovec *iov;
long copied = 0;
int err;
@@ -58,37 +56,28 @@ static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
ctx->more = 0;
- for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0;
- iovlen--, iov++) {
- unsigned long seglen = iov->iov_len;
- char __user *from = iov->iov_base;
+ while (iov_iter_count(&msg->msg_iter)) {
+ int len = iov_iter_count(&msg->msg_iter);
- while (seglen) {
- int len = min_t(unsigned long, seglen, limit);
- int newlen;
+ if (len > limit)
+ len = limit;
- newlen = af_alg_make_sg(&ctx->sgl, from, len, 0);
- if (newlen < 0) {
- err = copied ? 0 : newlen;
- goto unlock;
- }
-
- ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL,
- newlen);
-
- err = af_alg_wait_for_completion(
- crypto_ahash_update(&ctx->req),
- &ctx->completion);
+ len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len);
+ if (len < 0) {
+ err = copied ? 0 : len;
+ goto unlock;
+ }
- af_alg_free_sg(&ctx->sgl);
+ ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len);
- if (err)
- goto unlock;
+ err = af_alg_wait_for_completion(crypto_ahash_update(&ctx->req),
+ &ctx->completion);
+ af_alg_free_sg(&ctx->sgl);
+ if (err)
+ goto unlock;
- seglen -= newlen;
- from += newlen;
- copied += newlen;
- }
+ copied += len;
+ iov_iter_advance(&msg->msg_iter, len);
}
err = 0;
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index c12207c..37110fd 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -426,67 +426,59 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
&ctx->req));
struct skcipher_sg_list *sgl;
struct scatterlist *sg;
- unsigned long iovlen;
- const struct iovec *iov;
int err = -EAGAIN;
int used;
long copied = 0;
lock_sock(sk);
- for (iov = msg->msg_iter.iov, iovlen = msg->msg_iter.nr_segs; iovlen > 0;
- iovlen--, iov++) {
- unsigned long seglen = iov->iov_len;
- char __user *from = iov->iov_base;
-
- while (seglen) {
- sgl = list_first_entry(&ctx->tsgl,
- struct skcipher_sg_list, list);
- sg = sgl->sg;
-
- while (!sg->length)
- sg++;
-
- if (!ctx->used) {
- err = skcipher_wait_for_data(sk, flags);
- if (err)
- goto unlock;
- }
+ while (iov_iter_count(&msg->msg_iter)) {
+ sgl = list_first_entry(&ctx->tsgl,
+ struct skcipher_sg_list, list);
+ sg = sgl->sg;
- used = min_t(unsigned long, ctx->used, seglen);
+ while (!sg->length)
+ sg++;
- used = af_alg_make_sg(&ctx->rsgl, from, used, 1);
- err = used;
- if (err < 0)
+ used = ctx->used;
+ if (!used) {
+ err = skcipher_wait_for_data(sk, flags);
+ if (err)
goto unlock;
+ }
+
+ used = min_t(unsigned long, used, iov_iter_count(&msg->msg_iter));
+
+ used = af_alg_make_sg(&ctx->rsgl, &msg->msg_iter, used);
+ err = used;
+ if (err < 0)
+ goto unlock;
- if (ctx->more || used < ctx->used)
- used -= used % bs;
+ if (ctx->more || used < ctx->used)
+ used -= used % bs;
- err = -EINVAL;
- if (!used)
- goto free;
+ err = -EINVAL;
+ if (!used)
+ goto free;
- ablkcipher_request_set_crypt(&ctx->req, sg,
- ctx->rsgl.sg, used,
- ctx->iv);
+ ablkcipher_request_set_crypt(&ctx->req, sg,
+ ctx->rsgl.sg, used,
+ ctx->iv);
- err = af_alg_wait_for_completion(
+ err = af_alg_wait_for_completion(
ctx->enc ?
crypto_ablkcipher_encrypt(&ctx->req) :
crypto_ablkcipher_decrypt(&ctx->req),
&ctx->completion);
free:
- af_alg_free_sg(&ctx->rsgl);
+ af_alg_free_sg(&ctx->rsgl);
- if (err)
- goto unlock;
+ if (err)
+ goto unlock;
- copied += used;
- from += used;
- seglen -= used;
- skcipher_pull_sgl(sk, used);
- }
+ copied += used;
+ skcipher_pull_sgl(sk, used);
+ iov_iter_advance(&msg->msg_iter, used);
}
err = 0;
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index cd62bf4..88ea64e 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -67,8 +67,7 @@ int af_alg_unregister_type(const struct af_alg_type *type);
int af_alg_release(struct socket *sock);
int af_alg_accept(struct sock *sk, struct socket *newsock);
-int af_alg_make_sg(struct af_alg_sgl *sgl, void __user *addr, int len,
- int write);
+int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len);
void af_alg_free_sg(struct af_alg_sgl *sgl);
int af_alg_cmsg_send(struct msghdr *msg, struct af_alg_control *con);
--
2.1.4
^ permalink raw reply related
* [PATCH v3 08/18] ip: convert tcp_sendmsg() to iov_iter primitives
From: Al Viro @ 2015-02-04 6:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
patch is actually smaller than it seems to be - most of it is unindenting
the inner loop body in tcp_sendmsg() itself...
the bit in tcp_input.c is going to get reverted very soon - that's what
memcpy_from_msg() will become, but not in this commit; let's keep it
reasonably contained...
There's one potentially subtle change here: in case of short copy from
userland, mainline tcp_send_syn_data() discards the skb it has allocated
and falls back to normal path, where we'll send as much as possible after
rereading the same data again. This patch trims SYN+data skb instead -
that way we don't need to copy from the same place twice.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
include/net/sock.h | 18 ++--
net/ipv4/tcp.c | 233 +++++++++++++++++++++++---------------------------
net/ipv4/tcp_input.c | 2 +-
net/ipv4/tcp_output.c | 11 ++-
4 files changed, 123 insertions(+), 141 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 1534149..1e45e59 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1803,27 +1803,25 @@ static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags)
}
static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb,
- char __user *from, char *to,
+ struct iov_iter *from, char *to,
int copy, int offset)
{
if (skb->ip_summed == CHECKSUM_NONE) {
- int err = 0;
- __wsum csum = csum_and_copy_from_user(from, to, copy, 0, &err);
- if (err)
- return err;
+ __wsum csum = 0;
+ if (csum_and_copy_from_iter(to, copy, &csum, from) != copy)
+ return -EFAULT;
skb->csum = csum_block_add(skb->csum, csum, offset);
} else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) {
- if (!access_ok(VERIFY_READ, from, copy) ||
- __copy_from_user_nocache(to, from, copy))
+ if (copy_from_iter_nocache(to, copy, from) != copy)
return -EFAULT;
- } else if (copy_from_user(to, from, copy))
+ } else if (copy_from_iter(to, copy, from) != copy)
return -EFAULT;
return 0;
}
static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb,
- char __user *from, int copy)
+ struct iov_iter *from, int copy)
{
int err, offset = skb->len;
@@ -1835,7 +1833,7 @@ static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb,
return err;
}
-static inline int skb_copy_to_page_nocache(struct sock *sk, char __user *from,
+static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *from,
struct sk_buff *skb,
struct page *page,
int off, int copy)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 3075723..9d72a0f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1067,11 +1067,10 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size)
{
- const struct iovec *iov;
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
- int iovlen, flags, err, copied = 0;
- int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
+ int flags, err, copied = 0;
+ int mss_now = 0, size_goal, copied_syn = 0;
bool sg;
long timeo;
@@ -1084,7 +1083,6 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
goto out;
else if (err)
goto out_err;
- offset = copied_syn;
}
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -1118,8 +1116,6 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
mss_now = tcp_send_mss(sk, &size_goal, flags);
/* Ok commence sending. */
- iovlen = msg->msg_iter.nr_segs;
- iov = msg->msg_iter.iov;
copied = 0;
err = -EPIPE;
@@ -1128,151 +1124,134 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
sg = !!(sk->sk_route_caps & NETIF_F_SG);
- while (--iovlen >= 0) {
- size_t seglen = iov->iov_len;
- unsigned char __user *from = iov->iov_base;
+ while (iov_iter_count(&msg->msg_iter)) {
+ int copy = 0;
+ int max = size_goal;
- iov++;
- if (unlikely(offset > 0)) { /* Skip bytes copied in SYN */
- if (offset >= seglen) {
- offset -= seglen;
- continue;
- }
- seglen -= offset;
- from += offset;
- offset = 0;
+ skb = tcp_write_queue_tail(sk);
+ if (tcp_send_head(sk)) {
+ if (skb->ip_summed == CHECKSUM_NONE)
+ max = mss_now;
+ copy = max - skb->len;
}
- while (seglen > 0) {
- int copy = 0;
- int max = size_goal;
-
- skb = tcp_write_queue_tail(sk);
- if (tcp_send_head(sk)) {
- if (skb->ip_summed == CHECKSUM_NONE)
- max = mss_now;
- copy = max - skb->len;
- }
-
- if (copy <= 0) {
+ if (copy <= 0) {
new_segment:
- /* Allocate new segment. If the interface is SG,
- * allocate skb fitting to single page.
- */
- if (!sk_stream_memory_free(sk))
- goto wait_for_sndbuf;
+ /* Allocate new segment. If the interface is SG,
+ * allocate skb fitting to single page.
+ */
+ if (!sk_stream_memory_free(sk))
+ goto wait_for_sndbuf;
- skb = sk_stream_alloc_skb(sk,
- select_size(sk, sg),
- sk->sk_allocation);
- if (!skb)
- goto wait_for_memory;
+ skb = sk_stream_alloc_skb(sk,
+ select_size(sk, sg),
+ sk->sk_allocation);
+ if (!skb)
+ goto wait_for_memory;
- /*
- * Check whether we can use HW checksum.
- */
- if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
- skb->ip_summed = CHECKSUM_PARTIAL;
+ /*
+ * Check whether we can use HW checksum.
+ */
+ if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
+ skb->ip_summed = CHECKSUM_PARTIAL;
- skb_entail(sk, skb);
- copy = size_goal;
- max = size_goal;
+ skb_entail(sk, skb);
+ copy = size_goal;
+ max = size_goal;
- /* All packets are restored as if they have
- * already been sent. skb_mstamp isn't set to
- * avoid wrong rtt estimation.
- */
- if (tp->repair)
- TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED;
- }
+ /* All packets are restored as if they have
+ * already been sent. skb_mstamp isn't set to
+ * avoid wrong rtt estimation.
+ */
+ if (tp->repair)
+ TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED;
+ }
- /* Try to append data to the end of skb. */
- if (copy > seglen)
- copy = seglen;
-
- /* Where to copy to? */
- if (skb_availroom(skb) > 0) {
- /* We have some space in skb head. Superb! */
- copy = min_t(int, copy, skb_availroom(skb));
- err = skb_add_data_nocache(sk, skb, from, copy);
- if (err)
- goto do_fault;
- } else {
- bool merge = true;
- int i = skb_shinfo(skb)->nr_frags;
- struct page_frag *pfrag = sk_page_frag(sk);
-
- if (!sk_page_frag_refill(sk, pfrag))
- goto wait_for_memory;
-
- if (!skb_can_coalesce(skb, i, pfrag->page,
- pfrag->offset)) {
- if (i == MAX_SKB_FRAGS || !sg) {
- tcp_mark_push(tp, skb);
- goto new_segment;
- }
- merge = false;
- }
+ /* Try to append data to the end of skb. */
+ if (copy > iov_iter_count(&msg->msg_iter))
+ copy = iov_iter_count(&msg->msg_iter);
+
+ /* Where to copy to? */
+ if (skb_availroom(skb) > 0) {
+ /* We have some space in skb head. Superb! */
+ copy = min_t(int, copy, skb_availroom(skb));
+ err = skb_add_data_nocache(sk, skb, &msg->msg_iter, copy);
+ if (err)
+ goto do_fault;
+ } else {
+ bool merge = true;
+ int i = skb_shinfo(skb)->nr_frags;
+ struct page_frag *pfrag = sk_page_frag(sk);
+
+ if (!sk_page_frag_refill(sk, pfrag))
+ goto wait_for_memory;
- copy = min_t(int, copy, pfrag->size - pfrag->offset);
-
- if (!sk_wmem_schedule(sk, copy))
- goto wait_for_memory;
-
- err = skb_copy_to_page_nocache(sk, from, skb,
- pfrag->page,
- pfrag->offset,
- copy);
- if (err)
- goto do_error;
-
- /* Update the skb. */
- if (merge) {
- skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
- } else {
- skb_fill_page_desc(skb, i, pfrag->page,
- pfrag->offset, copy);
- get_page(pfrag->page);
+ if (!skb_can_coalesce(skb, i, pfrag->page,
+ pfrag->offset)) {
+ if (i == MAX_SKB_FRAGS || !sg) {
+ tcp_mark_push(tp, skb);
+ goto new_segment;
}
- pfrag->offset += copy;
+ merge = false;
}
- if (!copied)
- TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
+ copy = min_t(int, copy, pfrag->size - pfrag->offset);
- tp->write_seq += copy;
- TCP_SKB_CB(skb)->end_seq += copy;
- tcp_skb_pcount_set(skb, 0);
+ if (!sk_wmem_schedule(sk, copy))
+ goto wait_for_memory;
- from += copy;
- copied += copy;
- if ((seglen -= copy) == 0 && iovlen == 0) {
- tcp_tx_timestamp(sk, skb);
- goto out;
+ err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
+ pfrag->page,
+ pfrag->offset,
+ copy);
+ if (err)
+ goto do_error;
+
+ /* Update the skb. */
+ if (merge) {
+ skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
+ } else {
+ skb_fill_page_desc(skb, i, pfrag->page,
+ pfrag->offset, copy);
+ get_page(pfrag->page);
}
+ pfrag->offset += copy;
+ }
- if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair))
- continue;
+ if (!copied)
+ TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
+
+ tp->write_seq += copy;
+ TCP_SKB_CB(skb)->end_seq += copy;
+ tcp_skb_pcount_set(skb, 0);
+
+ copied += copy;
+ if (!iov_iter_count(&msg->msg_iter)) {
+ tcp_tx_timestamp(sk, skb);
+ goto out;
+ }
- if (forced_push(tp)) {
- tcp_mark_push(tp, skb);
- __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH);
- } else if (skb == tcp_send_head(sk))
- tcp_push_one(sk, mss_now);
+ if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair))
continue;
+ if (forced_push(tp)) {
+ tcp_mark_push(tp, skb);
+ __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH);
+ } else if (skb == tcp_send_head(sk))
+ tcp_push_one(sk, mss_now);
+ continue;
+
wait_for_sndbuf:
- set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+ set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
- tcp_push(sk, flags & ~MSG_MORE, mss_now,
- TCP_NAGLE_PUSH, size_goal);
+ if (copied)
+ tcp_push(sk, flags & ~MSG_MORE, mss_now,
+ TCP_NAGLE_PUSH, size_goal);
- if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
- goto do_error;
+ if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
+ goto do_error;
- mss_now = tcp_send_mss(sk, &size_goal, flags);
- }
+ mss_now = tcp_send_mss(sk, &size_goal, flags);
}
out:
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 71fb37c..93c7482 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4368,7 +4368,7 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
goto err_free;
- if (memcpy_from_msg(skb_put(skb, size), msg, size))
+ if (copy_from_iter(skb_put(skb, size), size, &msg->msg_iter) != size)
goto err_free;
TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 20ab06b..722c8bc 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3055,7 +3055,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_fastopen_request *fo = tp->fastopen_req;
- int syn_loss = 0, space, err = 0;
+ int syn_loss = 0, space, err = 0, copied;
unsigned long last_syn_loss = 0;
struct sk_buff *syn_data;
@@ -3093,11 +3093,16 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
goto fallback;
syn_data->ip_summed = CHECKSUM_PARTIAL;
memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
- if (unlikely(memcpy_fromiovecend(skb_put(syn_data, space),
- fo->data->msg_iter.iov, 0, space))) {
+ copied = copy_from_iter(skb_put(syn_data, space), space,
+ &fo->data->msg_iter);
+ if (unlikely(!copied)) {
kfree_skb(syn_data);
goto fallback;
}
+ if (copied != space) {
+ skb_trim(syn_data, copied);
+ space = copied;
+ }
/* No more data pending in inet_wait_for_connect() */
if (space == fo->size)
--
2.1.4
^ permalink raw reply related
* [PATCH v3 10/18] tipc: tipc ->sendmsg() conversion
From: Al Viro @ 2015-02-04 6:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Jon Maloy
In-Reply-To: <20150204063730.GG29656@ZenIV.linux.org.uk>
From: Al Viro <viro@zeniv.linux.org.uk>
This one needs to copy the same data from user potentially more than
once. Sadly, MTU changes can trigger that ;-/
Cc: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
net/tipc/msg.c | 7 ++-----
net/tipc/socket.c | 14 ++++++++++++--
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 18aba9e..da67c8d 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -189,7 +189,6 @@ err:
* tipc_msg_build - create buffer chain containing specified header and data
* @mhdr: Message header, to be prepended to data
* @m: User message
- * @offset: Posision in iov to start copying from
* @dsz: Total length of user data
* @pktmax: Max packet size that can be used
* @list: Buffer or chain of buffers to be returned to caller
@@ -221,8 +220,7 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,
__skb_queue_tail(list, skb);
skb_copy_to_linear_data(skb, mhdr, mhsz);
pktpos = skb->data + mhsz;
- if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset,
- dsz))
+ if (copy_from_iter(pktpos, dsz, &m->msg_iter) == dsz)
return dsz;
rc = -EFAULT;
goto error;
@@ -252,12 +250,11 @@ int tipc_msg_build(struct net *net, struct tipc_msg *mhdr, struct msghdr *m,
if (drem < pktrem)
pktrem = drem;
- if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) {
+ if (copy_from_iter(pktpos, pktrem, &m->msg_iter) != pktrem) {
rc = -EFAULT;
goto error;
}
drem -= pktrem;
- offset += pktrem;
if (!drem)
break;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 679a220..caa4d66 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -733,6 +733,7 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq,
struct net *net = sock_net(sk);
struct tipc_msg *mhdr = &tipc_sk(sk)->phdr;
struct sk_buff_head head;
+ struct iov_iter save = msg->msg_iter;
uint mtu;
int rc;
@@ -758,8 +759,10 @@ new_mtu:
rc = dsz;
break;
}
- if (rc == -EMSGSIZE)
+ if (rc == -EMSGSIZE) {
+ msg->msg_iter = save;
goto new_mtu;
+ }
if (rc != -ELINKCONG)
break;
tipc_sk(sk)->link_cong = 1;
@@ -895,6 +898,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sk_buff_head head;
struct sk_buff *skb;
struct tipc_name_seq *seq = &dest->addr.nameseq;
+ struct iov_iter save;
u32 mtu;
long timeo;
int rc;
@@ -963,6 +967,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
msg_set_hdr_sz(mhdr, BASIC_H_SIZE);
}
+ save = m->msg_iter;
new_mtu:
mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
__skb_queue_head_init(&head);
@@ -980,8 +985,10 @@ new_mtu:
rc = dsz;
break;
}
- if (rc == -EMSGSIZE)
+ if (rc == -EMSGSIZE) {
+ m->msg_iter = save;
goto new_mtu;
+ }
if (rc != -ELINKCONG)
break;
tsk->link_cong = 1;
@@ -1052,6 +1059,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
long timeo;
u32 dnode;
uint mtu, send, sent = 0;
+ struct iov_iter save;
/* Handle implied connection establishment */
if (unlikely(dest)) {
@@ -1078,6 +1086,7 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
dnode = tsk_peer_node(tsk);
next:
+ save = m->msg_iter;
mtu = tsk->max_pkt;
send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
__skb_queue_head_init(&head);
@@ -1097,6 +1106,7 @@ next:
if (rc == -EMSGSIZE) {
tsk->max_pkt = tipc_node_get_mtu(net, dnode,
portid);
+ m->msg_iter = save;
goto next;
}
if (rc != -ELINKCONG)
--
2.1.4
^ permalink raw reply related
* Invalid timestamp? causing tight ack loop (hundreds of thousands of packets / sec)
From: Avery Fay @ 2015-02-04 6:50 UTC (permalink / raw)
To: netdev
Hello,
Let me say first: if there's a better place to ask this, please point
me in that direction.
We've been having huge packets / sec spikes in the past few days.
After some investigation, it looks like single connections are getting
stuck in a loop (see tcpdump below). Each "stuck" connection will
generate about 200kpps. It looks like our side is rejecting packets
with "packets rejects in established connections because of timestamp"
from netstat -s (internally PAWSEstab counter) and then generating an
additional packet that we send out. All of these connections originate
from georgia tech, but so far (not completely verified) it doesn't
seem like there's any pattern to the client/os other than the fact
that they're trying to make an https request to us.
As a temporary countermeasure, we've disabled net.ipv4.tcp_timestamps,
which solves the immediate problem.
Our server is 174.36.240.86 running Ubuntu 12.04 with kernel 3.13.0-35-generic
The client is 128.61.57.205 and in this case almost certainly has user
agent (we found successful requests 10 seconds before the tcpdump with
same ip): Dalvik/2.1.0 (Linux; U; Android 5.0; XT1095
Build/LXE22.46-11)
Beginning of tcpdump:
05:36:10.723423 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags [S],
seq 4192140517, win 65535, options [mss 1380,sackOK,TS val 3985707 ecr
0,nop,wscale 8], length 0
05:36:10.723431 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags
[S.], seq 1191654135, ack 4192140518, win 28960, options [mss
1460,sackOK,TS val 3311875276 ecr 3985707,nop,wscale 7], length 0
05:36:10.742480 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags [.],
ack 1, win 343, options [nop,nop,TS val 3985710 ecr 3311875276],
length 0
05:36:10.742534 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags [.],
ack 1, win 343, options [nop,nop,TS val 3985710 ecr 3311875276],
length 0
05:36:10.761060 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], seq 1:227, ack 1, win 343, options [nop,nop,TS val 3985712 ecr
3311875276], length 226
05:36:10.761067 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 227, win 235, options [nop,nop,TS val 3311875285 ecr 3985712],
length 0
05:36:10.761122 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:2737, ack 227, win 235, options [nop,nop,TS val 3311875285 ecr
3985712], length 2736
05:36:10.761129 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags
[P.], seq 2737:3256, ack 227, win 235, options [nop,nop,TS val
3311875285 ecr 3985712], length 519
05:36:10.798133 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags
[P.], seq 2737:3256, ack 227, win 235, options [nop,nop,TS val
3311875295 ecr 3985712], length 519
05:36:11.018130 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:1369, ack 227, win 235, options [nop,nop,TS val 3311875350 ecr
3985712], length 1368
05:36:11.458134 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:1369, ack 227, win 235, options [nop,nop,TS val 3311875460 ecr
3985712], length 1368
05:36:12.338130 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:1369, ack 227, win 235, options [nop,nop,TS val 3311875680 ecr
3985712], length 1368
05:36:14.102128 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:1369, ack 227, win 235, options [nop,nop,TS val 3311876121 ecr
3985712], length 1368
05:36:17.634130 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
seq 1:1369, ack 227, win 235, options [nop,nop,TS val 3311877004 ecr
3985712], length 1368
05:36:20.820850 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[F.], seq 227, ack 1, win 343, options [nop,nop,TS val 3986717 ecr
3311875285], length 0
05:36:20.820879 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags
[F.], seq 3256, ack 228, win 235, options [nop,nop,TS val 3311877800
ecr 3986717], length 0
05:36:20.835368 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr
3311875276,nop,nop,sack 1 {3256:3256}], length 0
05:36:20.835373 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877804 ecr 3986717],
length 0
05:36:20.835375 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.835378 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877804 ecr 3986717],
length 0
05:36:20.849735 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr
3311875276,nop,nop,sack 2 {3257:3257}{3256:3256}], length 0
05:36:20.849740 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877807 ecr 3986717],
length 0
05:36:20.849783 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.849785 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877807 ecr 3986717],
length 0
05:36:20.849787 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.849788 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877807 ecr 3986717],
length 0
05:36:20.849789 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.849790 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877807 ecr 3986717],
length 0
05:36:20.864132 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864137 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.864185 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864189 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.864226 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864228 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.864229 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864230 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.864231 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864233 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.864282 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.864285 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877811 ecr 3986717],
length 0
05:36:20.878523 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878530 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878532 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878534 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878620 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878624 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878625 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878627 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878628 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878629 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878630 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878632 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878632 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878634 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878635 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878636 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878672 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878674 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878678 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878679 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878724 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878726 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
05:36:20.878816 IP 128.61.57.205.34574 > 174.36.240.86.443: Flags
[P.], ack 1, win 343, options [nop,nop,TS val 3985712 ecr 3311875276],
length 0
05:36:20.878818 IP 174.36.240.86.443 > 128.61.57.205.34574: Flags [.],
ack 228, win 235, options [nop,nop,TS val 3311877815 ecr 3986717],
length 0
At this point, it just repeats until some timeout is hit. I haven't
timed it, but probably one or two minutes.
I guess I have a few questions:
1.) What's going on here? It looks like maybe there's some packet loss
and then connection termination gets stuck in a loop because the
client timestamp went down?
2.) Is there a better way to mitigate this other than disabling
tcp_timestamps or blocking gatech ips?
3.) Is this our problem (ok, obviously our problem since we're
affected but...), a kernel problem, or a gatech problem?
I'd really appreciate any help on this,
Avery
^ permalink raw reply
* Re: [PATCH net-next] cxgb4: Add low latency socket busy_poll support
From: Kumar Sanghvi @ 2015-02-04 6:21 UTC (permalink / raw)
To: Eric Dumazet
Cc: Hariprasad Shenai, netdev, davem, leedom, anish, nirranjan,
praveenm
In-Reply-To: <1423029509.907.79.camel@edumazet-glaptop2.roam.corp.google.com>
On Tuesday, February 02/03/15, 2015 at 21:58:29 -0800, Eric Dumazet wrote:
> On Tue, 2015-02-03 at 10:50 +0530, Hariprasad Shenai wrote:
>
> > @@ -1978,9 +2016,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
> > {
> > unsigned int params;
> > struct sge_rspq *q = container_of(napi, struct sge_rspq, napi);
> > - int work_done = process_responses(q, budget);
> > + int work_done = 0;
> > u32 val;
> >
> > + if (!cxgb_poll_lock_napi(q))
> > + return work_done;
> > +
>
>
> This is very suspicious. Please take a look at commits
>
> 24e579c8898aa641 ("bnx2x: fix napi poll return value for repoll")
> f104fedc0da126ab ("enic: fix rx napi poll return value")
>
> for context.
Thanks Eric for pointing on this.
So, this probably needs change after commit d75b1ade567ffab ("net: less interrupt masking in NAPI"), or
is there something else that is missed ?
Thanks,
Kumar.
^ permalink raw reply
* Re: [PATCH net-next] cxgb4: Add low latency socket busy_poll support
From: Kumar Sanghvi @ 2015-02-04 6:24 UTC (permalink / raw)
To: Rick Jones
Cc: Hariprasad Shenai, netdev, davem, leedom, anish, nirranjan,
praveenm
In-Reply-To: <54D0FB41.1030802@hp.com>
Hi Rick,
On Tuesday, February 02/03/15, 2015 at 08:45:53 -0800, Rick Jones wrote:
> On 02/02/2015 09:20 PM, Hariprasad Shenai wrote:
> >cxgb_busy_poll, corresponding to ndo_busy_poll, gets called by the socket
> >waiting for data.
> >
> >With busy_poll enabled, improvement is seen in latency numbers as observed by
> >collecting netperf TCP_RR numbers.
>
> Which, not surprisingly, leads to the question - how much
> improvement? :) Extra credit for including the change in
> netperf-reported service demands.
>
> happy benchmarking,
>
> rick jones
>
netperf was not changed in this case. Rather, busy-polling was enabled globally by
setting sysctls busy_poll and busy_read.
We will post the improvement numbers when submitting V2.
Thanks,
Kumar.
^ permalink raw reply
* Re: [PATCH v3 net 1/3] ipv6: Select fragment id during UFO segmentation if not set.
From: David Miller @ 2015-02-04 7:08 UTC (permalink / raw)
To: vyasevich; +Cc: netdev, virtualization
In-Reply-To: <1422999377-18777-2-git-send-email-vyasevic@redhat.com>
From: Vladislav Yasevich <vyasevich@gmail.com>
Date: Tue, 3 Feb 2015 16:36:15 -0500
> diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
> index 97f41a3..54520a0 100644
> --- a/net/ipv6/output_core.c
> +++ b/net/ipv6/output_core.c
> @@ -9,6 +9,24 @@
> #include <net/addrconf.h>
> #include <net/secure_seq.h>
>
> +u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst, struct in6_addr *src)
__ipv6_select_ident() is not used anywhere outside of this file, please
mark it static and remove the declaration for it from net/ipv6.h
^ permalink raw reply
* RE: [PATCH net] hyperv: Fix the error processing in netvsc_send()
From: Jason Wang @ 2015-02-04 7:29 UTC (permalink / raw)
To: Haiyang Zhang
Cc: olaf@aepfle.de, netdev@vger.kernel.org,
driverdev-devel@linuxdriverproject.org,
linux-kernel@vger.kernel.org, davem@davemloft.net
In-Reply-To: <BN1PR0301MB077018D4A512E3AA9B8583E0CA3D0@BN1PR0301MB0770.namprd03.prod.out look.com>
On Tue, Feb 3, 2015 at 11:46 PM, Haiyang Zhang <haiyangz@microsoft.com>
wrote:
>
>
>> -----Original Message-----
>> From: Jason Wang [mailto:jasowang@redhat.com]
>> Sent: Monday, February 2, 2015 1:49 AM
>> >> btw, I find during netvsc_start_xmit(), ret was change to
>> -ENOSPC
>> >> when
>> >> queue_sends[q_idx] < 1. But non of the caller check -ENOSPC in
>> fact?
>> >
>> > In this case, we don't request re-send, so set ret to a value
>> other
>> > than
>> > -EAGAIN.
>>
>> Why not? We have available slots for it to be sent now. Dropping the
>> packet in this case may cause out of order sending.
>
> The EAGAIN error doesn't normally happen, because we set the hi water
> mark
> to stop send queue.
This is not true since only txq was stopped which means only network
stack stop sending packets but not for control path e.g
rndis_filter_send_request() or other callers who call
vmbus_sendpacket() directly (e.g recv completion).
For control path, user may meet several errors when they want to change
mac address under heavy load.
What's more serious is netvsc_send_recv_completion(), it can not even
recover from more than 3 times of EAGAIN.
I must say mixing data packets with control packets with the same
channel sounds really scary. Since control packets could be blocked or
even dropped because of data packets already queued during heavy load,
and you need to synchronize two paths carefully (e.g I didn't see any
tx lock were held if rndis_filter_send_request() call netsc_send()
which may stop or start a queue).
> If in really rare case, the ring buffer is full and there
> is no outstanding sends, we can't stop queue here because there will
> be no
> send-completion msg to wake it up.
Confused, I believe only txq is stopped but we may still get completion
interrupt in this case.
> And, the ring buffer is likely to be
> occupied by other special msg, e.g. receive-completion msg (not a
> normal case),
> so we can't assume there are available slots.
Then why not checking hv_ringbuf_avail_percent() instead? And there's
no need to check queue_sends since it does not count recv completion.
> We don't request retry from
> the upper layer in this case to avoid possible busy retry.
Can't we just do this by stopping txq and depending on tx interrupt to
wake it?
Thanks
^ permalink raw reply
* Re: [PATCH] net: remove sock_iocb
From: Ying Xue @ 2015-02-04 7:29 UTC (permalink / raw)
To: Al Viro, David Miller, Jon Maloy; +Cc: netdev, hch
In-Reply-To: <20150129075721.GD29656@ZenIV.linux.org.uk>
On 01/29/2015 03:57 PM, Al Viro wrote:
> On Wed, Jan 28, 2015 at 11:22:11PM -0800, David Miller wrote:
>> From: Christoph Hellwig <hch@lst.de>
>> Date: Wed, 28 Jan 2015 18:04:53 +0100
>>
>>> The sock_iocb structure is allocate on stack for each read/write-like
>>> operation on sockets, and contains various fields of which only the
>>> embedded msghdr and sometimes a pointer to the scm_cookie is ever used.
>>> Get rid of the sock_iocb and put a msghdr directly on the stack and pass
>>> the scm_cookie explicitly to netlink_mmap_sendmsg.
>>>
>>> Signed-off-by: Christoph Hellwig <hch@lst.de>
>>
>> Looks good, applied, thanks.
>
> You know, that's getting _really_ interesting. The thing is, now
> there's only one ->sendmsg() instance using iocb argument at all,
> and it's a really weird one. TIPC. Which only compares it with
> NULL, and that - to tell the normal calls (== done by sock_sendmsg()
> et.al.) from tipc_{accept,connect}()-generated ones. And the way
> it's used is
> if (iocb)
> lock_sock(sk);
> in tipc_send_stream(). IOW, "tipc_accept() and tipc_connect() would like
> to use the guts of tipc_send_stream(), but they are already holding the
> socket locked; let's just pass NULL iocb (which net/socket.c never does)
> to tell it to leave the fucking lock alone, thank you very much".
>
> And no ->recvmsg() are using iocb at all now. How about we take the
> guts of tipc_send_stream() into a helper function and have tipc_accept/connect
> use _that_? Then we could drop iocb argument completely and for ->sendmsg()
> it would be the difference between 4 and 3 arguments, which has interesting
> effects on certain register-starved architectures...
>
> While we are at it, size (both for sendmsg and recvmsg) is always equal to
> iov_iter_count(&msg->msg_iter), so that's not the only redundant argument
> there...
>
> Comments?
Below is a demonstrated patch to not use iocb argument in tipc socket:
Subject: [PATCH] tipc: Don't use iocb argument in socket layer
Signed-off-by: Ying Xue <ying.xue@windriver.com>
---
net/tipc/socket.c | 44 ++++++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 679a220..8362feb 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -116,6 +116,9 @@ static int tipc_sk_withdraw(struct tipc_sock *tsk,
uint scope,
static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid);
static int tipc_sk_insert(struct tipc_sock *tsk);
static void tipc_sk_remove(struct tipc_sock *tsk);
+static int __tipc_send_stream(struct socket *sock, struct msghdr *m,
+ size_t dsz);
+static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t
dsz);
static const struct proto_ops packet_ops;
static const struct proto_ops stream_ops;
@@ -886,6 +889,18 @@ static int tipc_wait_for_sndmsg(struct socket
*sock, long *timeo_p)
static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t dsz)
{
+ struct sock *sk = sock->sk;
+ int ret;
+
+ lock_sock(sk);
+ ret = __tipc_sendmsg(sock, m, dsz);
+ release_sock(sk);
+
+ return ret;
+}
+
+static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t
dsz)
+{
DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
struct sock *sk = sock->sk;
struct tipc_sock *tsk = tipc_sk(sk);
@@ -909,9 +924,6 @@ static int tipc_sendmsg(struct kiocb *iocb, struct
socket *sock,
if (dsz > TIPC_MAX_USER_MSG_SIZE)
return -EMSGSIZE;
- if (iocb)
- lock_sock(sk);
-
if (unlikely(sock->state != SS_READY)) {
if (sock->state == SS_LISTENING) {
rc = -EPIPE;
@@ -990,9 +1002,6 @@ new_mtu:
__skb_queue_purge(&head);
} while (!rc);
exit:
- if (iocb)
- release_sock(sk);
-
return rc;
}
@@ -1042,6 +1051,18 @@ static int tipc_send_stream(struct kiocb *iocb,
struct socket *sock,
struct msghdr *m, size_t dsz)
{
struct sock *sk = sock->sk;
+ int ret;
+
+ lock_sock(sk);
+ ret = __tipc_send_stream(sock, m, dsz);
+ release_sock(sk);
+
+ return ret;
+}
+
+static int __tipc_send_stream(struct socket *sock, struct msghdr *m,
size_t dsz)
+{
+ struct sock *sk = sock->sk;
struct net *net = sock_net(sk);
struct tipc_sock *tsk = tipc_sk(sk);
struct tipc_msg *mhdr = &tsk->phdr;
@@ -1055,7 +1076,7 @@ static int tipc_send_stream(struct kiocb *iocb,
struct socket *sock,
/* Handle implied connection establishment */
if (unlikely(dest)) {
- rc = tipc_sendmsg(iocb, sock, m, dsz);
+ rc = __tipc_sendmsg(sock, m, dsz);
if (dsz && (dsz == rc))
tsk->sent_unacked = 1;
return rc;
@@ -1063,9 +1084,6 @@ static int tipc_send_stream(struct kiocb *iocb,
struct socket *sock,
if (dsz > (uint)INT_MAX)
return -EMSGSIZE;
- if (iocb)
- lock_sock(sk);
-
if (unlikely(sock->state != SS_CONNECTED)) {
if (sock->state == SS_DISCONNECTING)
rc = -EPIPE;
@@ -1108,8 +1126,6 @@ next:
__skb_queue_purge(&head);
} while (!rc);
exit:
- if (iocb)
- release_sock(sk);
return sent ? sent : rc;
}
@@ -1874,7 +1890,7 @@ static int tipc_connect(struct socket *sock,
struct sockaddr *dest,
if (!timeout)
m.msg_flags = MSG_DONTWAIT;
- res = tipc_sendmsg(NULL, sock, &m, 0);
+ res = __tipc_sendmsg(sock, &m, 0);
if ((res < 0) && (res != -EWOULDBLOCK))
goto exit;
@@ -2030,7 +2046,7 @@ static int tipc_accept(struct socket *sock, struct
socket *new_sock, int flags)
struct msghdr m = {NULL,};
tsk_advance_rx_queue(sk);
- tipc_send_packet(NULL, new_sock, &m, 0);
+ __tipc_send_stream(new_sock, &m, 0);
} else {
__skb_dequeue(&sk->sk_receive_queue);
__skb_queue_head(&new_sk->sk_receive_queue, buf);
Regards,
Ying
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
^ permalink raw reply related
* [PATCH] cw1200: use msecs_to_jiffies for conversion
From: Nicholas Mc Guire @ 2015-02-04 7:39 UTC (permalink / raw)
To: Solomon Peachy
Cc: Kalle Valo, linux-wireless, netdev, linux-kernel,
Nicholas Mc Guire
This is only an API consolidation to make things more readable.
Instances of HZ / CONST are replaced by appropriate msecs_to_jiffies().
Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
---
Converting milliseconds to jiffies by "val * HZ / 1000" or passing
HZ / 10 is technically OK but appropriate msecs_to_jiffies(val), respectively
msecs_to_jiffies(100) is the cleaner solution and handles all corner cases
correctly. This is a minor API cleanup only.
Patch was only compile tested for x86_64_defconfig + CONFIG_CW1200=m
Patch is against 3.19.0-rc7 (localversion-next = -next-20150203)
drivers/net/wireless/cw1200/scan.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c
index f2e276f..bff81b8 100644
--- a/drivers/net/wireless/cw1200/scan.c
+++ b/drivers/net/wireless/cw1200/scan.c
@@ -39,9 +39,9 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
cancel_delayed_work_sync(&priv->clear_recent_scan_work);
atomic_set(&priv->scan.in_progress, 1);
atomic_set(&priv->recent_scan, 1);
- cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000);
+ cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo));
queue_delayed_work(priv->workqueue, &priv->scan.timeout,
- tmo * HZ / 1000);
+ msecs_to_jiffies(tmo));
ret = wsm_scan(priv, scan);
if (ret) {
atomic_set(&priv->scan.in_progress, 0);
@@ -386,8 +386,8 @@ void cw1200_probe_work(struct work_struct *work)
if (down_trylock(&priv->scan.lock)) {
/* Scan is already in progress. Requeue self. */
schedule();
- queue_delayed_work(priv->workqueue,
- &priv->scan.probe_work, HZ / 10);
+ queue_delayed_work(priv->workqueue, &priv->scan.probe_work,
+ msecs_to_jiffies(100));
mutex_unlock(&priv->conf_mutex);
return;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH net-next] xps: fix xps for stacked devices
From: Eric Dumazet @ 2015-02-04 7:48 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Willem de Bruijn, Nandita Dukkipati, Yuchung Cheng
From: Eric Dumazet <edumazet@google.com>
A typical qdisc setup is the following :
bond0 : bonding device, using HTB hierarchy
eth1/eth2 : slaves, multiqueue NIC, using MQ + FQ qdisc
XPS allows to spread packets on specific tx queues, based on the cpu
doing the send.
Problem is that dequeues from bond0 qdisc can happen on random cpus,
due to the fact that qdisc_run() can dequeue a batch of packets.
CPUA -> queue packet P1 on bond0 qdisc, P1->ooo_okay=1
CPUA -> queue packet P2 on bond0 qdisc, P2->ooo_okay=0
CPUB -> dequeue packet P1 from bond0
enqueue packet on eth1/eth2
CPUC -> dequeue packet P2 from bond0
enqueue packet on eth1/eth2 using sk cache (ooo_okay is 0)
get_xps_queue() then might select wrong queue for P1, since current cpu
might be different than CPUA.
P2 might be sent on the old queue (stored in sk->sk_tx_queue_mapping),
if CPUC runs a bit faster (or CPUB spins a bit on qdisc lock)
Effect of this bug is TCP reorders, and more generally not optimal
TX queue placement. (A victim bulk flow can be migrated to the wrong TX
queue for a while)
To fix this, we have to record sender cpu number the first time
dev_queue_xmit() is called for one tx skb.
We can union napi_id (used on receive path) and sender_cpu,
granted we clear sender_cpu in skb_scrub_packet() (credit to Willem for
this union idea)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Nandita Dukkipati <nanditad@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
---
include/linux/skbuff.h | 7 +++++--
net/core/flow_dissector.c | 7 ++++++-
net/core/skbuff.c | 4 ++++
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 85ab7d72b54c2f269812015b19544674bc6dcd72..2748ff63914438268458246adb165e61ed892656 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -626,8 +626,11 @@ struct sk_buff {
__u32 hash;
__be16 vlan_proto;
__u16 vlan_tci;
-#ifdef CONFIG_NET_RX_BUSY_POLL
- unsigned int napi_id;
+#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)
+ union {
+ unsigned int napi_id;
+ unsigned int sender_cpu;
+ };
#endif
#ifdef CONFIG_NETWORK_SECMARK
__u32 secmark;
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index beb83d1ac1c688d7b593a5cad85236b6d94c3106..2c35c02a931e227fa368cd346873596d4b037a3d 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -422,7 +422,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
dev_maps = rcu_dereference(dev->xps_maps);
if (dev_maps) {
map = rcu_dereference(
- dev_maps->cpu_map[raw_smp_processor_id()]);
+ dev_maps->cpu_map[skb->sender_cpu - 1]);
if (map) {
if (map->len == 1)
queue_index = map->queues[0];
@@ -468,6 +468,11 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev,
{
int queue_index = 0;
+#ifdef CONFIG_XPS
+ if (skb->sender_cpu == 0)
+ skb->sender_cpu = raw_smp_processor_id() + 1;
+#endif
+
if (dev->real_num_tx_queues != 1) {
const struct net_device_ops *ops = dev->netdev_ops;
if (ops->ndo_select_queue)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index a5bff2767f15abe09b5f0d0a3bfecfb5775a4e64..88c613eab142962dc44f2075378fce0b94349e8e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -825,6 +825,9 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#ifdef CONFIG_NET_RX_BUSY_POLL
CHECK_SKB_FIELD(napi_id);
#endif
+#ifdef CONFIG_XPS
+ CHECK_SKB_FIELD(sender_cpu);
+#endif
#ifdef CONFIG_NET_SCHED
CHECK_SKB_FIELD(tc_index);
#ifdef CONFIG_NET_CLS_ACT
@@ -4169,6 +4172,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
skb->ignore_df = 0;
skb_dst_drop(skb);
skb->mark = 0;
+ skb->sender_cpu = 0;
skb_init_secmark(skb);
secpath_reset(skb);
nf_reset(skb);
^ permalink raw reply related
* Re: [PATCH net-next] cxgb4: Add low latency socket busy_poll support
From: Eric Dumazet @ 2015-02-04 7:50 UTC (permalink / raw)
To: Kumar Sanghvi
Cc: Hariprasad Shenai, netdev, davem, leedom, anish, nirranjan,
praveenm
In-Reply-To: <20150204062137.GD30631@kumar-pc.asicdesigners.com>
On Wed, 2015-02-04 at 12:21 +0600, Kumar Sanghvi wrote:
> On Tuesday, February 02/03/15, 2015 at 21:58:29 -0800, Eric Dumazet wrote:
> > On Tue, 2015-02-03 at 10:50 +0530, Hariprasad Shenai wrote:
> >
> > > @@ -1978,9 +2016,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
> > > {
> > > unsigned int params;
> > > struct sge_rspq *q = container_of(napi, struct sge_rspq, napi);
> > > - int work_done = process_responses(q, budget);
> > > + int work_done = 0;
> > > u32 val;
> > >
> > > + if (!cxgb_poll_lock_napi(q))
> > > + return work_done;
> > > +
> >
> >
> > This is very suspicious. Please take a look at commits
> >
> > 24e579c8898aa641 ("bnx2x: fix napi poll return value for repoll")
> > f104fedc0da126ab ("enic: fix rx napi poll return value")
> >
> > for context.
>
> Thanks Eric for pointing on this.
> So, this probably needs change after commit d75b1ade567ffab ("net: less interrupt masking in NAPI"), or
> is there something else that is missed ?
Right, you probably need to return budget here, not 0 (work_done == 0 at
this stage)
^ permalink raw reply
* Re: [PATCH net-next] bridge: Let bridge not age 'externally' learnt FDB entries, they are removed when 'external' entity notifies the aging
From: Siva Mannem @ 2015-02-04 8:02 UTC (permalink / raw)
To: roopa; +Cc: Netdev, Scott Feldman, Jiri Pirko
In-Reply-To: <54D0E521.6070100@cumulusnetworks.com>
On Tue, Feb 3, 2015 at 8:41 PM, roopa <roopa@cumulusnetworks.com> wrote:
> On 2/2/15, 9:21 AM, Siva Mannem wrote:
>>
>> When 'learned_sync' flag is turned on, the offloaded switch
>> port syncs learned MAC addresses to bridge's FDB via switchdev notifier
>> (NETDEV_SWITCH_FDB_ADD). Currently, FDB entries learnt via this
>> mechanism are
>> wrongly being deleted by bridge aging logic. This patch ensures that FDB
>> entries synced from offloaded switch ports are not deleted by bridging
>> logic.
>> Such entries can only be deleted via switchdev notifier
>> (NETDEV_SWITCH_FDB_DEL).
>
>
> Your patch seems right and maintains symmetry for fdb add/del of externally
> learnt entries.
> However, this could be made configurable. I think some drivers may rely on
> bridge driver aging these entries (The default setting needs more thought).
> I am not sure what rocker does (CC'ed rocker maintainers). But, our driver
> does rely on the bridge driver aging these entries by default.
added_by_external_learn flag is only set for entries learned via
switchdev notifier
(NETDEV_SWITCH_FDB_ADD) and rocker is the only driver using these notifiers.
I see that rocker is deleting the entries via switchdev notifier
(NETDEV_SWITCH_FDB_DEL).
This mechanism is only used by drivers when learned_sync is turned on by user.
$ sudo bridge link set dev swp1 learning_sync on self
Am I missing something here?
>
>>
>> Signed-off-by: Siva Mannem <siva.mannem.lnx@gmail.com>
>> ---
>> net/bridge/br_fdb.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
>> index 08bf04b..6eb94b5 100644
>> --- a/net/bridge/br_fdb.c
>> +++ b/net/bridge/br_fdb.c
>> @@ -280,7 +280,7 @@ void br_fdb_cleanup(unsigned long _data)
>> hlist_for_each_entry_safe(f, n, &br->hash[i], hlist) {
>> unsigned long this_timer;
>> - if (f->is_static)
>> + if (f->is_static || f->added_by_external_learn)
>> continue;
>> this_timer = f->updated + delay;
>> if (time_before_eq(this_timer, jiffies))
>
>
--
Regards,
Siva Mannem.
^ permalink raw reply
* Re: Invalid timestamp? causing tight ack loop (hundreds of thousands of packets / sec)
From: Eric Dumazet @ 2015-02-04 8:03 UTC (permalink / raw)
To: Avery Fay; +Cc: netdev, Neal Cardwell
In-Reply-To: <CAO-X30uMA7=DTm5KqqvYC5RVTM0bg9pKBO1nX1+6x_2pF_fWfA@mail.gmail.com>
On Tue, 2015-02-03 at 22:50 -0800, Avery Fay wrote:
> Hello,
>
> Let me say first: if there's a better place to ask this, please point
> me in that direction.
>
> We've been having huge packets / sec spikes in the past few days.
> After some investigation, it looks like single connections are getting
> stuck in a loop (see tcpdump below). Each "stuck" connection will
> generate about 200kpps. It looks like our side is rejecting packets
> with "packets rejects in established connections because of timestamp"
> from netstat -s (internally PAWSEstab counter) and then generating an
> additional packet that we send out. All of these connections originate
> from georgia tech, but so far (not completely verified) it doesn't
> seem like there's any pattern to the client/os other than the fact
> that they're trying to make an https request to us.
>
> As a temporary countermeasure, we've disabled net.ipv4.tcp_timestamps,
> which solves the immediate problem.
>
> Our server is 174.36.240.86 running Ubuntu 12.04 with kernel 3.13.0-35-generic
>
> The client is 128.61.57.205 and in this case almost certainly has user
> agent (we found successful requests 10 seconds before the tcpdump with
> same ip): Dalvik/2.1.0 (Linux; U; Android 5.0; XT1095
> Build/LXE22.46-11)
>
> Beginning of tcpdump:
...
>
> At this point, it just repeats until some timeout is hit. I haven't
> timed it, but probably one or two minutes.
>
> I guess I have a few questions:
>
> 1.) What's going on here? It looks like maybe there's some packet loss
> and then connection termination gets stuck in a loop because the
> client timestamp went down?
> 2.) Is there a better way to mitigate this other than disabling
> tcp_timestamps or blocking gatech ips?
> 3.) Is this our problem (ok, obviously our problem since we're
> affected but...), a kernel problem, or a gatech problem?
>
> I'd really appreciate any help on this,
Would you have a pcap file instead ?
It looks a middlebox is broken, I dont think Android could possibly send
a frame with no payload, but with Push flag.
Neal has some patches that add a rate limiting on DACKS, that we might
upstream. (per socket rate limiting of 2 DACK per second)
Thanks
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox