diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-19 00:03:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-19 00:06:19 -0400 |
commit | 4d8863a29c4755a0461cd31b6865026187d6c43a (patch) | |
tree | 502b355314b1ff2e6cef52bf3778aba3bdae80cd /net/sched | |
parent | 25bfcd5a78a377ea4c54a3c21e44590e2fc478a6 (diff) |
pkt_sched: Don't hold qdisc lock over qdisc_destroy().
Based upon reports by Denys Fedoryshchenko, and feedback
and help from Jarek Poplawski and Herbert Xu.
We always either:
1) Never made an external reference to this qdisc.
or
2) Did a dev_deactivate() which purged all asynchronous
references.
So do not lock the qdisc when we call qdisc_destroy(),
it's illegal anyways as when we drop the lock this is
free'd memory.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 13 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 6 |
2 files changed, 2 insertions, 17 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 7d7070b1eebd..d91a2338877c 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -638,11 +638,8 @@ static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid | |||
638 | if (new || old) | 638 | if (new || old) |
639 | qdisc_notify(skb, n, clid, old, new); | 639 | qdisc_notify(skb, n, clid, old, new); |
640 | 640 | ||
641 | if (old) { | 641 | if (old) |
642 | sch_tree_lock(old); | ||
643 | qdisc_destroy(old); | 642 | qdisc_destroy(old); |
644 | sch_tree_unlock(old); | ||
645 | } | ||
646 | } | 643 | } |
647 | 644 | ||
648 | /* Graft qdisc "new" to class "classid" of qdisc "parent" or | 645 | /* Graft qdisc "new" to class "classid" of qdisc "parent" or |
@@ -1092,16 +1089,10 @@ create_n_graft: | |||
1092 | 1089 | ||
1093 | graft: | 1090 | graft: |
1094 | if (1) { | 1091 | if (1) { |
1095 | spinlock_t *root_lock; | ||
1096 | |||
1097 | err = qdisc_graft(dev, p, skb, n, clid, q, NULL); | 1092 | err = qdisc_graft(dev, p, skb, n, clid, q, NULL); |
1098 | if (err) { | 1093 | if (err) { |
1099 | if (q) { | 1094 | if (q) |
1100 | root_lock = qdisc_root_lock(q); | ||
1101 | spin_lock_bh(root_lock); | ||
1102 | qdisc_destroy(q); | 1095 | qdisc_destroy(q); |
1103 | spin_unlock_bh(root_lock); | ||
1104 | } | ||
1105 | return err; | 1096 | return err; |
1106 | } | 1097 | } |
1107 | } | 1098 | } |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 6f96b7bc0809..c3ed4d44fc14 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -518,8 +518,6 @@ void qdisc_reset(struct Qdisc *qdisc) | |||
518 | } | 518 | } |
519 | EXPORT_SYMBOL(qdisc_reset); | 519 | EXPORT_SYMBOL(qdisc_reset); |
520 | 520 | ||
521 | /* Under qdisc_lock(qdisc) and BH! */ | ||
522 | |||
523 | void qdisc_destroy(struct Qdisc *qdisc) | 521 | void qdisc_destroy(struct Qdisc *qdisc) |
524 | { | 522 | { |
525 | const struct Qdisc_ops *ops = qdisc->ops; | 523 | const struct Qdisc_ops *ops = qdisc->ops; |
@@ -712,14 +710,10 @@ static void shutdown_scheduler_queue(struct net_device *dev, | |||
712 | struct Qdisc *qdisc_default = _qdisc_default; | 710 | struct Qdisc *qdisc_default = _qdisc_default; |
713 | 711 | ||
714 | if (qdisc) { | 712 | if (qdisc) { |
715 | spinlock_t *root_lock = qdisc_lock(qdisc); | ||
716 | |||
717 | dev_queue->qdisc = qdisc_default; | 713 | dev_queue->qdisc = qdisc_default; |
718 | dev_queue->qdisc_sleeping = qdisc_default; | 714 | dev_queue->qdisc_sleeping = qdisc_default; |
719 | 715 | ||
720 | spin_lock_bh(root_lock); | ||
721 | qdisc_destroy(qdisc); | 716 | qdisc_destroy(qdisc); |
722 | spin_unlock_bh(root_lock); | ||
723 | } | 717 | } |
724 | } | 718 | } |
725 | 719 | ||