Commit c1a8f1f1 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: restore gnet_stats_basic to previous definition

In 5e140dfc "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: default avatarMichael Spang <mspang@csclub.uwaterloo.ca>
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c6ba973b
...@@ -19,6 +19,11 @@ enum { ...@@ -19,6 +19,11 @@ enum {
* @packets: number of seen packets * @packets: number of seen packets
*/ */
struct gnet_stats_basic struct gnet_stats_basic
{
__u64 bytes;
__u32 packets;
};
struct gnet_stats_basic_packed
{ {
__u64 bytes; __u64 bytes;
__u32 packets; __u32 packets;
......
...@@ -16,7 +16,7 @@ struct tcf_common { ...@@ -16,7 +16,7 @@ struct tcf_common {
u32 tcfc_capab; u32 tcfc_capab;
int tcfc_action; int tcfc_action;
struct tcf_t tcfc_tm; 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_queue tcfc_qstats;
struct gnet_stats_rate_est tcfc_rate_est; struct gnet_stats_rate_est tcfc_rate_est;
spinlock_t tcfc_lock; spinlock_t tcfc_lock;
......
...@@ -28,7 +28,7 @@ extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, ...@@ -28,7 +28,7 @@ extern int gnet_stats_start_copy_compat(struct sk_buff *skb, int type,
spinlock_t *lock, struct gnet_dump *d); spinlock_t *lock, struct gnet_dump *d);
extern int gnet_stats_copy_basic(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, extern int gnet_stats_copy_rate_est(struct gnet_dump *d,
struct gnet_stats_rate_est *r); struct gnet_stats_rate_est *r);
extern int gnet_stats_copy_queue(struct gnet_dump *d, 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); ...@@ -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 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, struct gnet_stats_rate_est *rate_est,
spinlock_t *stats_lock, struct nlattr *opt); 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); 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, struct gnet_stats_rate_est *rate_est,
spinlock_t *stats_lock, struct nlattr *opt); 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); const struct gnet_stats_rate_est *rate_est);
#endif #endif
...@@ -8,7 +8,7 @@ struct xt_rateest { ...@@ -8,7 +8,7 @@ struct xt_rateest {
spinlock_t lock; spinlock_t lock;
struct gnet_estimator params; struct gnet_estimator params;
struct gnet_stats_rate_est rstats; 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); extern struct xt_rateest *xt_rateest_lookup(const char *name);
......
...@@ -72,7 +72,7 @@ struct Qdisc ...@@ -72,7 +72,7 @@ struct Qdisc
*/ */
unsigned long state; unsigned long state;
struct sk_buff_head q; struct sk_buff_head q;
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
}; };
......
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
struct gen_estimator struct gen_estimator
{ {
struct list_head list; struct list_head list;
struct gnet_stats_basic *bstats; struct gnet_stats_basic_packed *bstats;
struct gnet_stats_rate_est *rate_est; struct gnet_stats_rate_est *rate_est;
spinlock_t *stats_lock; spinlock_t *stats_lock;
int ewma_log; int ewma_log;
...@@ -165,7 +165,7 @@ static void gen_add_node(struct gen_estimator *est) ...@@ -165,7 +165,7 @@ static void gen_add_node(struct gen_estimator *est)
} }
static 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) const struct gnet_stats_rate_est *rate_est)
{ {
struct rb_node *p = est_root.rb_node; struct rb_node *p = est_root.rb_node;
...@@ -202,7 +202,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats, ...@@ -202,7 +202,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats,
* *
* NOTE: Called under rtnl_mutex * 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, struct gnet_stats_rate_est *rate_est,
spinlock_t *stats_lock, spinlock_t *stats_lock,
struct nlattr *opt) struct nlattr *opt)
...@@ -262,7 +262,7 @@ static void __gen_kill_estimator(struct rcu_head *head) ...@@ -262,7 +262,7 @@ static void __gen_kill_estimator(struct rcu_head *head)
* *
* NOTE: Called under rtnl_mutex * 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 gnet_stats_rate_est *rate_est)
{ {
struct gen_estimator *e; struct gen_estimator *e;
...@@ -292,7 +292,7 @@ EXPORT_SYMBOL(gen_kill_estimator); ...@@ -292,7 +292,7 @@ EXPORT_SYMBOL(gen_kill_estimator);
* *
* Returns 0 on success or a negative error code. * 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, struct gnet_stats_rate_est *rate_est,
spinlock_t *stats_lock, struct nlattr *opt) spinlock_t *stats_lock, struct nlattr *opt)
{ {
...@@ -308,7 +308,7 @@ EXPORT_SYMBOL(gen_replace_estimator); ...@@ -308,7 +308,7 @@ EXPORT_SYMBOL(gen_replace_estimator);
* *
* Returns true if estimator is active, and false if not. * 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) const struct gnet_stats_rate_est *rate_est)
{ {
ASSERT_RTNL(); ASSERT_RTNL();
......
...@@ -106,16 +106,21 @@ gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, ...@@ -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. * if the room in the socket buffer was not sufficient.
*/ */
int 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) { if (d->compat_tc_stats) {
d->tc_stats.bytes = b->bytes; d->tc_stats.bytes = b->bytes;
d->tc_stats.packets = b->packets; d->tc_stats.packets = b->packets;
} }
if (d->tail) if (d->tail) {
return gnet_stats_copy(d, TCA_STATS_BASIC, b, sizeof(*b)); 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; return 0;
} }
......
...@@ -74,7 +74,7 @@ static unsigned int ...@@ -74,7 +74,7 @@ static unsigned int
xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par) xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
{ {
const struct xt_rateest_target_info *info = par->targinfo; 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); spin_lock_bh(&info->est->lock);
stats->bytes += skb->len; stats->bytes += skb->len;
......
...@@ -49,7 +49,7 @@ struct atm_flow_data { ...@@ -49,7 +49,7 @@ struct atm_flow_data {
struct socket *sock; /* for closing */ struct socket *sock; /* for closing */
u32 classid; /* x:y type ID */ u32 classid; /* x:y type ID */
int ref; /* reference count */ int ref; /* reference count */
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct atm_flow_data *next; struct atm_flow_data *next;
struct atm_flow_data *excess; /* flow for excess traffic; struct atm_flow_data *excess; /* flow for excess traffic;
......
...@@ -128,7 +128,7 @@ struct cbq_class ...@@ -128,7 +128,7 @@ struct cbq_class
long avgidle; long avgidle;
long deficit; /* Saved deficit for WRR */ long deficit; /* Saved deficit for WRR */
psched_time_t penalized; psched_time_t penalized;
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est rate_est;
struct tc_cbq_xstats xstats; struct tc_cbq_xstats xstats;
......
...@@ -22,7 +22,7 @@ struct drr_class { ...@@ -22,7 +22,7 @@ struct drr_class {
unsigned int refcnt; unsigned int refcnt;
unsigned int filter_cnt; unsigned int filter_cnt;
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est rate_est;
struct list_head alist; struct list_head alist;
......
...@@ -116,7 +116,7 @@ struct hfsc_class ...@@ -116,7 +116,7 @@ struct hfsc_class
struct Qdisc_class_common cl_common; struct Qdisc_class_common cl_common;
unsigned int refcnt; /* usage count */ unsigned int refcnt; /* usage count */
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est rate_est;
unsigned int level; /* class level in hierarchy */ unsigned int level; /* class level in hierarchy */
......
...@@ -74,7 +74,7 @@ enum htb_cmode { ...@@ -74,7 +74,7 @@ enum htb_cmode {
struct htb_class { struct htb_class {
struct Qdisc_class_common common; struct Qdisc_class_common common;
/* general class parameters */ /* general class parameters */
struct gnet_stats_basic bstats; struct gnet_stats_basic_packed bstats;
struct gnet_stats_queue qstats; struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est; struct gnet_stats_rate_est rate_est;
struct tc_htb_xstats xstats; /* our special stats */ struct tc_htb_xstats xstats; /* our special stats */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment