900-gen_stats-fix-netlink-stats-padding.patch 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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. However, on architectures that need padding (i.e., that don't set
  7. CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added
  8. before the stats, which means that the stored pointer will point to the
  9. padding, and so when the header is fixed up, the result is just a very
  10. big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS
  11. struct, this problem has been mostly invisible, but we exposed it with
  12. the netlink attribute-based statistics in CAKE.
  13. Fix the issue by fixing up the stored pointer if it points to a padding
  14. nlattr.
  15. Tested-by: Pete Heist <[email protected]>
  16. Tested-by: Kevin Darbyshire-Bryant <[email protected]>
  17. Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
  18. ---
  19. net/core/gen_stats.c | 16 ++++++++++++++--
  20. 1 file changed, 14 insertions(+), 2 deletions(-)
  21. --- a/net/core/gen_stats.c
  22. +++ b/net/core/gen_stats.c
  23. @@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_b
  24. d->lock = lock;
  25. spin_lock_bh(lock);
  26. }
  27. - if (d->tail)
  28. - return gnet_stats_copy(d, type, NULL, 0, padattr);
  29. + if (d->tail) {
  30. + int ret = gnet_stats_copy(d, type, NULL, 0, padattr);
  31. +
  32. + /* The initial attribute added in gnet_stats_copy() may be
  33. + * preceded by a padding attribute, in which case d->tail will
  34. + * end up pointing at the padding instead of the real attribute.
  35. + * Fix this so gnet_stats_finish_copy() adjusts the length of
  36. + * the right attribute.
  37. + */
  38. + if (ret == 0 && d->tail->nla_type == padattr)
  39. + d->tail = (struct nlattr *)((char *)d->tail +
  40. + NLA_ALIGN(d->tail->nla_len));
  41. + return ret;
  42. + }
  43. return 0;
  44. }