aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm
diff options
context:
space:
mode:
authorSimon Arlott <simon@fire.lp0.eu>2009-11-21 10:33:51 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:52:58 -0500
commit9fc950d322380dda8e9bc8debe89766085e7a0eb (patch)
tree50449ddbcc2cf883da8afe7ecfd1861c2441624f /drivers/usb/atm
parent5d0a9c7932c45435de72b5a5b2825c7eb34186a4 (diff)
USB: cxacru: check device isn't being removed during sysfs calls
It is possible for usb_get_intfdata() to return NULL if sysfs is accessed while the module is being unloaded or the device is being removed. Move the access code to an inline function in usbatm.h, and return -ENODEV if any of the pointers are NULL. It should not be possible for the instance data or atm device to be invalid until after unbind() completes and the sysfs attributes have been removed. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/atm')
-rw-r--r--drivers/usb/atm/cxacru.c48
-rw-r--r--drivers/usb/atm/usbatm.c1
-rw-r--r--drivers/usb/atm/usbatm.h15
3 files changed, 44 insertions, 20 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 8da4a06bf140..4bead3da3850 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -200,9 +200,12 @@ static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
200static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \ 200static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
201 struct device_attribute *attr, char *buf) \ 201 struct device_attribute *attr, char *buf) \
202{ \ 202{ \
203 struct usb_interface *intf = to_usb_interface(dev); \ 203 struct cxacru_data *instance = to_usbatm_driver_data(\
204 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \ 204 to_usb_interface(dev)); \
205 struct cxacru_data *instance = usbatm_instance->driver_data; \ 205\
206 if (instance == NULL) \
207 return -ENODEV; \
208\
206 return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \ 209 return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
207} \ 210} \
208CXACRU__ATTR_INIT(_name) 211CXACRU__ATTR_INIT(_name)
@@ -288,22 +291,28 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
288static ssize_t cxacru_sysfs_show_mac_address(struct device *dev, 291static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
289 struct device_attribute *attr, char *buf) 292 struct device_attribute *attr, char *buf)
290{ 293{
291 struct usb_interface *intf = to_usb_interface(dev); 294 struct cxacru_data *instance = to_usbatm_driver_data(
292 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); 295 to_usb_interface(dev));
293 struct atm_dev *atm_dev = usbatm_instance->atm_dev;
294 296
295 return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi); 297 if (instance == NULL || instance->usbatm->atm_dev == NULL)
298 return -ENODEV;
299
300 return snprintf(buf, PAGE_SIZE, "%pM\n",
301 instance->usbatm->atm_dev->esi);
296} 302}
297 303
298static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev, 304static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
299 struct device_attribute *attr, char *buf) 305 struct device_attribute *attr, char *buf)
300{ 306{
301 struct usb_interface *intf = to_usb_interface(dev);
302 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
303 struct cxacru_data *instance = usbatm_instance->driver_data;
304 u32 value = instance->card_info[CXINF_LINE_STARTABLE];
305
306 static char *str[] = { "running", "stopped" }; 307 static char *str[] = { "running", "stopped" };
308 struct cxacru_data *instance = to_usbatm_driver_data(
309 to_usb_interface(dev));
310 u32 value;
311
312 if (instance == NULL)
313 return -ENODEV;
314
315 value = instance->card_info[CXINF_LINE_STARTABLE];
307 if (unlikely(value >= ARRAY_SIZE(str))) 316 if (unlikely(value >= ARRAY_SIZE(str)))
308 return snprintf(buf, PAGE_SIZE, "%u\n", value); 317 return snprintf(buf, PAGE_SIZE, "%u\n", value);
309 return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); 318 return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
@@ -312,9 +321,8 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
312static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev, 321static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
313 struct device_attribute *attr, const char *buf, size_t count) 322 struct device_attribute *attr, const char *buf, size_t count)
314{ 323{
315 struct usb_interface *intf = to_usb_interface(dev); 324 struct cxacru_data *instance = to_usbatm_driver_data(
316 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); 325 to_usb_interface(dev));
317 struct cxacru_data *instance = usbatm_instance->driver_data;
318 int ret; 326 int ret;
319 int poll = -1; 327 int poll = -1;
320 char str_cmd[8]; 328 char str_cmd[8];
@@ -328,13 +336,16 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
328 return -EINVAL; 336 return -EINVAL;
329 ret = 0; 337 ret = 0;
330 338
339 if (instance == NULL)
340 return -ENODEV;
341
331 if (mutex_lock_interruptible(&instance->adsl_state_serialize)) 342 if (mutex_lock_interruptible(&instance->adsl_state_serialize))
332 return -ERESTARTSYS; 343 return -ERESTARTSYS;
333 344
334 if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) { 345 if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
335 ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0); 346 ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
336 if (ret < 0) { 347 if (ret < 0) {
337 atm_err(usbatm_instance, "change adsl state:" 348 atm_err(instance->usbatm, "change adsl state:"
338 " CHIP_ADSL_LINE_STOP returned %d\n", ret); 349 " CHIP_ADSL_LINE_STOP returned %d\n", ret);
339 350
340 ret = -EIO; 351 ret = -EIO;
@@ -354,7 +365,7 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
354 if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) { 365 if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
355 ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); 366 ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
356 if (ret < 0) { 367 if (ret < 0) {
357 atm_err(usbatm_instance, "change adsl state:" 368 atm_err(instance->usbatm, "change adsl state:"
358 " CHIP_ADSL_LINE_START returned %d\n", ret); 369 " CHIP_ADSL_LINE_START returned %d\n", ret);
359 370
360 ret = -EIO; 371 ret = -EIO;
@@ -649,9 +660,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
649{ 660{
650 struct cxacru_data *instance = usbatm_instance->driver_data; 661 struct cxacru_data *instance = usbatm_instance->driver_data;
651 struct usb_interface *intf = usbatm_instance->usb_intf; 662 struct usb_interface *intf = usbatm_instance->usb_intf;
652 /*
653 struct atm_dev *atm_dev = usbatm_instance->atm_dev;
654 */
655 int ret; 663 int ret;
656 int start_polling = 1; 664 int start_polling = 1;
657 665
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index fbea8563df1e..40380434ba96 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -1333,6 +1333,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1333 if (instance->atm_dev) { 1333 if (instance->atm_dev) {
1334 sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device"); 1334 sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
1335 atm_dev_deregister(instance->atm_dev); 1335 atm_dev_deregister(instance->atm_dev);
1336 instance->atm_dev = NULL;
1336 } 1337 }
1337 1338
1338 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ 1339 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index f6f4508a9d42..0863f85fcc26 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -204,4 +204,19 @@ struct usbatm_data {
204 struct urb *urbs[0]; 204 struct urb *urbs[0];
205}; 205};
206 206
207static inline void *to_usbatm_driver_data(struct usb_interface *intf)
208{
209 struct usbatm_data *usbatm_instance;
210
211 if (intf == NULL)
212 return NULL;
213
214 usbatm_instance = usb_get_intfdata(intf);
215
216 if (usbatm_instance == NULL) /* set NULL before unbind() */
217 return NULL;
218
219 return usbatm_instance->driver_data; /* set NULL after unbind() */
220}
221
207#endif /* _USBATM_H_ */ 222#endif /* _USBATM_H_ */