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 | |
| 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>
| -rw-r--r-- | include/net/sch_generic.h | 1 | ||||
| -rw-r--r-- | net/sched/sch_generic.c | 27 |
2 files changed, 9 insertions, 19 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 757ab087adbf..84d25f2e6188 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h | |||
| @@ -61,7 +61,6 @@ struct Qdisc | |||
| 61 | struct gnet_stats_basic bstats; | 61 | struct gnet_stats_basic bstats; |
| 62 | struct gnet_stats_queue qstats; | 62 | struct gnet_stats_queue qstats; |
| 63 | struct gnet_stats_rate_est rate_est; | 63 | struct gnet_stats_rate_est rate_est; |
| 64 | struct rcu_head q_rcu; | ||
| 65 | int (*reshape_fail)(struct sk_buff *skb, | 64 | int (*reshape_fail)(struct sk_buff *skb, |
| 66 | struct Qdisc *q); | 65 | struct Qdisc *q); |
| 67 | 66 | ||
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) |
