dahdi_dynamic: Replace usecount and dead members with 'struct kref'

dahdi_dynamic can be converted to use kernel idiomatic reference
counting since DAHDI only supports 2.6.9+ kernels now.

Signed-off-by: Shaun Ruffell <sruffell@digium.com>
Acked-by: Kinsey Moore <kmoore@digium.com>

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9571 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Shaun Ruffell 2011-01-03 18:25:23 +00:00
parent 7251a7e35a
commit 53fef32a61

View File

@ -97,8 +97,7 @@ struct dahdi_dynamic {
char addr[40]; char addr[40];
char dname[20]; char dname[20];
int err; int err;
int usecount; struct kref kref;
int dead;
long rxjif; long rxjif;
unsigned short txcnt; unsigned short txcnt;
unsigned short rxcnt; unsigned short rxcnt;
@ -135,7 +134,7 @@ static void checkmaster(void)
if (d->timing) { if (d->timing) {
d->master = 0; d->master = 0;
if (!(d->span.alarms & DAHDI_ALARM_RED) && if (!(d->span.alarms & DAHDI_ALARM_RED) &&
(d->timing < best) && !d->dead) { (d->timing < best)) {
/* If not in alarm and they're /* If not in alarm and they're
a better timing source, use them */ a better timing source, use them */
master = d; master = d;
@ -226,7 +225,6 @@ static void __dahdi_dynamic_run(void)
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(d, &dspan_list, list) { list_for_each_entry_rcu(d, &dspan_list, list) {
if (!d->dead) {
for (y = 0; y < d->span.channels; y++) { for (y = 0; y < d->span.channels; y++) {
struct dahdi_chan *const c = d->span.chans[y]; struct dahdi_chan *const c = d->span.chans[y];
/* Echo cancel double buffered data */ /* Echo cancel double buffered data */
@ -237,7 +235,6 @@ static void __dahdi_dynamic_run(void)
/* Handle all transmissions now */ /* Handle all transmissions now */
dahdi_dynamic_sendmessage(d); dahdi_dynamic_sendmessage(d);
} }
}
list_for_each_entry_rcu(drv, &driver_list, list) { list_for_each_entry_rcu(drv, &driver_list, list) {
/* Flush any traffic still pending in the driver */ /* Flush any traffic still pending in the driver */
@ -399,29 +396,47 @@ void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msgl
dahdi_dynamic_run(); dahdi_dynamic_run();
} }
static void dynamic_destroy(struct dahdi_dynamic *d) /**
* dahdi_dynamic_release() - Free the memory associated with the dahdi_dynamic.
* @kref: Pointer to kref embedded in dahdi_dynamic structure.
*
*/
static void dahdi_dynamic_release(struct kref *kref)
{ {
struct dahdi_dynamic *d = container_of(kref, struct dahdi_dynamic,
kref);
unsigned int x; unsigned int x;
/* Unregister span if appropriate */ WARN_ON(test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags));
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags))
dahdi_unregister(&d->span);
/* Destroy the pvt stuff if there */ if (d->pvt) {
if (d->pvt) if (d->driver && d->driver->destroy)
d->driver->destroy(d->pvt); d->driver->destroy(d->pvt);
else
WARN_ON(1);
}
/* Free message buffer if appropriate */
kfree(d->msgbuf); kfree(d->msgbuf);
/* Free channels */
for (x = 0; x < d->span.channels; x++) for (x = 0; x < d->span.channels; x++)
kfree(d->chans[x]); kfree(d->chans[x]);
/* Free d */
kfree(d); kfree(d);
}
checkmaster(); static inline int dynamic_put(struct dahdi_dynamic *d)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
kref_put(&d->kref, dahdi_dynamic_release);
return 1;
#else
return kref_put(&d->kref, dahdi_dynamic_release);
#endif
}
static inline void dynamic_get(struct dahdi_dynamic *d)
{
kref_get(&d->kref);
} }
static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *dds) static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *dds)
@ -432,6 +447,7 @@ static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *dds)
list_for_each_entry_rcu(d, &dspan_list, list) { list_for_each_entry_rcu(d, &dspan_list, list) {
if (!strcmp(d->dname, dds->driver) && if (!strcmp(d->dname, dds->driver) &&
!strcmp(d->addr, dds->addr)) { !strcmp(d->addr, dds->addr)) {
dynamic_get(d);
found = d; found = d;
break; break;
} }
@ -467,19 +483,20 @@ static int destroy_dynamic(struct dahdi_dynamic_span *dds)
if (unlikely(!d)) if (unlikely(!d))
return -EINVAL; return -EINVAL;
if (d->usecount) { if (atomic_read(&d->kref.refcount) > 1)
printk(KERN_NOTICE "Attempt to destroy dynamic span while it is in use\n");
return -EBUSY; return -EBUSY;
}
dahdi_unregister(&d->span);
spin_lock_irqsave(&dspan_lock, flags); spin_lock_irqsave(&dspan_lock, flags);
list_del_rcu(&d->list); list_del_rcu(&d->list);
spin_unlock_irqrestore(&dspan_lock, flags); spin_unlock_irqrestore(&dspan_lock, flags);
synchronize_rcu(); synchronize_rcu();
/* Destroy it */ /* One since we've removed the item from the list... */
dynamic_destroy(d); dynamic_put(d);
/* ...and one for find_dynamic. */
dynamic_put(d);
return 0; return 0;
} }
@ -492,11 +509,7 @@ static int dahdi_dynamic_rbsbits(struct dahdi_chan *chan, int bits)
static int dahdi_dynamic_open(struct dahdi_chan *chan) static int dahdi_dynamic_open(struct dahdi_chan *chan)
{ {
struct dahdi_dynamic *d = dynamic_from_span(chan->span); struct dahdi_dynamic *d = dynamic_from_span(chan->span);
if (likely(d)) { dynamic_get(d);
if (unlikely(d->dead))
return -ENODEV;
d->usecount++;
}
return 0; return 0;
} }
@ -508,11 +521,7 @@ static int dahdi_dynamic_chanconfig(struct dahdi_chan *chan, int sigtype)
static int dahdi_dynamic_close(struct dahdi_chan *chan) static int dahdi_dynamic_close(struct dahdi_chan *chan)
{ {
struct dahdi_dynamic *d = dynamic_from_span(chan->span); struct dahdi_dynamic *d = dynamic_from_span(chan->span);
if (d) { dynamic_put(d);
d->usecount--;
if (d->dead && !d->usecount)
dynamic_destroy(d);
}
return 0; return 0;
} }
@ -545,20 +554,24 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
} }
d = find_dynamic(dds); d = find_dynamic(dds);
if (d) if (d) {
dynamic_put(d);
return -EEXIST; return -EEXIST;
}
/* Allocate memory */
d = kzalloc(sizeof(*d), GFP_KERNEL); d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
kref_init(&d->kref);
for (x = 0; x < dds->numchans; x++) { for (x = 0; x < dds->numchans; x++) {
d->chans[x] = kzalloc(sizeof(*d->chans[x]), GFP_KERNEL); d->chans[x] = kzalloc(sizeof(*d->chans[x]), GFP_KERNEL);
if (!d->chans[x]) { if (!d->chans[x]) {
dynamic_destroy(d); dynamic_put(d);
return -ENOMEM; return -ENOMEM;
} }
d->span.channels++;
} }
/* Allocate message buffer with sample space and header space */ /* Allocate message buffer with sample space and header space */
@ -567,7 +580,7 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
d->msgbuf = kzalloc(bufsize, GFP_KERNEL); d->msgbuf = kzalloc(bufsize, GFP_KERNEL);
if (!d->msgbuf) { if (!d->msgbuf) {
dynamic_destroy(d); dynamic_put(d);
return -ENOMEM; return -ENOMEM;
} }
@ -578,7 +591,6 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
sprintf(d->span.name, "DYN/%s/%s", dds->driver, dds->addr); sprintf(d->span.name, "DYN/%s/%s", dds->driver, dds->addr);
sprintf(d->span.desc, "Dynamic '%s' span at '%s'", sprintf(d->span.desc, "Dynamic '%s' span at '%s'",
dds->driver, dds->addr); dds->driver, dds->addr);
d->span.channels = dds->numchans;
d->span.deflaw = DAHDI_LAW_MULAW; d->span.deflaw = DAHDI_LAW_MULAW;
d->span.flags |= DAHDI_FLAG_RBS; d->span.flags |= DAHDI_FLAG_RBS;
d->span.chans = d->chans; d->span.chans = d->chans;
@ -617,7 +629,7 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
if (!dtd) { if (!dtd) {
printk(KERN_NOTICE "No such driver '%s' for dynamic span\n", printk(KERN_NOTICE "No such driver '%s' for dynamic span\n",
dds->driver); dds->driver);
dynamic_destroy(d); dynamic_put(d);
return -EINVAL; return -EINVAL;
} }
@ -626,7 +638,7 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
if (!d->pvt) { if (!d->pvt) {
printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n", printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n",
dtd->name, dtd->desc, d->addr); dtd->name, dtd->desc, d->addr);
/* Creation failed */ dynamic_put(d);
return -EINVAL; return -EINVAL;
} }
@ -637,18 +649,21 @@ static int create_dynamic(struct dahdi_dynamic_span *dds)
if (dahdi_register(&d->span, 0)) { if (dahdi_register(&d->span, 0)) {
printk(KERN_NOTICE "Unable to register span '%s'\n", printk(KERN_NOTICE "Unable to register span '%s'\n",
d->span.name); d->span.name);
dynamic_destroy(d); dynamic_put(d);
return -EINVAL; return -EINVAL;
} }
x = d->span.spanno;
/* Transfer our reference to the dspan_list. Do not touch d after
* this point. It also must remain on the list while registered. */
spin_lock_irqsave(&dspan_lock, flags); spin_lock_irqsave(&dspan_lock, flags);
list_add_rcu(&d->list, &dspan_list); list_add_rcu(&d->list, &dspan_list);
spin_unlock_irqrestore(&dspan_lock, flags); spin_unlock_irqrestore(&dspan_lock, flags);
checkmaster(); checkmaster();
/* All done */ return x;
return d->span.spanno;
} }
@ -733,11 +748,7 @@ void dahdi_dynamic_unregister(struct dahdi_dynamic_driver *dri)
list_del_rcu(&d->list); list_del_rcu(&d->list);
spin_unlock_irqrestore(&dspan_lock, flags); spin_unlock_irqrestore(&dspan_lock, flags);
synchronize_rcu(); synchronize_rcu();
dynamic_put(d);
if (!d->usecount)
dynamic_destroy(d);
else
d->dead = 1;
} }
} }
} }