50 lines
1.9 KiB
Diff
50 lines
1.9 KiB
Diff
|
The gen_stats facility will add a header for the toplevel nlattr of type
|
||
|
TCA_STATS2 that contains all stats added by qdisc callbacks. A reference
|
||
|
to this header is stored in the gnet_dump struct, and when all the
|
||
|
per-qdisc callbacks have finished adding their stats, the length of the
|
||
|
containing header will be adjusted to the right value.
|
||
|
|
||
|
However, on architectures that need padding (i.e., that don't set
|
||
|
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added
|
||
|
before the stats, which means that the stored pointer will point to the
|
||
|
padding, and so when the header is fixed up, the result is just a very
|
||
|
big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS
|
||
|
struct, this problem has been mostly invisible, but we exposed it with
|
||
|
the netlink attribute-based statistics in CAKE.
|
||
|
|
||
|
Fix the issue by fixing up the stored pointer if it points to a padding
|
||
|
nlattr.
|
||
|
|
||
|
Tested-by: Pete Heist <pete@heistp.net>
|
||
|
Tested-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
|
||
|
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||
|
---
|
||
|
net/core/gen_stats.c | 16 ++++++++++++++--
|
||
|
1 file changed, 14 insertions(+), 2 deletions(-)
|
||
|
|
||
|
--- a/net/core/gen_stats.c
|
||
|
+++ b/net/core/gen_stats.c
|
||
|
@@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_b
|
||
|
d->lock = lock;
|
||
|
spin_lock_bh(lock);
|
||
|
}
|
||
|
- if (d->tail)
|
||
|
- return gnet_stats_copy(d, type, NULL, 0, padattr);
|
||
|
+ if (d->tail) {
|
||
|
+ int ret = gnet_stats_copy(d, type, NULL, 0, padattr);
|
||
|
+
|
||
|
+ /* The initial attribute added in gnet_stats_copy() may be
|
||
|
+ * preceded by a padding attribute, in which case d->tail will
|
||
|
+ * end up pointing at the padding instead of the real attribute.
|
||
|
+ * Fix this so gnet_stats_finish_copy() adjusts the length of
|
||
|
+ * the right attribute.
|
||
|
+ */
|
||
|
+ if (ret == 0 && d->tail->nla_type == padattr)
|
||
|
+ d->tail = (struct nlattr *)((char *)d->tail +
|
||
|
+ NLA_ALIGN(d->tail->nla_len));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
|
||
|
return 0;
|
||
|
}
|