Merge branch 'qdisc-destroy'
Vlad Buslov says: ==================== Fix Qdisc destroy issues caused by adding fine-grained locking to filter API TC filter API unlocking introduced several new fine-grained locks. The change caused sleeping-while-atomic BUGs in several Qdiscs that call cls APIs which need to obtain new mutex while holding sch tree spinlock. This series fixes affected Qdiscs by ensuring that cls API that became sleeping is only called outside of sch tree lock critical section. ==================== Acked-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
5c7ff18149
|
@ -1302,6 +1302,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
|
|||
struct htb_class *cl = (struct htb_class *)*arg, *parent;
|
||||
struct nlattr *opt = tca[TCA_OPTIONS];
|
||||
struct nlattr *tb[TCA_HTB_MAX + 1];
|
||||
struct Qdisc *parent_qdisc = NULL;
|
||||
struct tc_htb_opt *hopt;
|
||||
u64 rate64, ceil64;
|
||||
int warn = 0;
|
||||
|
@ -1401,7 +1402,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
|
|||
if (parent && !parent->level) {
|
||||
/* turn parent into inner node */
|
||||
qdisc_purge_queue(parent->leaf.q);
|
||||
qdisc_put(parent->leaf.q);
|
||||
parent_qdisc = parent->leaf.q;
|
||||
if (parent->prio_activity)
|
||||
htb_deactivate(q, parent);
|
||||
|
||||
|
@ -1480,6 +1481,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
|
|||
cl->cbuffer = PSCHED_TICKS2NS(hopt->cbuffer);
|
||||
|
||||
sch_tree_unlock(sch);
|
||||
qdisc_put(parent_qdisc);
|
||||
|
||||
if (warn)
|
||||
pr_warn("HTB: quantum of class %X is %s. Consider r2q change.\n",
|
||||
|
|
|
@ -174,7 +174,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
|
|||
{
|
||||
struct multiq_sched_data *q = qdisc_priv(sch);
|
||||
struct tc_multiq_qopt *qopt;
|
||||
int i;
|
||||
struct Qdisc **removed;
|
||||
int i, n_removed = 0;
|
||||
|
||||
if (!netif_is_multiqueue(qdisc_dev(sch)))
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -185,6 +186,11 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
|
|||
|
||||
qopt->bands = qdisc_dev(sch)->real_num_tx_queues;
|
||||
|
||||
removed = kmalloc(sizeof(*removed) * (q->max_bands - q->bands),
|
||||
GFP_KERNEL);
|
||||
if (!removed)
|
||||
return -ENOMEM;
|
||||
|
||||
sch_tree_lock(sch);
|
||||
q->bands = qopt->bands;
|
||||
for (i = q->bands; i < q->max_bands; i++) {
|
||||
|
@ -192,13 +198,17 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
|
|||
struct Qdisc *child = q->queues[i];
|
||||
|
||||
q->queues[i] = &noop_qdisc;
|
||||
qdisc_tree_flush_backlog(child);
|
||||
qdisc_put(child);
|
||||
qdisc_purge_queue(child);
|
||||
removed[n_removed++] = child;
|
||||
}
|
||||
}
|
||||
|
||||
sch_tree_unlock(sch);
|
||||
|
||||
for (i = 0; i < n_removed; i++)
|
||||
qdisc_put(removed[i]);
|
||||
kfree(removed);
|
||||
|
||||
for (i = 0; i < q->bands; i++) {
|
||||
if (q->queues[i] == &noop_qdisc) {
|
||||
struct Qdisc *child, *old;
|
||||
|
@ -213,11 +223,10 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
|
|||
if (child != &noop_qdisc)
|
||||
qdisc_hash_add(child, true);
|
||||
|
||||
if (old != &noop_qdisc) {
|
||||
qdisc_tree_flush_backlog(old);
|
||||
qdisc_put(old);
|
||||
}
|
||||
if (old != &noop_qdisc)
|
||||
qdisc_purge_queue(old);
|
||||
sch_tree_unlock(sch);
|
||||
qdisc_put(old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -488,7 +488,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct sfb_sched_data *q = qdisc_priv(sch);
|
||||
struct Qdisc *child;
|
||||
struct Qdisc *child, *old;
|
||||
struct nlattr *tb[TCA_SFB_MAX + 1];
|
||||
const struct tc_sfb_qopt *ctl = &sfb_default_ops;
|
||||
u32 limit;
|
||||
|
@ -518,8 +518,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
qdisc_hash_add(child, true);
|
||||
sch_tree_lock(sch);
|
||||
|
||||
qdisc_tree_flush_backlog(q->qdisc);
|
||||
qdisc_put(q->qdisc);
|
||||
qdisc_purge_queue(q->qdisc);
|
||||
old = q->qdisc;
|
||||
q->qdisc = child;
|
||||
|
||||
q->rehash_interval = msecs_to_jiffies(ctl->rehash_interval);
|
||||
|
@ -542,6 +542,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
|
|||
sfb_init_perturbation(1, q);
|
||||
|
||||
sch_tree_unlock(sch);
|
||||
qdisc_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче