aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>2018-07-02 18:27:02 +0100
committerKevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>2018-07-03 11:40:18 +0100
commit3698b34a00d623f87a41179e656b8e89d0bb7267 (patch)
tree2c93680941644797e7cfc9ee5766e2705416df26
parent09b6755946409d8fd8e95fab003f037ae026f04b (diff)
downloadupstream-3698b34a00d623f87a41179e656b8e89d0bb7267.tar.gz
upstream-3698b34a00d623f87a41179e656b8e89d0bb7267.tar.bz2
upstream-3698b34a00d623f87a41179e656b8e89d0bb7267.zip
kernel: gen_stats: Fix netlink stats dumping in the presence of padding
Backport hot off the press upstream netlink patch. Fixes stats display from CAKE qdisc on MIPS allowing us to bump CAKE to latest version. 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. Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
-rw-r--r--target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch49
-rw-r--r--target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch49
2 files changed, 98 insertions, 0 deletions
diff --git a/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch b/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch
new file mode 100644
index 0000000000..f5ceecca93
--- /dev/null
+++ b/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch
@@ -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 <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;
+ }
diff --git a/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch b/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch
new file mode 100644
index 0000000000..f5ceecca93
--- /dev/null
+++ b/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch
@@ -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 <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;
+ }