[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>
This commit is contained in:
Stanislaw Gruszka
2005-11-29 16:16:41 -08:00
committed by David S. Miller
parent aaaaaadbe7
commit 64bf69ddff
6 changed files with 51 additions and 56 deletions

View File

@@ -221,6 +221,29 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
EXPORT_SYMBOL(vcc_release_async);
void atm_dev_release_vccs(struct atm_dev *dev)
{
int i;
write_lock_irq(&vcc_sklist_lock);
for (i = 0; i < VCC_HTABLE_SIZE; i++) {
struct hlist_head *head = &vcc_hash[i];
struct hlist_node *node, *tmp;
struct sock *s;
struct atm_vcc *vcc;
sk_for_each_safe(s, node, tmp, head) {
vcc = atm_sk(s);
if (vcc->dev == dev) {
vcc_release_async(vcc, -EPIPE);
sk_del_node_init(s);
}
}
}
write_unlock_irq(&vcc_sklist_lock);
}
static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
{
int max_sdu;
@@ -332,12 +355,13 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
return -EINVAL;
if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
error = 0;
error = -ENODEV;
if (!try_module_get(dev->ops->owner))
return -ENODEV;
return error;
vcc->dev = dev;
write_lock_irq(&vcc_sklist_lock);
if ((error = find_ci(vcc, &vpi, &vci))) {
if (test_bit(ATM_DF_REMOVED, &dev->flags) ||
(error = find_ci(vcc, &vpi, &vci))) {
write_unlock_irq(&vcc_sklist_lock);
goto fail_module_put;
}

View File

@@ -47,4 +47,6 @@ static inline void atm_proc_exit(void)
/* SVC */
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos);
void atm_dev_release_vccs(struct atm_dev *dev);
#endif

View File

@@ -70,6 +70,7 @@ struct atm_dev *atm_dev_lookup(int number)
return dev;
}
struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
int number, unsigned long *flags)
{
@@ -123,37 +124,22 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
void atm_dev_deregister(struct atm_dev *dev)
{
unsigned long warning_time;
atm_proc_dev_deregister(dev);
BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
set_bit(ATM_DF_REMOVED, &dev->flags);
/*
* if we remove current device from atm_devs list, new device
* with same number can appear, such we need deregister proc,
* release async all vccs and remove them from vccs list too
*/
down(&atm_dev_mutex);
list_del(&dev->dev_list);
up(&atm_dev_mutex);
warning_time = jiffies;
while (atomic_read(&dev->refcnt) != 1) {
msleep(250);
if ((jiffies - warning_time) > 10 * HZ) {
printk(KERN_EMERG "atm_dev_deregister: waiting for "
"dev %d to become free. Usage count = %d\n",
dev->number, atomic_read(&dev->refcnt));
warning_time = jiffies;
}
}
atm_dev_release_vccs(dev);
atm_proc_dev_deregister(dev);
kfree(dev);
}
void shutdown_atm_dev(struct atm_dev *dev)
{
if (atomic_read(&dev->refcnt) > 1) {
set_bit(ATM_DF_CLOSE, &dev->flags);
return;
}
if (dev->ops->dev_close)
dev->ops->dev_close(dev);
atm_dev_deregister(dev);
atm_dev_put(dev);
}
@@ -433,4 +419,3 @@ void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
EXPORT_SYMBOL(atm_dev_register);
EXPORT_SYMBOL(atm_dev_deregister);
EXPORT_SYMBOL(atm_dev_lookup);
EXPORT_SYMBOL(shutdown_atm_dev);