[ATM]: deregistration removes device from atm_devs list immediately

atm_dev_deregister() removes device from atm_dev list immediately to
prevent operations on a phantom device. Decision to free device based
only on ->refcnt now. Remove shutdown_atm_dev() use atm_dev_deregister()
instead. atm_dev_deregister() also asynchronously releases all vccs
related to device.

Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Stanislaw Gruszka and committed by David S. Miller 64bf69dd aaaaaadb

+51 -56
+2 -18
drivers/atm/atmtcp.c
··· 246 { 247 struct atm_dev *atmtcp_dev; 248 struct atmtcp_dev_data *dev_data; 249 - struct sock *s; 250 - struct hlist_node *node; 251 - struct atm_vcc *walk; 252 - int i; 253 254 atmtcp_dev = (struct atm_dev *) vcc->dev_data; 255 dev_data = PRIV(atmtcp_dev); ··· 253 if (dev_data->persist) return; 254 atmtcp_dev->dev_data = NULL; 255 kfree(dev_data); 256 - shutdown_atm_dev(atmtcp_dev); 257 vcc->dev_data = NULL; 258 - read_lock(&vcc_sklist_lock); 259 - for(i = 0; i < VCC_HTABLE_SIZE; ++i) { 260 - struct hlist_head *head = &vcc_hash[i]; 261 - 262 - sk_for_each(s, node, head) { 263 - walk = atm_sk(s); 264 - if (walk->dev != atmtcp_dev) 265 - continue; 266 - wake_up(s->sk_sleep); 267 - } 268 - } 269 - read_unlock(&vcc_sklist_lock); 270 module_put(THIS_MODULE); 271 } 272 ··· 434 if (PRIV(dev)->vcc) return 0; 435 kfree(dev_data); 436 atm_dev_put(dev); 437 - shutdown_atm_dev(dev); 438 return 0; 439 } 440
··· 246 { 247 struct atm_dev *atmtcp_dev; 248 struct atmtcp_dev_data *dev_data; 249 250 atmtcp_dev = (struct atm_dev *) vcc->dev_data; 251 dev_data = PRIV(atmtcp_dev); ··· 257 if (dev_data->persist) return; 258 atmtcp_dev->dev_data = NULL; 259 kfree(dev_data); 260 + atm_dev_deregister(atmtcp_dev); 261 vcc->dev_data = NULL; 262 module_put(THIS_MODULE); 263 } 264 ··· 450 if (PRIV(dev)->vcc) return 0; 451 kfree(dev_data); 452 atm_dev_put(dev); 453 + atm_dev_deregister(dev); 454 return 0; 455 } 456
+2 -2
drivers/usb/atm/usbatm.c
··· 879 880 fail: 881 instance->atm_dev = NULL; 882 - shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */ 883 return ret; 884 } 885 ··· 1164 1165 /* ATM finalize */ 1166 if (instance->atm_dev) 1167 - shutdown_atm_dev(instance->atm_dev); 1168 1169 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ 1170 }
··· 879 880 fail: 881 instance->atm_dev = NULL; 882 + atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */ 883 return ret; 884 } 885 ··· 1164 1165 /* ATM finalize */ 1166 if (instance->atm_dev) 1167 + atm_dev_deregister(instance->atm_dev); 1168 1169 usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ 1170 }
+7 -7
include/linux/atmdev.h
··· 274 275 276 enum { 277 - ATM_DF_CLOSE, /* close device when last VCC is closed */ 278 }; 279 280 ··· 415 int number,unsigned long *flags); /* number == -1: pick first available */ 416 struct atm_dev *atm_dev_lookup(int number); 417 void atm_dev_deregister(struct atm_dev *dev); 418 - void shutdown_atm_dev(struct atm_dev *dev); 419 void vcc_insert_socket(struct sock *sk); 420 421 ··· 456 457 static inline void atm_dev_put(struct atm_dev *dev) 458 { 459 - atomic_dec(&dev->refcnt); 460 - 461 - if ((atomic_read(&dev->refcnt) == 1) && 462 - test_bit(ATM_DF_CLOSE,&dev->flags)) 463 - shutdown_atm_dev(dev); 464 } 465 466
··· 274 275 276 enum { 277 + ATM_DF_REMOVED, /* device was removed from atm_devs list */ 278 }; 279 280 ··· 415 int number,unsigned long *flags); /* number == -1: pick first available */ 416 struct atm_dev *atm_dev_lookup(int number); 417 void atm_dev_deregister(struct atm_dev *dev); 418 void vcc_insert_socket(struct sock *sk); 419 420 ··· 457 458 static inline void atm_dev_put(struct atm_dev *dev) 459 { 460 + if (atomic_dec_and_test(&dev->refcnt)) { 461 + BUG_ON(!test_bit(ATM_DF_REMOVED, &dev->flags)); 462 + if (dev->ops->dev_close) 463 + dev->ops->dev_close(dev); 464 + kfree(dev); 465 + } 466 } 467 468
+27 -3
net/atm/common.c
··· 221 EXPORT_SYMBOL(vcc_release_async); 222 223 224 static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) 225 { 226 int max_sdu; ··· 355 return -EINVAL; 356 if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) 357 return -EPERM; 358 - error = 0; 359 if (!try_module_get(dev->ops->owner)) 360 - return -ENODEV; 361 vcc->dev = dev; 362 write_lock_irq(&vcc_sklist_lock); 363 - if ((error = find_ci(vcc, &vpi, &vci))) { 364 write_unlock_irq(&vcc_sklist_lock); 365 goto fail_module_put; 366 }
··· 221 EXPORT_SYMBOL(vcc_release_async); 222 223 224 + void atm_dev_release_vccs(struct atm_dev *dev) 225 + { 226 + int i; 227 + 228 + write_lock_irq(&vcc_sklist_lock); 229 + for (i = 0; i < VCC_HTABLE_SIZE; i++) { 230 + struct hlist_head *head = &vcc_hash[i]; 231 + struct hlist_node *node, *tmp; 232 + struct sock *s; 233 + struct atm_vcc *vcc; 234 + 235 + sk_for_each_safe(s, node, tmp, head) { 236 + vcc = atm_sk(s); 237 + if (vcc->dev == dev) { 238 + vcc_release_async(vcc, -EPIPE); 239 + sk_del_node_init(s); 240 + } 241 + } 242 + } 243 + write_unlock_irq(&vcc_sklist_lock); 244 + } 245 + 246 + 247 static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) 248 { 249 int max_sdu; ··· 332 return -EINVAL; 333 if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) 334 return -EPERM; 335 + error = -ENODEV; 336 if (!try_module_get(dev->ops->owner)) 337 + return error; 338 vcc->dev = dev; 339 write_lock_irq(&vcc_sklist_lock); 340 + if (test_bit(ATM_DF_REMOVED, &dev->flags) || 341 + (error = find_ci(vcc, &vpi, &vci))) { 342 write_unlock_irq(&vcc_sklist_lock); 343 goto fail_module_put; 344 }
+2
net/atm/common.h
··· 47 /* SVC */ 48 int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); 49 50 #endif
··· 47 /* SVC */ 48 int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos); 49 50 + void atm_dev_release_vccs(struct atm_dev *dev); 51 + 52 #endif
+11 -26
net/atm/resources.c
··· 70 return dev; 71 } 72 73 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, 74 int number, unsigned long *flags) 75 { ··· 124 125 void atm_dev_deregister(struct atm_dev *dev) 126 { 127 - unsigned long warning_time; 128 129 - atm_proc_dev_deregister(dev); 130 - 131 down(&atm_dev_mutex); 132 list_del(&dev->dev_list); 133 up(&atm_dev_mutex); 134 135 - warning_time = jiffies; 136 - while (atomic_read(&dev->refcnt) != 1) { 137 - msleep(250); 138 - if ((jiffies - warning_time) > 10 * HZ) { 139 - printk(KERN_EMERG "atm_dev_deregister: waiting for " 140 - "dev %d to become free. Usage count = %d\n", 141 - dev->number, atomic_read(&dev->refcnt)); 142 - warning_time = jiffies; 143 - } 144 - } 145 146 - kfree(dev); 147 - } 148 - 149 - void shutdown_atm_dev(struct atm_dev *dev) 150 - { 151 - if (atomic_read(&dev->refcnt) > 1) { 152 - set_bit(ATM_DF_CLOSE, &dev->flags); 153 - return; 154 - } 155 - if (dev->ops->dev_close) 156 - dev->ops->dev_close(dev); 157 - atm_dev_deregister(dev); 158 } 159 160 ··· 419 EXPORT_SYMBOL(atm_dev_register); 420 EXPORT_SYMBOL(atm_dev_deregister); 421 EXPORT_SYMBOL(atm_dev_lookup); 422 - EXPORT_SYMBOL(shutdown_atm_dev);
··· 70 return dev; 71 } 72 73 + 74 struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, 75 int number, unsigned long *flags) 76 { ··· 123 124 void atm_dev_deregister(struct atm_dev *dev) 125 { 126 + BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); 127 + set_bit(ATM_DF_REMOVED, &dev->flags); 128 129 + /* 130 + * if we remove current device from atm_devs list, new device 131 + * with same number can appear, such we need deregister proc, 132 + * release async all vccs and remove them from vccs list too 133 + */ 134 down(&atm_dev_mutex); 135 list_del(&dev->dev_list); 136 up(&atm_dev_mutex); 137 138 + atm_dev_release_vccs(dev); 139 + atm_proc_dev_deregister(dev); 140 141 + atm_dev_put(dev); 142 } 143 144 ··· 433 EXPORT_SYMBOL(atm_dev_register); 434 EXPORT_SYMBOL(atm_dev_deregister); 435 EXPORT_SYMBOL(atm_dev_lookup);