Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ad0c3c6 authored by James Ketrenos's avatar James Ketrenos Committed by Jeff Garzik
Browse files

[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: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 42e349fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -684,6 +684,7 @@ struct ieee80211_device {
	struct ieee80211_crypt_data *crypt[WEP_KEYS];
	struct ieee80211_crypt_data *crypt[WEP_KEYS];
	int tx_keyidx;		/* default TX key index (crypt[tx_keyidx]) */
	int tx_keyidx;		/* default TX key index (crypt[tx_keyidx]) */
	struct timer_list crypt_deinit_timer;
	struct timer_list crypt_deinit_timer;
	int crypt_quiesced;


	int bcrx_sta_key;	/* use individual keys to override default keys even
	int bcrx_sta_key;	/* use individual keys to override default keys even
				 * with RX of broad/multicast frames */
				 * with RX of broad/multicast frames */
+1 −0
Original line number Original line Diff line number Diff line
@@ -82,5 +82,6 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int);
void ieee80211_crypt_deinit_handler(unsigned long);
void ieee80211_crypt_deinit_handler(unsigned long);
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
				    struct ieee80211_crypt_data **crypt);
				    struct ieee80211_crypt_data **crypt);
void ieee80211_crypt_quiescing(struct ieee80211_device *ieee);


#endif
#endif
+27 −6
Original line number Original line Diff line number Diff line
@@ -44,6 +44,10 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
	unsigned long flags;
	unsigned long flags;


	spin_lock_irqsave(&ieee->lock, flags);
	spin_lock_irqsave(&ieee->lock, flags);

	if (list_empty(&ieee->crypt_deinit_list))
		goto unlock;

	for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
	for (ptr = ieee->crypt_deinit_list.next, n = ptr->next;
	     ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
	     ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) {
		entry = list_entry(ptr, struct ieee80211_crypt_data, list);
		entry = list_entry(ptr, struct ieee80211_crypt_data, list);
@@ -59,21 +63,35 @@ void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force)
		}
		}
		kfree(entry);
		kfree(entry);
	}
	}
      unlock:
	spin_unlock_irqrestore(&ieee->lock, flags);
}

/* After this, crypt_deinit_list won't accept new members */
void ieee80211_crypt_quiescing(struct ieee80211_device *ieee)
{
	unsigned long flags;

	spin_lock_irqsave(&ieee->lock, flags);
	ieee->crypt_quiesced = 1;
	spin_unlock_irqrestore(&ieee->lock, flags);
	spin_unlock_irqrestore(&ieee->lock, flags);
}
}


void ieee80211_crypt_deinit_handler(unsigned long data)
void ieee80211_crypt_deinit_handler(unsigned long data)
{
{
	struct ieee80211_device *ieee = (struct ieee80211_device *)data;
	struct ieee80211_device *ieee = (struct ieee80211_device *)data;
	unsigned long flags;


	ieee80211_crypt_deinit_entries(ieee, 0);
	ieee80211_crypt_deinit_entries(ieee, 0);
	if (!list_empty(&ieee->crypt_deinit_list)) {

	spin_lock_irqsave(&ieee->lock, flags);
	if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) {
		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
		printk(KERN_DEBUG "%s: entries remaining in delayed crypt "
		       "deletion list\n", ieee->dev->name);
		       "deletion list\n", ieee->dev->name);
		ieee->crypt_deinit_timer.expires = jiffies + HZ;
		ieee->crypt_deinit_timer.expires = jiffies + HZ;
		add_timer(&ieee->crypt_deinit_timer);
		add_timer(&ieee->crypt_deinit_timer);
	}
	}

	spin_unlock_irqrestore(&ieee->lock, flags);
}
}


void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
@@ -93,11 +111,13 @@ void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee,
	 * locking. */
	 * locking. */


	spin_lock_irqsave(&ieee->lock, flags);
	spin_lock_irqsave(&ieee->lock, flags);
	if (!ieee->crypt_quiesced) {
		list_add(&tmp->list, &ieee->crypt_deinit_list);
		list_add(&tmp->list, &ieee->crypt_deinit_list);
		if (!timer_pending(&ieee->crypt_deinit_timer)) {
		if (!timer_pending(&ieee->crypt_deinit_timer)) {
			ieee->crypt_deinit_timer.expires = jiffies + HZ;
			ieee->crypt_deinit_timer.expires = jiffies + HZ;
			add_timer(&ieee->crypt_deinit_timer);
			add_timer(&ieee->crypt_deinit_timer);
		}
		}
	}
	spin_unlock_irqrestore(&ieee->lock, flags);
	spin_unlock_irqrestore(&ieee->lock, flags);
}
}


@@ -250,6 +270,7 @@ static void __exit ieee80211_crypto_deinit(void)
EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
EXPORT_SYMBOL(ieee80211_crypt_deinit_entries);
EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
EXPORT_SYMBOL(ieee80211_crypt_deinit_handler);
EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit);
EXPORT_SYMBOL(ieee80211_crypt_quiescing);


EXPORT_SYMBOL(ieee80211_register_crypto_ops);
EXPORT_SYMBOL(ieee80211_register_crypto_ops);
EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
EXPORT_SYMBOL(ieee80211_unregister_crypto_ops);
+2 −0
Original line number Original line Diff line number Diff line
@@ -138,6 +138,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
	init_timer(&ieee->crypt_deinit_timer);
	init_timer(&ieee->crypt_deinit_timer);
	ieee->crypt_deinit_timer.data = (unsigned long)ieee;
	ieee->crypt_deinit_timer.data = (unsigned long)ieee;
	ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
	ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler;
	ieee->crypt_quiesced = 0;


	spin_lock_init(&ieee->lock);
	spin_lock_init(&ieee->lock);


@@ -161,6 +162,7 @@ void free_ieee80211(struct net_device *dev)


	int i;
	int i;


	ieee80211_crypt_quiescing(ieee);
	del_timer_sync(&ieee->crypt_deinit_timer);
	del_timer_sync(&ieee->crypt_deinit_timer);
	ieee80211_crypt_deinit_entries(ieee, 1);
	ieee80211_crypt_deinit_entries(ieee, 1);