On Mon, 2009-03-16 at 19:25 +0100, Ivo van Doorn wrote: > At rmmod stage, the code path is the following one : > > rt2x00lib_remove_dev > -> rt2x00lib_uninitialize() > -> rt2x00rfkill_unregister() > -> rfkill_unregister() > -> rt2x00rfkill_free() > -> rfkill_free() > > The problem is that rfkill_free should not be called after rfkill_free > otherwise put_device(&rfkill->dev) will be called 2 times. This patch > fix this by removing the call to rfkill_free Needs a better patch title :) During what? And I assume you mean "rfkill_free() should not be called after rfkill_unregister(), right? Dan > Signed-off-by: Gertjan van Wingerde <gwingerde@xxxxxxxxx> > Tested-by: Arnaud Patard <apatard@xxxxxxxxxxxx> > Signed-off-by: Ivo van Doorn <IvDoorn@xxxxxxxxx> > > --- > John, this patch is for 2.6.29 and only 2.6.29 since rfkill support itself > was removed from later versions (replaced by input_polldev). > The patch is quite big to be merged in a late state of the release cycle, > but since the SLAB corruption is a serious problem, I hope this can get in regardless. > > Thanks. > > diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h > index 39ecf3b..820fdb2 100644 > --- a/drivers/net/wireless/rt2x00/rt2x00.h > +++ b/drivers/net/wireless/rt2x00/rt2x00.h > @@ -687,8 +687,7 @@ struct rt2x00_dev { > */ > #ifdef CONFIG_RT2X00_LIB_RFKILL > unsigned long rfkill_state; > -#define RFKILL_STATE_ALLOCATED 1 > -#define RFKILL_STATE_REGISTERED 2 > +#define RFKILL_STATE_REGISTERED 1 > struct rfkill *rfkill; > struct delayed_work rfkill_work; > #endif /* CONFIG_RT2X00_LIB_RFKILL */ > diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c > index 87c0f2c..e694bb7 100644 > --- a/drivers/net/wireless/rt2x00/rt2x00dev.c > +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c > @@ -1105,7 +1105,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) > * Register extra components. > */ > rt2x00leds_register(rt2x00dev); > - rt2x00rfkill_allocate(rt2x00dev); > rt2x00debug_register(rt2x00dev); > > set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); > @@ -1137,7 +1136,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) > * Free extra components > */ > rt2x00debug_deregister(rt2x00dev); > - rt2x00rfkill_free(rt2x00dev); > rt2x00leds_unregister(rt2x00dev); > > /* > diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h > index 86cd26f..49309d4 100644 > --- a/drivers/net/wireless/rt2x00/rt2x00lib.h > +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h > @@ -260,8 +260,6 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, > #ifdef CONFIG_RT2X00_LIB_RFKILL > void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev); > void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev); > -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev); > -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev); > #else > static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) > { > @@ -270,14 +268,6 @@ static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) > static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) > { > } > - > -static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) > -{ > -} > - > -static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) > -{ > -} > #endif /* CONFIG_RT2X00_LIB_RFKILL */ > > /* > diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c > index 3298cae..08ffc6d 100644 > --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c > +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c > @@ -94,14 +94,50 @@ static void rt2x00rfkill_poll(struct work_struct *work) > &rt2x00dev->rfkill_work, RFKILL_POLL_INTERVAL); > } > > +static int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) > +{ > + struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy); > + > + rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN); > + if (!rt2x00dev->rfkill) > + return -ENOMEM; > + > + rt2x00dev->rfkill->name = rt2x00dev->ops->name; > + rt2x00dev->rfkill->data = rt2x00dev; > + rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; > + if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) { > + rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; > + rt2x00dev->rfkill->state = > + rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? > + RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; > + } else { > + rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED; > + } > + > + INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); > + > + return 0; > +} > + > +static void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) > +{ > + rfkill_free(rt2x00dev->rfkill); > + rt2x00dev->rfkill = NULL; > +} > + > void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) > { > - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || > - test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) > + if (test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) > + return; > + > + if (rt2x00rfkill_allocate(rt2x00dev)) { > + ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); > return; > + } > > if (rfkill_register(rt2x00dev->rfkill)) { > ERROR(rt2x00dev, "Failed to register rfkill handler.\n"); > + rt2x00rfkill_free(rt2x00dev); > return; > } > > @@ -117,8 +153,7 @@ void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) > > void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) > { > - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) || > - !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) > + if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state)) > return; > > cancel_delayed_work_sync(&rt2x00dev->rfkill_work); > @@ -127,46 +162,3 @@ void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev) > > __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state); > } > - > -void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) > -{ > - struct device *dev = wiphy_dev(rt2x00dev->hw->wiphy); > - > - if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) > - return; > - > - rt2x00dev->rfkill = rfkill_allocate(dev, RFKILL_TYPE_WLAN); > - if (!rt2x00dev->rfkill) { > - ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); > - return; > - } > - > - __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state); > - > - rt2x00dev->rfkill->name = rt2x00dev->ops->name; > - rt2x00dev->rfkill->data = rt2x00dev; > - rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; > - if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags)) { > - rt2x00dev->rfkill->get_state = rt2x00rfkill_get_state; > - rt2x00dev->rfkill->state = > - rt2x00dev->ops->lib->rfkill_poll(rt2x00dev) ? > - RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED; > - } else { > - rt2x00dev->rfkill->state = RFKILL_STATE_UNBLOCKED; > - } > - > - INIT_DELAYED_WORK(&rt2x00dev->rfkill_work, rt2x00rfkill_poll); > - > - return; > -} > - > -void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) > -{ > - if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state)) > - return; > - > - cancel_delayed_work_sync(&rt2x00dev->rfkill_work); > - > - rfkill_free(rt2x00dev->rfkill); > - rt2x00dev->rfkill = NULL; > -} > -- > To unsubscribe from this list: send the line "unsubscribe linux-wireless" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html