[svn-commits] kpfleming: branch 1.4 r3667 - in /branches/1.4: zaptel-base.c zconfig.h
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Fri Jan 11 15:35:19 CST 2008
Author: kpfleming
Date: Fri Jan 11 15:35:18 2008
New Revision: 3667
URL: http://svn.digium.com/view/zaptel?view=rev&rev=3667
Log:
Implement atomic reference counting for tone zone structures, ensuring that they will never be freed while they are in use by a channel or as the default zone.
In passing, improve default zone handling so that there will never be a default zone value pointing to a zone that hasn't been loaded yet.
(closes issue #10593)
Reported by: jmhunter
Patches were provided by Matti, but a different solution was chosen
Modified:
branches/1.4/zaptel-base.c
branches/1.4/zconfig.h
Modified: branches/1.4/zaptel-base.c
URL: http://svn.digium.com/view/zaptel/branches/1.4/zaptel-base.c?view=diff&rev=3667&r1=3666&r2=3667
==============================================================================
--- branches/1.4/zaptel-base.c (original)
+++ branches/1.4/zaptel-base.c Fri Jan 11 15:35:18 2008
@@ -59,6 +59,7 @@
#include <linux/if.h>
#include <linux/if_ppp.h>
#endif
+#include <asm/atomic.h>
#ifndef CONFIG_OLD_HDLC_API
#define NEW_HDLC_INTERFACE
@@ -361,6 +362,7 @@
#endif
struct zt_zone {
+ atomic_t refcount;
char name[40]; /* Informational, only */
int ringcadence[ZT_MAX_CADENCE];
struct zt_tone *tones[ZT_TONE_MAX];
@@ -382,7 +384,7 @@
static int maxconfs = 0;
static int maxlinks = 0;
-static int default_zone = DEFAULT_TONE_ZONE;
+static int default_zone = -1;
short __zt_mulaw[256];
short __zt_alaw[256];
@@ -994,6 +996,8 @@
readchunkpreec = chan->readchunkpreec;
chan->readchunkpreec = NULL;
chan->curtone = NULL;
+ if (chan->curzone)
+ atomic_dec(&chan->curzone->refcount);
chan->curzone = NULL;
chan->cadencepos = 0;
chan->pdialcount = 0;
@@ -1072,18 +1076,35 @@
{
struct zt_zone *z;
+ if ((num >= ZT_TONE_ZONE_MAX) || (num < 0))
+ return -EINVAL;
+
+ write_lock(&zone_lock);
z = tone_zones[num];
tone_zones[num] = NULL;
- kfree(z);
-
- return 0;
+ write_unlock(&zone_lock);
+
+ if (atomic_read(&z->refcount)) {
+ /* channels are still using this zone so put it back */
+ write_lock(&zone_lock);
+ tone_zones[num] = z;
+ write_unlock(&zone_lock);
+
+ return -EBUSY;
+ } else {
+ kfree(z);
+
+ return 0;
+ }
}
static int zt_register_tone_zone(int num, struct zt_zone *zone)
{
- int res=0;
+ int res = 0;
+
if ((num >= ZT_TONE_ZONE_MAX) || (num < 0))
return -EINVAL;
+
write_lock(&zone_lock);
if (tone_zones[num]) {
res = -EINVAL;
@@ -1092,8 +1113,10 @@
tone_zones[num] = zone;
}
write_unlock(&zone_lock);
+
if (!res)
printk(KERN_INFO "Registered tone zone %d (%s)\n", num, zone->name);
+
return res;
}
@@ -1147,20 +1170,27 @@
static int set_tone_zone(struct zt_chan *chan, int zone)
{
- int res=0;
+ int res = 0;
+ struct zt_zone *z;
+
/* Assumes channel is already locked */
- if ((zone >= ZT_TONE_ZONE_MAX) || (zone < -1))
+
+ if (zone == -1)
+ zone = default_zone;
+
+ if ((zone >= ZT_TONE_ZONE_MAX) || (zone < 0))
return -EINVAL;
read_lock(&zone_lock);
- if (zone == -1) {
- zone = default_zone;
- }
- if (tone_zones[zone]) {
- chan->curzone = tone_zones[zone];
+ if ((z = tone_zones[zone])) {
+ if (chan->curzone)
+ atomic_dec(&chan->curzone->refcount);
+
+ atomic_inc(&z->refcount);
+ chan->curzone = z;
chan->tonezone = zone;
- memcpy(chan->ringcadence, chan->curzone->ringcadence, sizeof(chan->ringcadence));
+ memcpy(chan->ringcadence, z->ringcadence, sizeof(chan->ringcadence));
} else {
res = -ENODATA;
}
@@ -2601,6 +2631,8 @@
for (x = 0; x < ZT_MAX_CADENCE; x++)
z->ringcadence[x] = th.ringcadence[x];
+
+ atomic_set(&z->refcount, 0);
for (x = 0; x < th.count; x++) {
enum {
@@ -3622,6 +3654,9 @@
write_unlock(&zone_lock);
return -EINVAL;
}
+ if ((default_zone != -1) && tone_zones[default_zone])
+ atomic_dec(&tone_zones[default_zone]->refcount);
+ atomic_inc(&tone_zones[j]->refcount);
default_zone = j;
write_unlock(&zone_lock);
break;
@@ -3629,19 +3664,7 @@
return ioctl_load_zone(data);
case ZT_FREEZONE:
get_user(j, (int *) data);
- if ((j < 0) || (j >= ZT_TONE_ZONE_MAX))
- return -EINVAL;
- write_lock(&zone_lock);
-#if 0
- if (j == default_zone) {
- write_unlock(&zone_lock);
- /* XXX: possibly a better return code here */
- return -EINVAL;
- }
-#endif
- free_tone_zone(j);
- write_unlock(&zone_lock);
- break;
+ return free_tone_zone(j);
case ZT_SET_DIALPARAMS:
if (copy_from_user(&tdp, (struct zt_dialparams *) data, sizeof(tdp)))
return -EFAULT;
@@ -3982,19 +4005,17 @@
rv = 0;
break;
case ZT_SETTONEZONE:
- get_user(j,(int *)data);
+ get_user(j, (int *) data);
spin_lock_irqsave(&chan->lock, flags);
- rv = set_tone_zone(chan, j);
+ rv = set_tone_zone(chan, j);
spin_unlock_irqrestore(&chan->lock, flags);
return rv;
case ZT_GETTONEZONE:
spin_lock_irqsave(&chan->lock, flags);
if (chan->curzone)
- rv = chan->tonezone;
- else
- rv = default_zone;
+ j = chan->tonezone;
spin_unlock_irqrestore(&chan->lock, flags);
- put_user(rv,(int *)data); /* return value */
+ put_user(j, (int *) data);
break;
case ZT_SENDTONE:
get_user(j,(int *)data);
Modified: branches/1.4/zconfig.h
URL: http://svn.digium.com/view/zaptel/branches/1.4/zconfig.h?view=diff&rev=3667&r1=3666&r2=3667
==============================================================================
--- branches/1.4/zconfig.h (original)
+++ branches/1.4/zconfig.h Fri Jan 11 15:35:18 2008
@@ -136,9 +136,6 @@
*/
/* #define CONFIG_ZAPTEL_WATCHDOG */
-/* Tone zone info */
-#define DEFAULT_TONE_ZONE 0
-
/*
* Uncomment for Non-standard FXS groundstart start state (A=Low, B=Low)
* particularly for CAC channel bank groundstart FXO ports.
More information about the svn-commits
mailing list