kernel: backport mtd support for subpartitions in DT
[oweals/openwrt.git] / target / linux / generic / pending-4.14 / 900-gen_stats-fix-netlink-stats-padding.patch
1 The gen_stats facility will add a header for the toplevel nlattr of type
2 TCA_STATS2 that contains all stats added by qdisc callbacks. A reference
3 to this header is stored in the gnet_dump struct, and when all the
4 per-qdisc callbacks have finished adding their stats, the length of the
5 containing header will be adjusted to the right value.
6
7 However, on architectures that need padding (i.e., that don't set
8 CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added
9 before the stats, which means that the stored pointer will point to the
10 padding, and so when the header is fixed up, the result is just a very
11 big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS
12 struct, this problem has been mostly invisible, but we exposed it with
13 the netlink attribute-based statistics in CAKE.
14
15 Fix the issue by fixing up the stored pointer if it points to a padding
16 nlattr.
17
18 Tested-by: Pete Heist <pete@heistp.net>
19 Tested-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
20 Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
21 ---
22  net/core/gen_stats.c |   16 ++++++++++++++--
23  1 file changed, 14 insertions(+), 2 deletions(-)
24
25 --- a/net/core/gen_stats.c
26 +++ b/net/core/gen_stats.c
27 @@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_b
28                 d->lock = lock;
29                 spin_lock_bh(lock);
30         }
31 -       if (d->tail)
32 -               return gnet_stats_copy(d, type, NULL, 0, padattr);
33 +       if (d->tail) {
34 +               int ret = gnet_stats_copy(d, type, NULL, 0, padattr);
35 +
36 +               /* The initial attribute added in gnet_stats_copy() may be
37 +                * preceded by a padding attribute, in which case d->tail will
38 +                * end up pointing at the padding instead of the real attribute.
39 +                * Fix this so gnet_stats_finish_copy() adjusts the length of
40 +                * the right attribute.
41 +                */
42 +               if (ret == 0 && d->tail->nla_type == padattr)
43 +                       d->tail = (struct nlattr *)((char *)d->tail +
44 +                                                   NLA_ALIGN(d->tail->nla_len));
45 +               return ret;
46 +       }
47  
48         return 0;
49  }