aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ketrenos <jketreno@linux.intel.com>2005-09-21 12:54:15 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-21 23:01:52 -0400
commit0ad0c3c64484b1458b51167bd3e614d8d9d070f8 (patch)
tree4ff20e24d22523603c51d9cd876ae0e5b1714531
parent42e349fd10d471d9ae6955a7f12523291c0193e6 (diff)
[PATCH] ieee80211: Fix kernel Oops when module unload
tree b69e983266840983183a00f5ac02c66d5270ca47 parent cdd6372949b76694622ed74fe36e1dd17a92eb71 author Zhu Yi <jketreno@io.(none)> 1124435425 -0500 committer James Ketrenos <jketreno@linux.intel.com> 1127312421 -0500 Fix kernel Oops when module unload. Export a new function ieee80211_crypt_quiescing from ieee80211. Device drivers call it to make the host crypto stack enter the quiescence state, which means "process existing requests, but don't accept new ones". This is usually called during a driver's host crypto data structure free (module unload) path. Signed-off-by: James Ketrenos <jketreno@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--include/net/ieee80211.h1
-rw-r--r--include/net/ieee80211_crypt.h1
-rw-r--r--net/ieee80211/ieee80211_crypt.c33
-rw-r--r--net/ieee80211/ieee80211_module.c2
4 files changed, 31 insertions, 6 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index fa14360dbc9d..6cc0674e5606 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -684,6 +684,7 @@ struct ieee80211_device {
684 struct ieee80211_crypt_data *crypt[WEP_KEYS]; 684 struct ieee80211_crypt_data *crypt[WEP_KEYS];
685 int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ 685 int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
686 struct timer_list crypt_deinit_timer; 686 struct timer_list crypt_deinit_timer;
687 int crypt_quiesced;
687 688
688 int bcrx_sta_key; /* use individual keys to override default keys even 689 int bcrx_sta_key; /* use individual keys to override default keys even
689 * with RX of broad/multicast frames */ 690 * with RX of broad/multicast frames */
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index e2064edb957d..536e9a9e6718 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -82,5 +82,6 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
82void ieee80211_crypt_deinit_handler(unsigned long); 82void ieee80211_crypt_deinit_handler(unsigned long);
83void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, 83void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
84 struct ieee80211_crypt_data **crypt); 84 struct ieee80211_crypt_data **crypt);
85void ieee80211_crypt_quiescing(struct ieee80211_device *ieee);
85 86
86#endif 87#endif
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 0c366299db0f..60d3166facce 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -44,6 +44,10 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
44 unsigned long flags; 44 unsigned long flags;
45 45
46 spin_lock_irqsave(&ieee->lock, flags); 46 spin_lock_irqsave(&ieee->lock, flags);
47
48 if (list_empty(&ieee->crypt_deinit_list))
49 goto unlock;
50
47 for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; 51 for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
48 ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { 52 ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
49 entry = list_entry(ptr, struct ieee80211_crypt_data, list); 53 entry = list_entry(ptr, struct ieee80211_crypt_data, list);
@@ -59,21 +63,35 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
59 } 63 }
60 kfree(entry); 64 kfree(entry);
61 } 65 }
66 unlock:
67 spin_unlock_irqrestore(&ieee->lock, flags);
68}
69
70/* After this, crypt_deinit_list won't accept new members */
71void ieee80211_crypt_quiescing(struct ieee80211_device *ieee)
72{
73 unsigned long flags;
74
75 spin_lock_irqsave(&ieee->lock, flags);
76 ieee->crypt_quiesced = 1;
62 spin_unlock_irqrestore(&ieee->lock, flags); 77 spin_unlock_irqrestore(&ieee->lock, flags);
63} 78}
64 79
65void ieee80211_crypt_deinit_handler(unsigned long data) 80void ieee80211_crypt_deinit_handler(unsigned long data)
66{ 81{
67 struct ieee80211_device *ieee = (struct ieee80211_device *)data; 82 struct ieee80211_device *ieee = (struct ieee80211_device *)data;
83 unsigned long flags;
68 84
69 ieee80211_crypt_deinit_entries(ieee, 0); 85 ieee80211_crypt_deinit_entries(ieee, 0);
70 if (!list_empty(&ieee->crypt_deinit_list)) { 86
87 spin_lock_irqsave(&ieee->lock, flags);
88 if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) {
71 printk(KERN_DEBUG "%s: entries remaining in delayed crypt " 89 printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
72 "deletion list\n", ieee->dev->name); 90 "deletion list\n", ieee->dev->name);
73 ieee->crypt_deinit_timer.expires = jiffies + HZ; 91 ieee->crypt_deinit_timer.expires = jiffies + HZ;
74 add_timer(&ieee->crypt_deinit_timer); 92 add_timer(&ieee->crypt_deinit_timer);
75 } 93 }
76 94 spin_unlock_irqrestore(&ieee->lock, flags);
77} 95}
78 96
79void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, 97void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
@@ -93,10 +111,12 @@ void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
93 * locking. */ 111 * locking. */
94 112
95 spin_lock_irqsave(&ieee->lock, flags); 113 spin_lock_irqsave(&ieee->lock, flags);
96 list_add(&tmp->list, &ieee->crypt_deinit_list); 114 if (!ieee->crypt_quiesced) {
97 if (!timer_pending(&ieee->crypt_deinit_timer)) { 115 list_add(&tmp->list, &ieee->crypt_deinit_list);
98 ieee->crypt_deinit_timer.expires = jiffies + HZ; 116 if (!timer_pending(&ieee->crypt_deinit_timer)) {
99 add_timer(&ieee->crypt_deinit_timer); 117 ieee->crypt_deinit_timer.expires = jiffies + HZ;
118 add_timer(&ieee->crypt_deinit_timer);
119 }
100 } 120 }
101 spin_unlock_irqrestore(&ieee->lock, flags); 121 spin_unlock_irqrestore(&ieee->lock, flags);
102} 122}
@@ -250,6 +270,7 @@ static void __exit ieee80211_crypto_deinit(void)
250EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); 270EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
251EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); 271EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
252EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); 272EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
273EXPORT_SYMBOL(ieee80211_crypt_quiescing);
253 274
254EXPORT_SYMBOL(ieee80211_register_crypto_ops); 275EXPORT_SYMBOL(ieee80211_register_crypto_ops);
255EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); 276EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index 4b43ae1235f9..82a4fd713b28 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -138,6 +138,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
138 init_timer(&ieee->crypt_deinit_timer); 138 init_timer(&ieee->crypt_deinit_timer);
139 ieee->crypt_deinit_timer.data = (unsigned long)ieee; 139 ieee->crypt_deinit_timer.data = (unsigned long)ieee;
140 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; 140 ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
141 ieee->crypt_quiesced = 0;
141 142
142 spin_lock_init(&ieee->lock); 143 spin_lock_init(&ieee->lock);
143 144
@@ -161,6 +162,7 @@ void free_ieee80211(struct net_device *dev)
161 162
162 int i; 163 int i;
163 164
165 ieee80211_crypt_quiescing(ieee);
164 del_timer_sync(&ieee->crypt_deinit_timer); 166 del_timer_sync(&ieee->crypt_deinit_timer);
165 ieee80211_crypt_deinit_entries(ieee, 1); 167 ieee80211_crypt_deinit_entries(ieee, 1);
166 168