|
|
@@ -0,0 +1,49 @@
|
|
|
+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 <[email protected]>
|
|
|
+Tested-by: Kevin Darbyshire-Bryant <[email protected]>
|
|
|
+Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
|
|
|
+---
|
|
|
+ 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;
|
|
|
+ }
|