sch->dequeue = ops->dequeue;
sch->dev = dev;
atomic_set(&sch->refcnt, 1);
- sch->stats.lock = &dev->queue_lock;
+ sch->stats_lock = &dev->queue_lock;
if (handle == 0) {
handle = qdisc_alloc_handle(dev);
err = -ENOMEM;
if (!try_module_get(ops->owner))
goto err_out;
+ /* enqueue is accessed locklessly - make sure it's visible
+ * before we set a netdevice's qdisc pointer to sch */
+ smp_wmb();
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
write_lock(&qdisc_tree_lock);
sch->next = dev->qdisc_list;
write_unlock(&qdisc_tree_lock);
#ifdef CONFIG_NET_ESTIMATOR
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
return sch;
}
#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) {
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
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);
- RTA_PUT(skb, TCA_STATS, (char*)&st->lock - (char*)st, st);
- spin_unlock_bh(st->lock);
+ spin_lock_bh(lock);
+ RTA_PUT(skb, TCA_STATS, sizeof(struct tc_stats), st);
+ spin_unlock_bh(lock);
return 0;
rtattr_failure:
- spin_unlock_bh(st->lock);
+ spin_unlock_bh(lock);
return -1;
}
if (q->ops->dump && q->ops->dump(q, skb) < 0)
goto rtattr_failure;
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;
nlh->nlmsg_len = skb->tail - b;
return skb->len;
delta = bound;
return delta;
}
+EXPORT_SYMBOL(psched_tod_diff);
#endif
psched_time_t psched_time_base;
#if PSCHED_CLOCK_SOURCE == PSCHED_CPU
psched_tdiff_t psched_clock_per_hz;
int psched_clock_scale;
+EXPORT_SYMBOL(psched_clock_per_hz);
+EXPORT_SYMBOL(psched_clock_scale);
#endif
#ifdef PSCHED_WATCHER
PSCHED_WATCHER psched_time_mark;
+EXPORT_SYMBOL(psched_time_mark);
+EXPORT_SYMBOL(psched_time_base);
static void psched_tick(unsigned long);
EXPORT_SYMBOL(qdisc_put_rtab);
EXPORT_SYMBOL(register_qdisc);
EXPORT_SYMBOL(unregister_qdisc);
-PSCHED_EXPORTLIST;