patch-2.4.22 linux-2.4.22/net/atm/resources.c
Next file: linux-2.4.22/net/atm/resources.h
Previous file: linux-2.4.22/net/atm/raw.c
Back to the patch index
Back to the overall index
- Lines: 277
- Date:
2003-08-25 04:44:44.000000000 -0700
- Orig file:
linux-2.4.21/net/atm/resources.c
- Orig date:
2003-06-13 07:51:39.000000000 -0700
diff -urN linux-2.4.21/net/atm/resources.c linux-2.4.22/net/atm/resources.c
@@ -23,67 +23,83 @@
LIST_HEAD(atm_devs);
-struct atm_vcc *nodev_vccs = NULL;
-extern spinlock_t atm_dev_lock;
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
-static struct atm_dev *alloc_atm_dev(const char *type)
+static struct atm_dev *__alloc_atm_dev(const char *type)
{
struct atm_dev *dev;
dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
- if (!dev) return NULL;
- memset(dev,0,sizeof(*dev));
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(*dev));
dev->type = type;
dev->signal = ATM_PHY_SIG_UNKNOWN;
dev->link_rate = ATM_OC3_PCR;
- list_add_tail(&dev->dev_list, &atm_devs);
+ spin_lock_init(&dev->lock);
return dev;
}
-static void free_atm_dev(struct atm_dev *dev)
+static void __free_atm_dev(struct atm_dev *dev)
{
- list_del(&dev->dev_list);
kfree(dev);
}
-struct atm_dev *atm_find_dev(int number)
+static struct atm_dev *__atm_dev_lookup(int number)
{
struct atm_dev *dev;
struct list_head *p;
list_for_each(p, &atm_devs) {
dev = list_entry(p, struct atm_dev, dev_list);
- if (dev->ops && dev->number == number)
+ if ((dev->ops) && (dev->number == number)) {
+ atm_dev_hold(dev);
return dev;
+ }
}
return NULL;
}
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
- int number,atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_lookup(int number)
{
- struct atm_dev *dev = NULL;
+ struct atm_dev *dev;
spin_lock(&atm_dev_lock);
+ dev = __atm_dev_lookup(number);
+ spin_unlock(&atm_dev_lock);
+ return dev;
+}
- dev = alloc_atm_dev(type);
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+ int number, atm_dev_flags_t *flags)
+{
+ struct atm_dev *dev, *inuse;
+
+
+ dev = __alloc_atm_dev(type);
if (!dev) {
printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
type);
- goto done;
+ return NULL;
}
+ spin_lock(&atm_dev_lock);
if (number != -1) {
- if (atm_find_dev(number)) {
- free_atm_dev(dev);
+ if ((inuse = __atm_dev_lookup(number))) {
+ atm_dev_release(inuse);
+ spin_unlock(&atm_dev_lock);
+ __free_atm_dev(dev);
return NULL;
}
dev->number = number;
} else {
dev->number = 0;
- while (atm_find_dev(dev->number)) dev->number++;
+ while ((inuse = __atm_dev_lookup(dev->number))) {
+ atm_dev_release(inuse);
+ dev->number++;
+ }
}
dev->vccs = dev->last = NULL;
dev->dev_data = NULL;
@@ -92,41 +108,66 @@
if (flags)
dev->flags = *flags;
else
- memset(&dev->flags,0,sizeof(dev->flags));
- memset((void *) &dev->stats,0,sizeof(dev->stats));
+ memset(&dev->flags, 0, sizeof(dev->flags));
+ memset(&dev->stats, 0, sizeof(dev->stats));
+ atomic_set(&dev->refcnt, 1);
+ list_add_tail(&dev->dev_list, &atm_devs);
+ spin_unlock(&atm_dev_lock);
+
#ifdef CONFIG_PROC_FS
- if (ops->proc_read)
+ if (ops->proc_read) {
if (atm_proc_dev_register(dev) < 0) {
printk(KERN_ERR "atm_dev_register: "
- "atm_proc_dev_register failed for dev %s\n",type);
- free_atm_dev(dev);
- goto done;
+ "atm_proc_dev_register failed for dev %s\n",
+ type);
+ spin_lock(&atm_dev_lock);
+ list_del(&dev->dev_list);
+ spin_unlock(&atm_dev_lock);
+ __free_atm_dev(dev);
+ return NULL;
}
+ }
#endif
-done:
- spin_unlock(&atm_dev_lock);
return dev;
}
void atm_dev_deregister(struct atm_dev *dev)
{
+ unsigned long warning_time;
+
#ifdef CONFIG_PROC_FS
if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
#endif
spin_lock(&atm_dev_lock);
- free_atm_dev(dev);
+ list_del(&dev->dev_list);
spin_unlock(&atm_dev_lock);
+
+ warning_time = jiffies;
+ while (atomic_read(&dev->refcnt) != 1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ / 4);
+ current->state = TASK_RUNNING;
+ 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;
+ }
+ }
+
+ __free_atm_dev(dev);
}
void shutdown_atm_dev(struct atm_dev *dev)
{
- if (dev->vccs) {
- set_bit(ATM_DF_CLOSE,&dev->flags);
+ if (atomic_read(&dev->refcnt) > 1) {
+ set_bit(ATM_DF_CLOSE, &dev->flags);
return;
}
- if (dev->ops->dev_close) dev->ops->dev_close(dev);
+ if (dev->ops->dev_close)
+ dev->ops->dev_close(dev);
atm_dev_deregister(dev);
}
@@ -143,66 +184,69 @@
struct atm_vcc *vcc;
sk = sk_alloc(family, GFP_KERNEL, 1);
- if (!sk) return NULL;
- vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc),GFP_KERNEL);
+ if (!sk)
+ return NULL;
+ vcc = sk->protinfo.af_atm = kmalloc(sizeof(*vcc), GFP_KERNEL);
if (!vcc) {
sk_free(sk);
return NULL;
}
- sock_init_data(NULL,sk);
+ sock_init_data(NULL, sk);
sk->destruct = atm_free_sock;
- memset(vcc,0,sizeof(*vcc));
+ memset(vcc, 0, sizeof(*vcc));
vcc->sk = sk;
- if (nodev_vccs) nodev_vccs->prev = vcc;
- vcc->prev = NULL;
- vcc->next = nodev_vccs;
- nodev_vccs = vcc;
+
return sk;
}
-static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
+static void unlink_vcc(struct atm_vcc *vcc)
{
- if (vcc->prev) vcc->prev->next = vcc->next;
- else if (vcc->dev) vcc->dev->vccs = vcc->next;
- else nodev_vccs = vcc->next;
- if (vcc->next) vcc->next->prev = vcc->prev;
- else if (vcc->dev) vcc->dev->last = vcc->prev;
- if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
- test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
- shutdown_atm_dev(vcc->dev);
+ unsigned long flags;
+ if (vcc->dev) {
+ spin_lock_irqsave(&vcc->dev->lock, flags);
+ if (vcc->prev)
+ vcc->prev->next = vcc->next;
+ else
+ vcc->dev->vccs = vcc->next;
+
+ if (vcc->next)
+ vcc->next->prev = vcc->prev;
+ else
+ vcc->dev->last = vcc->prev;
+ spin_unlock_irqrestore(&vcc->dev->lock, flags);
+ }
}
+
void free_atm_vcc_sk(struct sock *sk)
{
- unlink_vcc(sk->protinfo.af_atm,NULL);
+ unlink_vcc(sk->protinfo.af_atm);
sk_free(sk);
}
void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
{
- unlink_vcc(vcc,dev);
+ unsigned long flags;
+
+ unlink_vcc(vcc);
vcc->dev = dev;
if (dev) {
+ spin_lock_irqsave(&dev->lock, flags);
vcc->next = NULL;
vcc->prev = dev->last;
if (dev->vccs) dev->last->next = vcc;
else dev->vccs = vcc;
dev->last = vcc;
- }
- else {
- if (nodev_vccs) nodev_vccs->prev = vcc;
- vcc->next = nodev_vccs;
- vcc->prev = NULL;
- nodev_vccs = vcc;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
}
EXPORT_SYMBOL(atm_dev_register);
EXPORT_SYMBOL(atm_dev_deregister);
-EXPORT_SYMBOL(atm_find_dev);
+EXPORT_SYMBOL(atm_dev_lookup);
EXPORT_SYMBOL(shutdown_atm_dev);
EXPORT_SYMBOL(bind_vcc);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)