diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-10-17 07:42:32 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-18 17:01:27 -0400 |
commit | bc0a7438605c5e0cafdb32a3caf46254e146b116 (patch) | |
tree | 7331f97459c13f1f4bb18d8d2db6abd724ad6f7f /drivers/net/hamradio | |
parent | ad4ebed00fbf570411edbf6eb6c391e16b71df25 (diff) |
[PATCH] rcu in bpqether driver.
From Suzanne Wood <suzannew@cs.pdx.edu>:
Clarify RCU implementation in bpqether.c.
Because bpq_new_device() calls list_add_rcu() and bpq_free_device() calls
list_del_rcu(), substitute list_for_each_entry_rcu() for
list_for_each_entry() in bpq_get_ax25_dev() and in bpq_seq_start().
Add rcu dereference protection in bpq_seq_next().
The rcu_read_lock()/unlock() in bpq_device_event() are removed because
netdev event handlers are called with RTNL locking in place.
FYI: bpq_free_device() calls list_del_rcu() which, per list.h, requires
synchronize_rcu() which can block or call_rcu() or call_rcu_bh() which
cannot block. Herbert Xu notes that synchronization is done here by
unregister_netdevice(). This calls synchronize_net() which in turn uses
synchronize_rcu().
Signed-off-by: Ralf Baechle DL5RB <ralf@linux-mips.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net/hamradio')
-rw-r--r-- | drivers/net/hamradio/bpqether.c | 9 |
1 files changed, 3 insertions, 6 deletions
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 1756f0ed54cc..cb43a9d28774 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c | |||
@@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) | |||
144 | { | 144 | { |
145 | struct bpqdev *bpq; | 145 | struct bpqdev *bpq; |
146 | 146 | ||
147 | list_for_each_entry(bpq, &bpq_devices, bpq_list) { | 147 | list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) { |
148 | if (bpq->ethdev == dev) | 148 | if (bpq->ethdev == dev) |
149 | return bpq->axdev; | 149 | return bpq->axdev; |
150 | } | 150 | } |
@@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos) | |||
399 | if (*pos == 0) | 399 | if (*pos == 0) |
400 | return SEQ_START_TOKEN; | 400 | return SEQ_START_TOKEN; |
401 | 401 | ||
402 | list_for_each_entry(bpqdev, &bpq_devices, bpq_list) { | 402 | list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) { |
403 | if (i == *pos) | 403 | if (i == *pos) |
404 | return bpqdev; | 404 | return bpqdev; |
405 | } | 405 | } |
@@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
418 | p = ((struct bpqdev *)v)->bpq_list.next; | 418 | p = ((struct bpqdev *)v)->bpq_list.next; |
419 | 419 | ||
420 | return (p == &bpq_devices) ? NULL | 420 | return (p == &bpq_devices) ? NULL |
421 | : list_entry(p, struct bpqdev, bpq_list); | 421 | : rcu_dereference(list_entry(p, struct bpqdev, bpq_list)); |
422 | } | 422 | } |
423 | 423 | ||
424 | static void bpq_seq_stop(struct seq_file *seq, void *v) | 424 | static void bpq_seq_stop(struct seq_file *seq, void *v) |
@@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi | |||
561 | if (!dev_is_ethdev(dev)) | 561 | if (!dev_is_ethdev(dev)) |
562 | return NOTIFY_DONE; | 562 | return NOTIFY_DONE; |
563 | 563 | ||
564 | rcu_read_lock(); | ||
565 | |||
566 | switch (event) { | 564 | switch (event) { |
567 | case NETDEV_UP: /* new ethernet device -> new BPQ interface */ | 565 | case NETDEV_UP: /* new ethernet device -> new BPQ interface */ |
568 | if (bpq_get_ax25_dev(dev) == NULL) | 566 | if (bpq_get_ax25_dev(dev) == NULL) |
@@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi | |||
581 | default: | 579 | default: |
582 | break; | 580 | break; |
583 | } | 581 | } |
584 | rcu_read_unlock(); | ||
585 | 582 | ||
586 | return NOTIFY_DONE; | 583 | return NOTIFY_DONE; |
587 | } | 584 | } |