Commit 00e11c5f authored by David S. Miller's avatar David S. Miller

[PKT_SCHED]: Do not embed spinlock in tc_stats structure.

This makes it not get sized/copied around to/from
userspace correctly.  The real crux of the problem
comes from the rtnetlink attribute copying line which
read:
	RTA_PUT(skb, TCA_STATS, (char*)&st->lock - (char*)st, st);
which is not necessarily sizeof(struct tc_stats) due
to alignment issues.
parent 18c9628e
...@@ -38,9 +38,6 @@ struct tc_stats ...@@ -38,9 +38,6 @@ struct tc_stats
__u32 pps; /* Current flow packet rate */ __u32 pps; /* Current flow packet rate */
__u32 qlen; __u32 qlen;
__u32 backlog; __u32 backlog;
#ifdef __KERNEL__
spinlock_t *lock;
#endif
}; };
struct tc_estimator struct tc_estimator
......
...@@ -258,7 +258,7 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int ...@@ -258,7 +258,7 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int
p->tm.lastuse = jiffies; p->tm.lastuse = jiffies;
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (est) { if (est) {
qdisc_new_estimator(&p->stats, est); qdisc_new_estimator(&p->stats, p->stats_lock, est);
} }
#endif #endif
h = tcf_hash(p->index); h = tcf_hash(p->index);
......
...@@ -96,6 +96,7 @@ struct Qdisc ...@@ -96,6 +96,7 @@ struct Qdisc
struct net_device *dev; struct net_device *dev;
struct tc_stats stats; struct tc_stats stats;
spinlock_t *stats_lock;
struct rcu_head q_rcu; struct rcu_head q_rcu;
int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q); int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q);
...@@ -376,6 +377,7 @@ struct tcf_police ...@@ -376,6 +377,7 @@ struct tcf_police
struct qdisc_rate_table *P_tab; struct qdisc_rate_table *P_tab;
struct tc_stats stats; struct tc_stats stats;
spinlock_t *stats_lock;
}; };
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
...@@ -391,6 +393,7 @@ struct tcf_##name *next; \ ...@@ -391,6 +393,7 @@ struct tcf_##name *next; \
int action; \ int action; \
struct tcf_t tm; \ struct tcf_t tm; \
struct tc_stats stats; \ struct tc_stats stats; \
spinlock_t *stats_lock; \
spinlock_t lock spinlock_t lock
...@@ -436,7 +439,7 @@ extern int tcf_act_police(struct sk_buff **skb, struct tc_action *a); ...@@ -436,7 +439,7 @@ extern int tcf_act_police(struct sk_buff **skb, struct tc_action *a);
#endif #endif
extern int tcf_police(struct sk_buff *skb, struct tcf_police *p); extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st); extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st, spinlock_t *lock);
extern void tcf_police_destroy(struct tcf_police *p); extern void tcf_police_destroy(struct tcf_police *p);
extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est); extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
...@@ -479,7 +482,7 @@ void dev_deactivate(struct net_device *dev); ...@@ -479,7 +482,7 @@ void dev_deactivate(struct net_device *dev);
void qdisc_reset(struct Qdisc *qdisc); void qdisc_reset(struct Qdisc *qdisc);
void qdisc_destroy(struct Qdisc *qdisc); void qdisc_destroy(struct Qdisc *qdisc);
struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops); struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops);
int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt); int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt);
void qdisc_kill_estimator(struct tc_stats *stats); void qdisc_kill_estimator(struct tc_stats *stats);
struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab); struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct rtattr *tab);
void qdisc_put_rtab(struct qdisc_rate_table *tab); void qdisc_put_rtab(struct qdisc_rate_table *tab);
......
...@@ -81,6 +81,7 @@ struct qdisc_estimator ...@@ -81,6 +81,7 @@ struct qdisc_estimator
{ {
struct qdisc_estimator *next; struct qdisc_estimator *next;
struct tc_stats *stats; struct tc_stats *stats;
spinlock_t *stats_lock;
unsigned interval; unsigned interval;
int ewma_log; int ewma_log;
u64 last_bytes; u64 last_bytes;
...@@ -112,7 +113,7 @@ static void est_timer(unsigned long arg) ...@@ -112,7 +113,7 @@ static void est_timer(unsigned long arg)
u32 npackets; u32 npackets;
u32 rate; u32 rate;
spin_lock(st->lock); spin_lock(e->stats_lock);
nbytes = st->bytes; nbytes = st->bytes;
npackets = st->packets; npackets = st->packets;
rate = (nbytes - e->last_bytes)<<(7 - idx); rate = (nbytes - e->last_bytes)<<(7 - idx);
...@@ -124,14 +125,14 @@ static void est_timer(unsigned long arg) ...@@ -124,14 +125,14 @@ static void est_timer(unsigned long arg)
e->last_packets = npackets; e->last_packets = npackets;
e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log; e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
e->stats->pps = (e->avpps+0x1FF)>>10; e->stats->pps = (e->avpps+0x1FF)>>10;
spin_unlock(st->lock); spin_unlock(e->stats_lock);
} }
mod_timer(&elist[idx].timer, jiffies + ((HZ/4)<<idx)); mod_timer(&elist[idx].timer, jiffies + ((HZ/4)<<idx));
read_unlock(&est_lock); read_unlock(&est_lock);
} }
int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt) int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt)
{ {
struct qdisc_estimator *est; struct qdisc_estimator *est;
struct tc_estimator *parm = RTA_DATA(opt); struct tc_estimator *parm = RTA_DATA(opt);
...@@ -149,6 +150,7 @@ int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt) ...@@ -149,6 +150,7 @@ int qdisc_new_estimator(struct tc_stats *stats, struct rtattr *opt)
memset(est, 0, sizeof(*est)); memset(est, 0, sizeof(*est));
est->interval = parm->interval + 2; est->interval = parm->interval + 2;
est->stats = stats; est->stats = stats;
est->stats_lock = stats_lock;
est->ewma_log = parm->ewma_log; est->ewma_log = parm->ewma_log;
est->last_bytes = stats->bytes; est->last_bytes = stats->bytes;
est->avbps = stats->bps<<5; est->avbps = stats->bps<<5;
......
...@@ -207,7 +207,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio ...@@ -207,7 +207,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio
ret = 1; ret = 1;
p->refcnt = 1; p->refcnt = 1;
spin_lock_init(&p->lock); spin_lock_init(&p->lock);
p->stats.lock = &p->lock; p->stats_lock = &p->lock;
if (bind) if (bind)
p->bindcnt = 1; p->bindcnt = 1;
override: override:
...@@ -245,7 +245,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio ...@@ -245,7 +245,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio
p->index = parm->index ? : tcf_police_new_index(); p->index = parm->index ? : tcf_police_new_index();
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (est) if (est)
qdisc_new_estimator(&p->stats, est); qdisc_new_estimator(&p->stats, p->stats_lock, est);
#endif #endif
h = tcf_police_hash(p->index); h = tcf_police_hash(p->index);
write_lock_bh(&police_lock); write_lock_bh(&police_lock);
...@@ -280,7 +280,7 @@ int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a) ...@@ -280,7 +280,7 @@ int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a)
struct tcf_police *p; struct tcf_police *p;
p = PRIV(a); p = PRIV(a);
if (NULL != p) if (NULL != p)
return qdisc_copy_stats(skb, &p->stats); return qdisc_copy_stats(skb, &p->stats, p->stats_lock);
return 1; return 1;
} }
...@@ -452,7 +452,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) ...@@ -452,7 +452,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est)
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
p->refcnt = 1; p->refcnt = 1;
spin_lock_init(&p->lock); spin_lock_init(&p->lock);
p->stats.lock = &p->lock; p->stats_lock = &p->lock;
if (parm->rate.rate) { if (parm->rate.rate) {
if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL)
goto failure; goto failure;
...@@ -480,7 +480,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) ...@@ -480,7 +480,7 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est)
p->action = parm->action; p->action = parm->action;
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (est) if (est)
qdisc_new_estimator(&p->stats, est); qdisc_new_estimator(&p->stats, p->stats_lock, est);
#endif #endif
h = tcf_police_hash(p->index); h = tcf_police_hash(p->index);
write_lock_bh(&police_lock); write_lock_bh(&police_lock);
......
...@@ -433,7 +433,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) ...@@ -433,7 +433,7 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
sch->dequeue = ops->dequeue; sch->dequeue = ops->dequeue;
sch->dev = dev; sch->dev = dev;
atomic_set(&sch->refcnt, 1); atomic_set(&sch->refcnt, 1);
sch->stats.lock = &dev->queue_lock; sch->stats_lock = &dev->queue_lock;
if (handle == 0) { if (handle == 0) {
handle = qdisc_alloc_handle(dev); handle = qdisc_alloc_handle(dev);
err = -ENOMEM; err = -ENOMEM;
...@@ -460,7 +460,8 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) ...@@ -460,7 +460,8 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
write_unlock(&qdisc_tree_lock); write_unlock(&qdisc_tree_lock);
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) if (tca[TCA_RATE-1])
qdisc_new_estimator(&sch->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&sch->stats, sch->stats_lock,
tca[TCA_RATE-1]);
#endif #endif
return sch; return sch;
} }
...@@ -487,7 +488,8 @@ static int qdisc_change(struct Qdisc *sch, struct rtattr **tca) ...@@ -487,7 +488,8 @@ static int qdisc_change(struct Qdisc *sch, struct rtattr **tca)
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) { if (tca[TCA_RATE-1]) {
qdisc_kill_estimator(&sch->stats); qdisc_kill_estimator(&sch->stats);
qdisc_new_estimator(&sch->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&sch->stats, sch->stats_lock,
tca[TCA_RATE-1]);
} }
#endif #endif
return 0; return 0;
...@@ -726,15 +728,15 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) ...@@ -726,15 +728,15 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
return 0; return 0;
} }
int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st) int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st, spinlock_t *lock)
{ {
spin_lock_bh(st->lock); spin_lock_bh(lock);
RTA_PUT(skb, TCA_STATS, (char*)&st->lock - (char*)st, st); RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), st);
spin_unlock_bh(st->lock); spin_unlock_bh(lock);
return 0; return 0;
rtattr_failure: rtattr_failure:
spin_unlock_bh(st->lock); spin_unlock_bh(lock);
return -1; return -1;
} }
...@@ -758,7 +760,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, ...@@ -758,7 +760,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
if (q->ops->dump && q->ops->dump(q, skb) < 0) if (q->ops->dump && q->ops->dump(q, skb) < 0)
goto rtattr_failure; goto rtattr_failure;
q->stats.qlen = q->q.qlen; q->stats.qlen = q->q.qlen;
if (qdisc_copy_stats(skb, &q->stats)) if (qdisc_copy_stats(skb, &q->stats, q->stats_lock))
goto rtattr_failure; goto rtattr_failure;
nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_len = skb->tail - b;
return skb->len; return skb->len;
......
...@@ -70,6 +70,7 @@ struct atm_flow_data { ...@@ -70,6 +70,7 @@ struct atm_flow_data {
u32 classid; /* x:y type ID */ u32 classid; /* x:y type ID */
int ref; /* reference count */ int ref; /* reference count */
struct tc_stats stats; struct tc_stats stats;
spinlock_t *stats_lock;
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;
NULL to set CLP instead */ NULL to set CLP instead */
......
...@@ -147,6 +147,7 @@ struct cbq_class ...@@ -147,6 +147,7 @@ struct cbq_class
long deficit; /* Saved deficit for WRR */ long deficit; /* Saved deficit for WRR */
unsigned long penalized; unsigned long penalized;
struct tc_stats stats; struct tc_stats stats;
spinlock_t *stats_lock;
struct tc_cbq_xstats xstats; struct tc_cbq_xstats xstats;
struct tcf_proto *filter_list; struct tcf_proto *filter_list;
...@@ -1468,7 +1469,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -1468,7 +1469,7 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
q->link.ewma_log = TC_CBQ_DEF_EWMA; q->link.ewma_log = TC_CBQ_DEF_EWMA;
q->link.avpkt = q->link.allot/2; q->link.avpkt = q->link.allot/2;
q->link.minidle = -0x7FFFFFFF; q->link.minidle = -0x7FFFFFFF;
q->link.stats.lock = &sch->dev->queue_lock; q->link.stats_lock = &sch->dev->queue_lock;
init_timer(&q->wd_timer); init_timer(&q->wd_timer);
q->wd_timer.data = (unsigned long)sch; q->wd_timer.data = (unsigned long)sch;
...@@ -1667,7 +1668,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg, ...@@ -1667,7 +1668,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
goto rtattr_failure; goto rtattr_failure;
rta->rta_len = skb->tail - b; rta->rta_len = skb->tail - b;
cl->stats.qlen = cl->q->q.qlen; cl->stats.qlen = cl->q->q.qlen;
if (qdisc_copy_stats(skb, &cl->stats)) if (qdisc_copy_stats(skb, &cl->stats, cl->stats_lock))
goto rtattr_failure; goto rtattr_failure;
spin_lock_bh(&sch->dev->queue_lock); spin_lock_bh(&sch->dev->queue_lock);
cl->xstats.avgidle = cl->avgidle; cl->xstats.avgidle = cl->avgidle;
...@@ -1897,7 +1898,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t ...@@ -1897,7 +1898,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) { if (tca[TCA_RATE-1]) {
qdisc_kill_estimator(&cl->stats); qdisc_kill_estimator(&cl->stats);
qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&cl->stats, cl->stats_lock,
tca[TCA_RATE-1]);
} }
#endif #endif
return 0; return 0;
...@@ -1958,7 +1960,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t ...@@ -1958,7 +1960,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
cl->allot = parent->allot; cl->allot = parent->allot;
cl->quantum = cl->allot; cl->quantum = cl->allot;
cl->weight = cl->R_tab->rate.rate; cl->weight = cl->R_tab->rate.rate;
cl->stats.lock = &sch->dev->queue_lock; cl->stats_lock = &sch->dev->queue_lock;
sch_tree_lock(sch); sch_tree_lock(sch);
cbq_link_class(cl); cbq_link_class(cl);
...@@ -1988,7 +1990,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t ...@@ -1988,7 +1990,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) if (tca[TCA_RATE-1])
qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&cl->stats, cl->stats_lock,
tca[TCA_RATE-1]);
#endif #endif
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
......
...@@ -386,7 +386,7 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops) ...@@ -386,7 +386,7 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
sch->enqueue = ops->enqueue; sch->enqueue = ops->enqueue;
sch->dequeue = ops->dequeue; sch->dequeue = ops->dequeue;
sch->dev = dev; sch->dev = dev;
sch->stats.lock = &dev->queue_lock; sch->stats_lock = &dev->queue_lock;
atomic_set(&sch->refcnt, 1); atomic_set(&sch->refcnt, 1);
/* enqueue is accessed locklessly - make sure it's visible /* enqueue is accessed locklessly - make sure it's visible
* before we set a netdevice's qdisc pointer to sch */ * before we set a netdevice's qdisc pointer to sch */
......
...@@ -122,6 +122,7 @@ struct hfsc_class ...@@ -122,6 +122,7 @@ struct hfsc_class
unsigned int refcnt; /* usage count */ unsigned int refcnt; /* usage count */
struct tc_stats stats; /* generic statistics */ struct tc_stats stats; /* generic statistics */
spinlock_t *stats_lock;
unsigned int level; /* class level in hierarchy */ unsigned int level; /* class level in hierarchy */
struct tcf_proto *filter_list; /* filter list */ struct tcf_proto *filter_list; /* filter list */
unsigned int filter_cnt; /* filter count */ unsigned int filter_cnt; /* filter count */
...@@ -1124,7 +1125,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1124,7 +1125,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) { if (tca[TCA_RATE-1]) {
qdisc_kill_estimator(&cl->stats); qdisc_kill_estimator(&cl->stats);
qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&cl->stats, cl->stats_lock,
tca[TCA_RATE-1]);
} }
#endif #endif
return 0; return 0;
...@@ -1167,7 +1169,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1167,7 +1169,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
cl->stats.lock = &sch->dev->queue_lock; cl->stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&cl->children); INIT_LIST_HEAD(&cl->children);
INIT_LIST_HEAD(&cl->actlist); INIT_LIST_HEAD(&cl->actlist);
...@@ -1181,7 +1183,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1181,7 +1183,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
#ifdef CONFIG_NET_ESTIMATOR #ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) if (tca[TCA_RATE-1])
qdisc_new_estimator(&cl->stats, tca[TCA_RATE-1]); qdisc_new_estimator(&cl->stats, cl->stats_lock,
tca[TCA_RATE-1]);
#endif #endif
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
return 0; return 0;
...@@ -1428,7 +1431,7 @@ static inline int ...@@ -1428,7 +1431,7 @@ static inline int
hfsc_dump_stats(struct sk_buff *skb, struct hfsc_class *cl) hfsc_dump_stats(struct sk_buff *skb, struct hfsc_class *cl)
{ {
cl->stats.qlen = cl->qdisc->q.qlen; cl->stats.qlen = cl->qdisc->q.qlen;
if (qdisc_copy_stats(skb, &cl->stats) < 0) if (qdisc_copy_stats(skb, &cl->stats, cl->stats_lock) < 0)
goto rtattr_failure; goto rtattr_failure;
return skb->len; return skb->len;
...@@ -1551,7 +1554,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) ...@@ -1551,7 +1554,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
qopt = RTA_DATA(opt); qopt = RTA_DATA(opt);
memset(q, 0, sizeof(struct hfsc_sched)); memset(q, 0, sizeof(struct hfsc_sched));
sch->stats.lock = &sch->dev->queue_lock; sch->stats_lock = &sch->dev->queue_lock;
q->defcls = qopt->defcls; q->defcls = qopt->defcls;
for (i = 0; i < HFSC_HSIZE; i++) for (i = 0; i < HFSC_HSIZE; i++)
...@@ -1566,7 +1569,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) ...@@ -1566,7 +1569,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
if (q->root.qdisc == NULL) if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc; q->root.qdisc = &noop_qdisc;
q->root.stats.lock = &sch->dev->queue_lock; q->root.stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&q->root.children); INIT_LIST_HEAD(&q->root.children);
INIT_LIST_HEAD(&q->root.actlist); INIT_LIST_HEAD(&q->root.actlist);
...@@ -1671,7 +1674,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb) ...@@ -1671,7 +1674,7 @@ hfsc_dump_qdisc(struct Qdisc *sch, struct sk_buff *skb)
RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
sch->stats.qlen = sch->q.qlen; sch->stats.qlen = sch->q.qlen;
if (qdisc_copy_stats(skb, &sch->stats) < 0) if (qdisc_copy_stats(skb, &sch->stats, sch->stats_lock) < 0)
goto rtattr_failure; goto rtattr_failure;
return skb->len; return skb->len;
......
...@@ -143,6 +143,7 @@ struct htb_class ...@@ -143,6 +143,7 @@ struct htb_class
/* general class parameters */ /* general class parameters */
u32 classid; u32 classid;
struct tc_stats stats; /* generic stats */ struct tc_stats stats; /* generic stats */
spinlock_t *stats_lock;
struct tc_htb_xstats xstats;/* our special stats */ struct tc_htb_xstats xstats;/* our special stats */
int refcnt; /* usage count of this class */ int refcnt; /* usage count of this class */
......
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