|
@@ -623,6 +623,31 @@ void qdisc_destroy(struct Qdisc *qdisc)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(qdisc_destroy);
|
|
EXPORT_SYMBOL(qdisc_destroy);
|
|
|
|
|
|
|
|
+/* Attach toplevel qdisc to device queue. */
|
|
|
|
+struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
|
|
|
|
+ struct Qdisc *qdisc)
|
|
|
|
+{
|
|
|
|
+ struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
|
|
|
|
+ spinlock_t *root_lock;
|
|
|
|
+
|
|
|
|
+ root_lock = qdisc_lock(oqdisc);
|
|
|
|
+ spin_lock_bh(root_lock);
|
|
|
|
+
|
|
|
|
+ /* Prune old scheduler */
|
|
|
|
+ if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1)
|
|
|
|
+ qdisc_reset(oqdisc);
|
|
|
|
+
|
|
|
|
+ /* ... and graft new one */
|
|
|
|
+ if (qdisc == NULL)
|
|
|
|
+ qdisc = &noop_qdisc;
|
|
|
|
+ dev_queue->qdisc_sleeping = qdisc;
|
|
|
|
+ rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
|
|
|
|
+
|
|
|
|
+ spin_unlock_bh(root_lock);
|
|
|
|
+
|
|
|
|
+ return oqdisc;
|
|
|
|
+}
|
|
|
|
+
|
|
static void attach_one_default_qdisc(struct net_device *dev,
|
|
static void attach_one_default_qdisc(struct net_device *dev,
|
|
struct netdev_queue *dev_queue,
|
|
struct netdev_queue *dev_queue,
|
|
void *_unused)
|
|
void *_unused)
|