net: restore gnet_stats_basic to previous definition
authorEric Dumazet <eric.dumazet@gmail.com>
Sun, 16 Aug 2009 09:36:49 +0000 (09:36 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 18 Aug 2009 04:33:49 +0000 (21:33 -0700)
In 5e140dfc1fe87eae27846f193086724806b33c7d "net: reorder struct Qdisc
for better SMP performance" the definition of struct gnet_stats_basic
changed incompatibly, as copies of this struct are shipped to
userland via netlink.

Restoring old behavior is not welcome, for performance reason.

Fix is to use a private structure for kernel, and
teach gnet_stats_copy_basic() to convert from kernel to user land,
using legacy structure (struct gnet_stats_basic)

Based on a report and initial patch from Michael Spang.

Reported-by: Michael Spang <mspang@csclub.uwaterloo.ca>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
13 files changed:
include/linux/gen_stats.h
include/net/act_api.h
include/net/gen_stats.h
include/net/netfilter/xt_rateest.h
include/net/sch_generic.h
net/core/gen_estimator.c
net/core/gen_stats.c
net/netfilter/xt_RATEEST.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c

index 0ffa41df0ee8ca007d9cda5b40fdbe315ee0a845..710e901085d0237195ca7a3d30b91b537287dc77 100644 (file)
@@ -19,6 +19,11 @@ enum {
  * @packets: number of seen packets
  */
 struct gnet_stats_basic
+{
+       __u64   bytes;
+       __u32   packets;
+};
+struct gnet_stats_basic_packed
 {
        __u64   bytes;
        __u32   packets;
index 565eed8fe496d55c81c3454564eb5605e27afd71..c05fd717c588801a72c4fe7a18a000b4bf46e35c 100644 (file)
@@ -16,7 +16,7 @@ struct tcf_common {
        u32                             tcfc_capab;
        int                             tcfc_action;
        struct tcf_t                    tcfc_tm;
-       struct gnet_stats_basic         tcfc_bstats;
+       struct gnet_stats_basic_packed  tcfc_bstats;
        struct gnet_stats_queue         tcfc_qstats;
        struct gnet_stats_rate_est      tcfc_rate_est;
        spinlock_t                      tcfc_lock;
index d136b5240ef24a2e41cb6843b27d724295b4b9d3..c1488553e34964b9dbd4a3a66334d4c1f04f16bd 100644 (file)
@@ -28,7 +28,7 @@ extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type,
                                        spinlock_t *lock, struct gnet_dump *d);
 
 extern int gnet_stats_copy_basic(struct gnet_dump *d,
-                                struct gnet_stats_basic *b);
+                                struct gnet_stats_basic_packed *b);
 extern int gnet_stats_copy_rate_est(struct gnet_dump *d,
                                    struct gnet_stats_rate_est *r);
 extern int gnet_stats_copy_queue(struct gnet_dump *d,
@@ -37,14 +37,14 @@ extern int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len);
 
 extern int gnet_stats_finish_copy(struct gnet_dump *d);
 
-extern int gen_new_estimator(struct gnet_stats_basic *bstats,
+extern int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
                             struct gnet_stats_rate_est *rate_est,
                             spinlock_t *stats_lock, struct nlattr *opt);
-extern void gen_kill_estimator(struct gnet_stats_basic *bstats,
+extern void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
                               struct gnet_stats_rate_est *rate_est);
-extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
+extern int gen_replace_estimator(struct gnet_stats_basic_packed *bstats,
                                 struct gnet_stats_rate_est *rate_est,
                                 spinlock_t *stats_lock, struct nlattr *opt);
-extern bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+extern bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats,
                                 const struct gnet_stats_rate_est *rate_est);
 #endif
index 65d594dffbff431e35a0ac7ec29a051bb022c8b6..ddbf37e19616a486b73b15a7e5314c47e1ed80a8 100644 (file)
@@ -8,7 +8,7 @@ struct xt_rateest {
        spinlock_t                      lock;
        struct gnet_estimator           params;
        struct gnet_stats_rate_est      rstats;
-       struct gnet_stats_basic         bstats;
+       struct gnet_stats_basic_packed  bstats;
 };
 
 extern struct xt_rateest *xt_rateest_lookup(const char *name);
index 964ffa0d8815139ae22d351590b5673a4dd38850..5482e9582f555ea9bae1d2a8e5f42bd571f97819 100644 (file)
@@ -72,7 +72,7 @@ struct Qdisc
         */
        unsigned long           state;
        struct sk_buff_head     q;
-       struct gnet_stats_basic bstats;
+       struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
 };
 
index 78e5bfc454ae00e627705515cbd857cd3d9c67d9..493775f4f2f1d7c19b618640e186aae7195ded53 100644 (file)
@@ -81,7 +81,7 @@
 struct gen_estimator
 {
        struct list_head        list;
-       struct gnet_stats_basic *bstats;
+       struct gnet_stats_basic_packed  *bstats;
        struct gnet_stats_rate_est      *rate_est;
        spinlock_t              *stats_lock;
        int                     ewma_log;
@@ -165,7 +165,7 @@ static void gen_add_node(struct gen_estimator *est)
 }
 
 static
-struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats,
+struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats,
                                    const struct gnet_stats_rate_est *rate_est)
 {
        struct rb_node *p = est_root.rb_node;
@@ -202,7 +202,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats,
  *
  * NOTE: Called under rtnl_mutex
  */
-int gen_new_estimator(struct gnet_stats_basic *bstats,
+int gen_new_estimator(struct gnet_stats_basic_packed *bstats,
                      struct gnet_stats_rate_est *rate_est,
                      spinlock_t *stats_lock,
                      struct nlattr *opt)
@@ -262,7 +262,7 @@ static void __gen_kill_estimator(struct rcu_head *head)
  *
  * NOTE: Called under rtnl_mutex
  */
-void gen_kill_estimator(struct gnet_stats_basic *bstats,
+void gen_kill_estimator(struct gnet_stats_basic_packed *bstats,
                        struct gnet_stats_rate_est *rate_est)
 {
        struct gen_estimator *e;
@@ -292,7 +292,7 @@ EXPORT_SYMBOL(gen_kill_estimator);
  *
  * Returns 0 on success or a negative error code.
  */
-int gen_replace_estimator(struct gnet_stats_basic *bstats,
+int gen_replace_estimator(struct gnet_stats_basic_packed *bstats,
                          struct gnet_stats_rate_est *rate_est,
                          spinlock_t *stats_lock, struct nlattr *opt)
 {
@@ -308,7 +308,7 @@ EXPORT_SYMBOL(gen_replace_estimator);
  *
  * Returns true if estimator is active, and false if not.
  */
-bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats,
                          const struct gnet_stats_rate_est *rate_est)
 {
        ASSERT_RTNL();
index c3d0ffeac24342417bca0017e3d55e7c05100018..8569310268ab76ba786402e6b2e6dc994621a7fd 100644 (file)
@@ -106,16 +106,21 @@ gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock,
  * if the room in the socket buffer was not sufficient.
  */
 int
-gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic *b)
+gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
 {
        if (d->compat_tc_stats) {
                d->tc_stats.bytes = b->bytes;
                d->tc_stats.packets = b->packets;
        }
 
-       if (d->tail)
-               return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b));
+       if (d->tail) {
+               struct gnet_stats_basic sb;
 
+               memset(&sb, 0, sizeof(sb));
+               sb.bytes = b->bytes;
+               sb.packets = b->packets;
+               return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb));
+       }
        return 0;
 }
 
index 43f5676b1af405d1a0c12a374710ae543d06346a..d80b8192e0d423a2f66ec27ea06efbcaf174d681 100644 (file)
@@ -74,7 +74,7 @@ static unsigned int
 xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
 {
        const struct xt_rateest_target_info *info = par->targinfo;
-       struct gnet_stats_basic *stats = &info->est->bstats;
+       struct gnet_stats_basic_packed *stats = &info->est->bstats;
 
        spin_lock_bh(&info->est->lock);
        stats->bytes += skb->len;
index 2a8b83af7c47a4bbee4471cc62894d46ca1d233a..ab82f145f68937a9c722322517fd2dd479550db0 100644 (file)
@@ -49,7 +49,7 @@ struct atm_flow_data {
        struct socket           *sock;          /* for closing */
        u32                     classid;        /* x:y type ID */
        int                     ref;            /* reference count */
-       struct gnet_stats_basic bstats;
+       struct gnet_stats_basic_packed  bstats;
        struct gnet_stats_queue qstats;
        struct atm_flow_data    *next;
        struct atm_flow_data    *excess;        /* flow for excess traffic;
index 23a167670fd5f11ed1affcfb07b9ad766b381b81..d5798e17a83205f3a44ac09d3c4b5318801d24d4 100644 (file)
@@ -128,7 +128,7 @@ struct cbq_class
        long                    avgidle;
        long                    deficit;        /* Saved deficit for WRR */
        psched_time_t           penalized;
-       struct gnet_stats_basic bstats;
+       struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est rate_est;
        struct tc_cbq_xstats    xstats;
index 7597fe14686600e6fa2584544b69ebdfb1144edf..12b2fb04b29b6d4d873e6fe28981dabd7de039b6 100644 (file)
@@ -22,7 +22,7 @@ struct drr_class {
        unsigned int                    refcnt;
        unsigned int                    filter_cnt;
 
-       struct gnet_stats_basic         bstats;
+       struct gnet_stats_basic_packed          bstats;
        struct gnet_stats_queue         qstats;
        struct gnet_stats_rate_est      rate_est;
        struct list_head                alist;
index 362c2811b2dfe95b93daf0d3f10cf98a06373cd6..dad0144423da5a87be4d18c76333cca56f05af84 100644 (file)
@@ -116,7 +116,7 @@ struct hfsc_class
        struct Qdisc_class_common cl_common;
        unsigned int    refcnt;         /* usage count */
 
-       struct gnet_stats_basic bstats;
+       struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est rate_est;
        unsigned int    level;          /* class level in hierarchy */
index 88cd0262662138f02fa18393a72667fc172e91c1..ec4d46399d59fbdfa638394b54136a294bf200bc 100644 (file)
@@ -74,7 +74,7 @@ enum htb_cmode {
 struct htb_class {
        struct Qdisc_class_common common;
        /* general class parameters */
-       struct gnet_stats_basic bstats;
+       struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est rate_est;
        struct tc_htb_xstats xstats;    /* our special stats */