diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-18 01:31:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-18 01:31:26 -0400 |
commit | 1e0d5a5747772182d1bb2525d8153da640fdfb58 (patch) | |
tree | 266a7c3e9a01728f7661d5b2976cc33d106b463c /net/sched | |
parent | 3a76e3716b4e571f5d91a20b6afb412560599083 (diff) |
pkt_sched: No longer destroy qdiscs from RCU.
We can now kill them synchronously with all of the
previous dev_deactivate() cures.
This makes netdev destruction and shutdown saner as
the qdiscs hold references to the device.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_generic.c | 27 |
1 files changed, 9 insertions, 18 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 30b76aec723b..6f96b7bc0809 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -518,14 +518,19 @@ void qdisc_reset(struct Qdisc *qdisc) | |||
518 | } | 518 | } |
519 | EXPORT_SYMBOL(qdisc_reset); | 519 | EXPORT_SYMBOL(qdisc_reset); |
520 | 520 | ||
521 | /* this is the rcu callback function to clean up a qdisc when there | 521 | /* Under qdisc_lock(qdisc) and BH! */ |
522 | * are no further references to it */ | ||
523 | 522 | ||
524 | static void __qdisc_destroy(struct rcu_head *head) | 523 | void qdisc_destroy(struct Qdisc *qdisc) |
525 | { | 524 | { |
526 | struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu); | ||
527 | const struct Qdisc_ops *ops = qdisc->ops; | 525 | const struct Qdisc_ops *ops = qdisc->ops; |
528 | 526 | ||
527 | if (qdisc->flags & TCQ_F_BUILTIN || | ||
528 | !atomic_dec_and_test(&qdisc->refcnt)) | ||
529 | return; | ||
530 | |||
531 | if (qdisc->parent) | ||
532 | list_del(&qdisc->list); | ||
533 | |||
529 | #ifdef CONFIG_NET_SCHED | 534 | #ifdef CONFIG_NET_SCHED |
530 | qdisc_put_stab(qdisc->stab); | 535 | qdisc_put_stab(qdisc->stab); |
531 | #endif | 536 | #endif |
@@ -542,20 +547,6 @@ static void __qdisc_destroy(struct rcu_head *head) | |||
542 | 547 | ||
543 | kfree((char *) qdisc - qdisc->padded); | 548 | kfree((char *) qdisc - qdisc->padded); |
544 | } | 549 | } |
545 | |||
546 | /* Under qdisc_lock(qdisc) and BH! */ | ||
547 | |||
548 | void qdisc_destroy(struct Qdisc *qdisc) | ||
549 | { | ||
550 | if (qdisc->flags & TCQ_F_BUILTIN || | ||
551 | !atomic_dec_and_test(&qdisc->refcnt)) | ||
552 | return; | ||
553 | |||
554 | if (qdisc->parent) | ||
555 | list_del(&qdisc->list); | ||
556 | |||
557 | call_rcu(&qdisc->q_rcu, __qdisc_destroy); | ||
558 | } | ||
559 | EXPORT_SYMBOL(qdisc_destroy); | 550 | EXPORT_SYMBOL(qdisc_destroy); |
560 | 551 | ||
561 | static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) | 552 | static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) |