Skip to contentSkip to conversation

extend taskstats API to support networking accounts

PATCH Superseded Li Yu 3 participants 7 messages Feb 23, 2012 – Feb 26, 2012

Subsystems (9)
lore
Share & tools
lore

Li Yu

author
#0 lore raw

PATCH 1/1 extend taskstats API to support networking accounts

This patch adds L7 traffic accounting in taskstats API, so the iotop like applications can receive these statistics data. In fact, I also have an iotop patch for this change.

It ignores any protocol header overhead, so results of this patch should be saw as the application-aware data statistics instead of traffic statistics on wire. And it also ignores any IPC traffic on local host.

This patch only records TCP/UDP/Raw-IP traffic so far, and adding other protocol support is easy.

 include/linux/sched.h     |    2 ++
 include/linux/taskstats.h |    7 ++++++-
 include/net/sock.h        |   10 ++++++++++
 kernel/fork.c             |    1 +
 kernel/taskstats.c        |    6 ++++++
 net/ipv4/raw.c            |    3 +++
 net/ipv4/tcp.c            |    8 +++++++-
 net/ipv4/udp.c            |   10 ++++++++--
include/linux/sched.h +2 -0
index 7d379a6..5b2dbc5 100644
@@ -1590,6 +1590,8 @@ struct task_struct {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	atomic_t ptrace_bp_refcnt;
 #endif
+       u64 rx_bytes;
+       u64 tx_bytes;
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
include/linux/taskstats.h +6 -1
index 2466e55..39b356c 100644
@@ -33,7 +33,7 @@
  */
 
 
-#define TASKSTATS_VERSION	8
+#define TASKSTATS_VERSION	9
 #define TS_COMM_LEN		32	/* should be >= TASK_COMM_LEN
 					 * in linux/sched.h */
 
@@ -163,6 +163,11 @@ struct taskstats {
 	/* Delay waiting for memory reclaim */
 	__u64	freepages_count;
 	__u64	freepages_delay_total;
+	 /* Version 8 ends here */
+
+	/* Net accounting */
+	__u64   rx_bytes;
+	__u64   tx_bytes;
 };
 
 
include/net/sock.h +0 -0
index 91c1c8b..7b4f3b0 100644
@@ -1735,6 +1735,16 @@ static inline int skb_copy_to_page(struct sock

*sk, char __user *from,
return 0;
}

+static inline void task_net_accounting_rx(unsigned int len) +{
+ current->rx_bytes += len; /* Ignore PDU header */
+}
+
+static inline void task_net_accounting_tx(unsigned int len) +{
+ current->tx_bytes += len; /* Ignore PDU header */
+}
+
/**
* sk_wmem_alloc_get - returns write allocations
* @sk: socket

kernel/fork.c +0 -0
index b77fd55..5788f3e 100644
@@ -1168,6 +1168,7 @@ static struct task_struct *copy_process(unsigned

long clone_flags,
p->default_timer_slack_ns = current->timer_slack_ns;

task_io_accounting_init(&p->ioac);
+ p->rx_bytes = p->tx_bytes = 0;
acct_clear_integrals(p);

posix_cpu_timers_init(p);

kernel/taskstats.c +0 -0
index e660464..4d1fcd2 100644
@@ -194,6 +194,9 @@ static void fill_stats(struct task_struct *tsk,

struct taskstats *stats)

/* fill in extended acct fields */
xacct_add_tsk(stats, tsk);
+
+ stats->rx_bytes = tsk->rx_bytes;
+ stats->tx_bytes = tsk->tx_bytes;
}

static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
@@ -247,6 +250,9 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)

stats->nvcsw += tsk->nvcsw;
stats->nivcsw += tsk->nivcsw;
+
+ stats->rx_bytes += tsk->rx_bytes;
+ stats->tx_bytes += tsk->tx_bytes;
} while_each_thread(first, tsk);

unlock_task_sighand(first, &flags);

net/ipv4/raw.c +3 -0
index ab46630..6d62190 100644
@@ -622,6 +622,7 @@ done:
 out:
 	if (err < 0)
 		return err;
+	task_net_accounting_tx(len);
 	return len;
 
 do_confirm:
@@ -729,6 +730,8 @@ done:
 out:
 	if (err)
 		return err;
+	if (!(flags & MSG_PEEK))
+		task_net_accounting_rx(copied);
 	return copied;
 }
 
net/ipv4/tcp.c +0 -0
index 37755cc..240384d 100644
@@ -682,8 +682,10 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t

*ppos,

release_sock(sk);

- if (spliced)
+ if (spliced) {
+ task_net_accounting_rx(spliced);
return spliced;
+ }

return ret;
}
@@ -860,6 +862,7 @@ wait_for_memory:
out:
if (copied)
tcp_push(sk, flags, mss_now, tp->nonagle);
+ task_net_accounting_tx(copied);
return copied;

do_error:
@@ -1114,6 +1117,7 @@ out:
if (copied)
tcp_push(sk, flags, mss_now, tp->nonagle);
release_sock(sk);
+ task_net_accounting_tx(copied);
return copied;

do_fault:
@@ -1771,6 +1775,8 @@ skip_copy:
tcp_cleanup_rbuf(sk, copied);

release_sock(sk);
+ if (!(flags & MSG_PEEK))
+ task_net_accounting_rx(copied);
return copied;

out:

net/ipv4/udp.c +3 -1
index cd99f1a..d2d09a3 100644
@@ -1006,8 +1006,10 @@ out:
 	ip_rt_put(rt);
 	if (free)
 		kfree(ipc.opt);
-	if (!err)
+	if (!err) {
+		task_net_accounting_tx(len);
 		return len;
+	}
 	/*
 	 * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space.  Reporting
 	 * ENOBUFS might not be good (it's not tunable per se), but otherwise
@@ -1073,8 +1075,10 @@ int udp_sendpage(struct sock *sk, struct page

*page, int offset,
up->len += size;
if (!(up->corkflag || (flags&MSG_MORE)))
ret = udp_push_pending_frames(sk);
- if (!ret)
+ if (!ret) {
ret = size;
+ task_net_accounting_tx(size);
+ }
out:
release_sock(sk);
return ret;
@@ -1237,6 +1241,8 @@ try_again:
ip_cmsg_recv(msg, skb);

err = copied;
+ if (!(flags & MSG_PEEK))
+ task_net_accounting_rx(copied);
if (flags & MSG_TRUNC)
err = ulen;

maintainer
#1 lore raw

From: Li Yu <[email protected]>
Date: Thu, 23 Feb 2012 16:22:23 +0800

Quoted 2 lines

This patch only records TCP/UDP/Raw-IP traffic so far, and adding other protocol support is easy.

It shouldn't even be necessary to put any code into specific protocols, it should instead be done at some generic location so that all protocols are supported transparently.

author
#2 lore raw

PATCH v2 1/1 extend taskstats API to support networking accounts

This patch adds L7 traffic accounting in taskstats API, so the iotop like applications can receive these statistics data. In fact, I also have an iotop patch for this change.

It ignores any protocol header overhead, so results of this patch should be saw as the applications-aware data statistics instead of traffic statistics on wire.

The changes of v2 are:

1. Move up accounting source code, so they are not protocol-aware now.
2. Skipping interrupt context accounting.

That is all, thanks

 include/linux/sched.h     |    2 ++
 include/linux/taskstats.h |    7 ++++++-
 include/net/sock.h        |   12 ++++++++++++
 kernel/fork.c             |    1 +
 kernel/taskstats.c        |    6 ++++++
 net/socket.c              |   27 ++++++++++++++++++++++-----
 6 files changed, 49 insertions(+), 6 deletions(-)
include/linux/sched.h +2 -0
index 7d379a6..5b2dbc5 100644
@@ -1590,6 +1590,8 @@ struct task_struct {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	atomic_t ptrace_bp_refcnt;
 #endif
+       u64 rx_bytes;
+       u64 tx_bytes;
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
include/linux/taskstats.h +6 -1
index 2466e55..39b356c 100644
@@ -33,7 +33,7 @@
  */
 
 
-#define TASKSTATS_VERSION	8
+#define TASKSTATS_VERSION	9
 #define TS_COMM_LEN		32	/* should be >= TASK_COMM_LEN
 					 * in linux/sched.h */
 
@@ -163,6 +163,11 @@ struct taskstats {
 	/* Delay waiting for memory reclaim */
 	__u64	freepages_count;
 	__u64	freepages_delay_total;
+	 /* Version 8 ends here */
+
+	/* Net accounting */
+	__u64   rx_bytes;
+	__u64   tx_bytes;
 };
 
 
include/net/sock.h +12 -0
index 91c1c8b..1f52c2a 100644
@@ -1735,6 +1735,18 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
 	return 0;
 }
 
+static inline void task_net_accounting_rx(unsigned int len)
+{
+	if (!in_irq() && len > 0)
+		current->rx_bytes += len;
+}
+
+static inline void task_net_accounting_tx(unsigned int len)
+{
+	if (!in_irq() && len > 0)
+		current->tx_bytes += len;
+}
+
 /**
  * sk_wmem_alloc_get - returns write allocations
  * @sk: socket
kernel/fork.c +1 -0
index b77fd55..5788f3e 100644
@@ -1168,6 +1168,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	p->default_timer_slack_ns = current->timer_slack_ns;
 
 	task_io_accounting_init(&p->ioac);
+	p->rx_bytes = p->tx_bytes = 0;
 	acct_clear_integrals(p);
 
 	posix_cpu_timers_init(p);
kernel/taskstats.c +6 -0
index e660464..4d1fcd2 100644
@@ -194,6 +194,9 @@ static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
 
 	/* fill in extended acct fields */
 	xacct_add_tsk(stats, tsk);
+
+	stats->rx_bytes = tsk->rx_bytes;
+	stats->tx_bytes = tsk->tx_bytes;
 }
 
 static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
@@ -247,6 +250,9 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
 
 		stats->nvcsw += tsk->nvcsw;
 		stats->nivcsw += tsk->nivcsw;
+
+		stats->rx_bytes += tsk->rx_bytes;
+		stats->tx_bytes += tsk->tx_bytes;
 	} while_each_thread(first, tsk);
 
 	unlock_task_sighand(first, &flags);
net/socket.c +22 -5
index 28a96af..c1b736d 100644
@@ -548,6 +548,7 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 				       struct msghdr *msg, size_t size)
 {
 	struct sock_iocb *si = kiocb_to_siocb(iocb);
+	int ret;
 
 	sock_update_classid(sock->sk);
 
@@ -558,7 +559,10 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 	si->msg = msg;
 	si->size = size;
 
-	return sock->ops->sendmsg(iocb, sock, msg, size);
+	ret = sock->ops->sendmsg(iocb, sock, msg, size);
+	task_net_accounting_tx(ret);
+
+	return ret;
 }
 
 static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
@@ -714,6 +718,7 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 				       struct msghdr *msg, size_t size, int flags)
 {
 	struct sock_iocb *si = kiocb_to_siocb(iocb);
+	int ret;
 
 	sock_update_classid(sock->sk);
 
@@ -723,7 +728,10 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 	si->size = size;
 	si->flags = flags;
 
-	return sock->ops->recvmsg(iocb, sock, msg, size, flags);
+	ret = sock->ops->recvmsg(iocb, sock, msg, size, flags);
+	task_net_accounting_rx(ret);
+
+	return ret;
 }
 
 static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -823,13 +831,17 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 				unsigned int flags)
 {
 	struct socket *sock = file->private_data;
+	int ret;
 
 	if (unlikely(!sock->ops->splice_read))
 		return -EINVAL;
 
 	sock_update_classid(sock->sk);
 
-	return sock->ops->splice_read(sock, ppos, pipe, len, flags);
+	ret = sock->ops->splice_read(sock, ppos, pipe, len, flags);
+	task_net_accounting_rx(ret);
+
+	return ret;
 }
 
 static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
@@ -3361,10 +3373,15 @@ EXPORT_SYMBOL(kernel_setsockopt);
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
 		    size_t size, int flags)
 {
+	int ret;
+
 	sock_update_classid(sock->sk);
 
-	if (sock->ops->sendpage)
-		return sock->ops->sendpage(sock, page, offset, size, flags);
+	if (sock->ops->sendpage) {
+		ret = sock->ops->sendpage(sock, page, offset, size, flags);
+		task_net_accounting_tx(ret);
+		return ret;
+	}
 
 	return sock_no_sendpage(sock, page, offset, size, flags);
 }
#3 lore raw
Quoted 12 lines · Li Yu

This patch adds L7 traffic accounting in taskstats API, so the iotop like applications can receive these statistics data. In fact, I also have an iotop patch for this change.

It ignores any protocol header overhead, so results of this patch should be saw as the applications-aware data statistics instead of traffic statistics on wire.

The changes of v2 are:

1. Move up accounting source code, so they are not protocol-aware now.
2. Skipping interrupt context accounting.

[...]

Quoted 8 lines
include/net/sock.h +1 -0
@@ -1735,6 +1735,18 @@ static inline int skb_copy_to_page(struct sock 
 *sk, char __user *from,
  	return 0;
  }
 
+static inline void task_net_accounting_rx(unsigned int len)

include/net/sock.h static inline int skb_copy_to_page(struct sock · line 1749

Quoted 10 lines
include/net/sock.h +10 -0
+{
+	if (!in_irq() && len > 0)
+		current->rx_bytes += len;
+}
+
+static inline void task_net_accounting_tx(unsigned int len)
+{
+	if (!in_irq() && len > 0)
+		current->tx_bytes += len;
+}

[...]

These are only called from system calls, so why are you checking for IRQ context?

include/net/sock.h static inline int __sock_sendmsg_nosec(struct kiocb · line 567

Quoted 11 lines
include/net/sock.h +4 -1
@@ -558,7 +559,10 @@ static inline int __sock_sendmsg_nosec(struct kiocb 
 *iocb, struct socket *sock,
  	si->msg = msg;
  	si->size = size;
 
-	return sock->ops->sendmsg(iocb, sock, msg, size);
+	ret = sock->ops->sendmsg(iocb, sock, msg, size);
+	task_net_accounting_tx(ret);
+
+	return ret;
  }

[...]

So what happens to the totals when sendmsg() returns an error?

It seems to me that the parameter type for the accounting functions should be ssize_t.

Ben.

Signature · 3 lines
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
author
#4 lore raw
Quoted 34 lines · Ben Hutchings
Quoted 12 lines · Li Yu

This patch adds L7 traffic accounting in taskstats API, so the iotop like applications can receive these statistics data. In fact, I also have an iotop patch for this change.

It ignores any protocol header overhead, so results of this patch should be saw as the applications-aware data statistics instead of traffic statistics on wire.

The changes of v2 are:

1. Move up accounting source code, so they are not protocol-aware now.
2. Skipping interrupt context accounting.

[...]

Quoted 18 lines
include/net/sock.h +11 -0
@@ -1735,6 +1735,18 @@ static inline int skb_copy_to_page(struct sock
 *sk, char __user *from,
   	return 0;
   }
 
+static inline void task_net_accounting_rx(unsigned int len)
+{
+	if (!in_irq()&&  len>  0)
+		current->rx_bytes += len;
+}
+
+static inline void task_net_accounting_tx(unsigned int len)
+{
+	if (!in_irq()&&  len>  0)
+		current->tx_bytes += len;
+}

[...]

Quoted 3 lines

These are only called from system calls, so why are you checking for IRQ context?

Some caller are exported symbols or in exported symbols path, so I think that we'd best that do not assume that such symbols only work at process context, it may be used by some kernel modules in softirq context.

However, faint, the 'len' should be signed int type.

Quoted 13 lines
Quoted 11 lines
include/net/sock.h +4 -1
@@ -558,7 +559,10 @@ static inline int __sock_sendmsg_nosec(struct kiocb
 *iocb, struct socket *sock,
   	si->msg = msg;
   	si->size = size;
 
-	return sock->ops->sendmsg(iocb, sock, msg, size);
+	ret = sock->ops->sendmsg(iocb, sock, msg, size);
+	task_net_accounting_tx(ret);
+
+	return ret;
   }

[...]

Quoted 5 lines

So what happens to the totals when sendmsg() returns an error?

It seems to me that the parameter type for the accounting functions should be ssize_t.

En, I think that "int" is enough here at least, the return type of __sock_sendmsg_nosec() also is int ...

Thanks

Yu

Quoted 2 lines

Ben.

author
#5 lore raw

PATCH v3 1/1 extend taskstats API to support networking accounts

In reply to David Miller

This patch adds L7 traffic accounting in taskstats API, so the iotop like applications can receive these statistics data. In fact, I also have an iotop patch for this change.

It ignores any protocol header overhead, so results of this patch should be saw as the applications-aware data statistics instead of traffic statistics on wire.

The changes of v3 are:

1. Fix unsigned type of parameter of task_net_accounting_tx/rx()

That is all, hope this is ready to merge.

Thanks.

 include/linux/sched.h     |    2 ++
 include/linux/taskstats.h |    7 ++++++-
 include/net/sock.h        |   12 ++++++++++++
 kernel/fork.c             |    1 +
 kernel/taskstats.c        |    6 ++++++
 net/socket.c              |   27 ++++++++++++++++++++++-----
 6 files changed, 49 insertions(+), 6 deletions(-)
include/linux/sched.h +2 -0
index 7d379a6..5b2dbc5 100644
@@ -1590,6 +1590,8 @@ struct task_struct {
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
 	atomic_t ptrace_bp_refcnt;
 #endif
+       u64 rx_bytes;
+       u64 tx_bytes;
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */
include/linux/taskstats.h +6 -1
index 2466e55..39b356c 100644
@@ -33,7 +33,7 @@
  */
 
 
-#define TASKSTATS_VERSION	8
+#define TASKSTATS_VERSION	9
 #define TS_COMM_LEN		32	/* should be >= TASK_COMM_LEN
 					 * in linux/sched.h */
 
@@ -163,6 +163,11 @@ struct taskstats {
 	/* Delay waiting for memory reclaim */
 	__u64	freepages_count;
 	__u64	freepages_delay_total;
+	 /* Version 8 ends here */
+
+	/* Net accounting */
+	__u64   rx_bytes;
+	__u64   tx_bytes;
 };
 
 
include/net/sock.h +12 -0
index 91c1c8b..1f52c2a 100644
@@ -1735,6 +1735,18 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
 	return 0;
 }
 
+static inline void task_net_accounting_rx(int len)
+{
+	if (!in_irq() && len > 0)
+		current->rx_bytes += len;
+}
+
+static inline void task_net_accounting_tx(int len)
+{
+	if (!in_irq() && len > 0)
+		current->tx_bytes += len;
+}
+
 /**
  * sk_wmem_alloc_get - returns write allocations
  * @sk: socket
kernel/fork.c +1 -0
index b77fd55..5788f3e 100644
@@ -1168,6 +1168,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	p->default_timer_slack_ns = current->timer_slack_ns;
 
 	task_io_accounting_init(&p->ioac);
+	p->rx_bytes = p->tx_bytes = 0;
 	acct_clear_integrals(p);
 
 	posix_cpu_timers_init(p);
kernel/taskstats.c +6 -0
index e660464..4d1fcd2 100644
@@ -194,6 +194,9 @@ static void fill_stats(struct task_struct *tsk, struct taskstats *stats)
 
 	/* fill in extended acct fields */
 	xacct_add_tsk(stats, tsk);
+
+	stats->rx_bytes = tsk->rx_bytes;
+	stats->tx_bytes = tsk->tx_bytes;
 }
 
 static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
@@ -247,6 +250,9 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
 
 		stats->nvcsw += tsk->nvcsw;
 		stats->nivcsw += tsk->nivcsw;
+
+		stats->rx_bytes += tsk->rx_bytes;
+		stats->tx_bytes += tsk->tx_bytes;
 	} while_each_thread(first, tsk);
 
 	unlock_task_sighand(first, &flags);
net/socket.c +22 -5
index 28a96af..c1b736d 100644
@@ -548,6 +548,7 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 				       struct msghdr *msg, size_t size)
 {
 	struct sock_iocb *si = kiocb_to_siocb(iocb);
+	int ret;
 
 	sock_update_classid(sock->sk);
 
@@ -558,7 +559,10 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 	si->msg = msg;
 	si->size = size;
 
-	return sock->ops->sendmsg(iocb, sock, msg, size);
+	ret = sock->ops->sendmsg(iocb, sock, msg, size);
+	task_net_accounting_tx(ret);
+
+	return ret;
 }
 
 static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
@@ -714,6 +718,7 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 				       struct msghdr *msg, size_t size, int flags)
 {
 	struct sock_iocb *si = kiocb_to_siocb(iocb);
+	int ret;
 
 	sock_update_classid(sock->sk);
 
@@ -723,7 +728,10 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
 	si->size = size;
 	si->flags = flags;
 
-	return sock->ops->recvmsg(iocb, sock, msg, size, flags);
+	ret = sock->ops->recvmsg(iocb, sock, msg, size, flags);
+	task_net_accounting_rx(ret);
+
+	return ret;
 }
 
 static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -823,13 +831,17 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 				unsigned int flags)
 {
 	struct socket *sock = file->private_data;
+	int ret;
 
 	if (unlikely(!sock->ops->splice_read))
 		return -EINVAL;
 
 	sock_update_classid(sock->sk);
 
-	return sock->ops->splice_read(sock, ppos, pipe, len, flags);
+	ret = sock->ops->splice_read(sock, ppos, pipe, len, flags);
+	task_net_accounting_rx(ret);
+
+	return ret;
 }
 
 static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
@@ -3361,10 +3373,15 @@ EXPORT_SYMBOL(kernel_setsockopt);
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
 		    size_t size, int flags)
 {
+	int ret;
+
 	sock_update_classid(sock->sk);
 
-	if (sock->ops->sendpage)
-		return sock->ops->sendpage(sock, page, offset, size, flags);
+	if (sock->ops->sendpage) {
+		ret = sock->ops->sendpage(sock, page, offset, size, flags);
+		task_net_accounting_tx(ret);
+		return ret;
+	}
 
 	return sock_no_sendpage(sock, page, offset, size, flags);
 }
maintainer
#6 lore raw

Your patch was severely corrupted by your email client, making it unusable for us.

Test email the patch to youself, and do not resubmit this patch to us until the patch you receive you can actually apply cleanly.