[svn-commits] sruffell: branch linux/sruffell/dahdi-linux-stackreduction r7075 - /linux/tea...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Aug 25 12:16:16 CDT 2009


Author: sruffell
Date: Tue Aug 25 12:16:15 2009
New Revision: 7075

URL: http://svn.asterisk.org/svn-view/dahdi?view=rev&rev=7075
Log:
dahdi-base: Reduce the stack usage of dahdi_common_ioctl.

Split the DAHDI_GETGAINS and DAHDI_SETGAINS ioctls into their own functions
and dynamically allocate the 'struct dahdi_gains' structure to reduce the
pressure on the stack.

Modified:
    linux/team/sruffell/dahdi-linux-stackreduction/drivers/dahdi/dahdi-base.c

Modified: linux/team/sruffell/dahdi-linux-stackreduction/drivers/dahdi/dahdi-base.c
URL: http://svn.asterisk.org/svn-view/dahdi/linux/team/sruffell/dahdi-linux-stackreduction/drivers/dahdi/dahdi-base.c?view=diff&rev=7075&r1=7074&r2=7075
==============================================================================
--- linux/team/sruffell/dahdi-linux-stackreduction/drivers/dahdi/dahdi-base.c (original)
+++ linux/team/sruffell/dahdi-linux-stackreduction/drivers/dahdi/dahdi-base.c Tue Aug 25 12:16:15 2009
@@ -3510,16 +3510,136 @@
 	return 0;
 }
 
+static int dahdi_ioctl_getgains(struct inode *node, struct file *file,
+				unsigned int cmd, unsigned long data, int unit)
+{
+	int res = 0;
+	struct dahdi_gains *gain;
+	int i, j;
+
+	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+	if (!gain)
+		return -ENOMEM;
+
+	if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+		res = -EFAULT;
+		goto cleanup;
+	}
+	i = gain->chan;  /* get channel no */
+	   /* if zero, use current channel no */
+	if (!i)
+		i = unit;
+
+	  /* make sure channel number makes sense */
+	if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+		res = -EINVAL;
+		goto cleanup;
+	}
+
+	if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+		res = -EINVAL;
+		goto cleanup;
+	}
+	gain->chan = i; /* put the span # in here */
+	for (j = 0; j < 256; ++j)  {
+		gain->txgain[j] = chans[i]->txgain[j];
+		gain->rxgain[j] = chans[i]->rxgain[j];
+	}
+	if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+		res = -EFAULT;
+		goto cleanup;
+	}
+cleanup:
+
+	kfree(gain);
+	return 0;
+}
+
+static int dahdi_ioctl_setgains(struct inode *node, struct file *file,
+				unsigned int cmd, unsigned long data, int unit)
+{
+	int res = 0;
+	struct dahdi_gains *gain;
+	unsigned char *txgain, *rxgain;
+	int i, j;
+	unsigned long flags;
+	const int GAIN_TABLE_SIZE = sizeof(defgain);
+
+	gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+	if (!gain)
+		return -ENOMEM;
+
+	if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+		res = -EFAULT;
+		goto cleanup;
+	}
+	i = gain->chan;  /* get channel no */
+	   /* if zero, use current channel no */
+	if (!i)
+		i = unit;
+	  /* make sure channel number makes sense */
+	if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+		res = -EINVAL;
+		goto cleanup;
+	}
+	if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+		res = -EINVAL;
+		goto cleanup;
+	}
+
+	rxgain = kzalloc(GAIN_TABLE_SIZE*2, GFP_KERNEL);
+	if (!rxgain) {
+		res = -ENOMEM;
+		goto cleanup;
+	}
+
+	gain->chan = i; /* put the span # in here */
+	txgain = rxgain + GAIN_TABLE_SIZE;
+
+	for (j = 0; j < GAIN_TABLE_SIZE; ++j) {
+		rxgain[j] = gain->rxgain[j];
+		txgain[j] = gain->txgain[j];
+	}
+
+	if (!memcmp(rxgain, defgain, GAIN_TABLE_SIZE) &&
+	    !memcmp(txgain, defgain, GAIN_TABLE_SIZE)) {
+		kfree(rxgain);
+		spin_lock_irqsave(&chans[i]->lock, flags);
+		if (chans[i]->gainalloc)
+			kfree(chans[i]->rxgain);
+		chans[i]->gainalloc = 0;
+		chans[i]->rxgain = defgain;
+		chans[i]->txgain = defgain;
+		spin_unlock_irqrestore(&chans[i]->lock, flags);
+	} else {
+		/* This is a custom gain setting */
+		spin_lock_irqsave(&chans[i]->lock, flags);
+		if (chans[i]->gainalloc)
+			kfree(chans[i]->rxgain);
+		chans[i]->gainalloc = 1;
+		chans[i]->rxgain = rxgain;
+		chans[i]->txgain = txgain;
+		spin_unlock_irqrestore(&chans[i]->lock, flags);
+	}
+
+	if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+		res = -EFAULT;
+		goto cleanup;
+	}
+cleanup:
+
+	kfree(gain);
+	return 0;
+}
+
 static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit)
 {
 	union {
-		struct dahdi_gains gain;
 		struct dahdi_spaninfo spaninfo;
 		struct dahdi_params param;
 	} stack;
 	struct dahdi_chan *chan;
 	unsigned long flags;
-	unsigned char *txgain, *rxgain;
 	int i,j;
 	int return_master = 0;
 	size_t size_to_copy;
@@ -3645,68 +3765,9 @@
 		break;
 	case DAHDI_GETGAINS_V1: /* Intentional drop through. */
 	case DAHDI_GETGAINS:  /* get gain stuff */
-		if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
-			return -EFAULT;
-		i = stack.gain.chan;  /* get channel no */
-		   /* if zero, use current channel no */
-		if (!i) i = unit;
-		  /* make sure channel number makes sense */
-		if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
-
-		if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
-		stack.gain.chan = i; /* put the span # in here */
-		for (j=0;j<256;j++)  {
-			stack.gain.txgain[j] = chans[i]->txgain[j];
-			stack.gain.rxgain[j] = chans[i]->rxgain[j];
-		}
-		if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
-			return -EFAULT;
-		break;
+		return dahdi_ioctl_getgains(node, file, cmd, data, unit);
 	case DAHDI_SETGAINS:  /* set gain stuff */
-		if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
-			return -EFAULT;
-		i = stack.gain.chan;  /* get channel no */
-		   /* if zero, use current channel no */
-		if (!i) i = unit;
-		  /* make sure channel number makes sense */
-		if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
-		if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
-
-		if (!(rxgain = kmalloc(512, GFP_KERNEL)))
-			return -ENOMEM;
-
-		stack.gain.chan = i; /* put the span # in here */
-		txgain = rxgain + 256;
-
-		for (j=0;j<256;j++) {
-			rxgain[j] = stack.gain.rxgain[j];
-			txgain[j] = stack.gain.txgain[j];
-		}
-
-		if (!memcmp(rxgain, defgain, 256) &&
-		    !memcmp(txgain, defgain, 256)) {
-			if (rxgain)
-				kfree(rxgain);
-			spin_lock_irqsave(&chans[i]->lock, flags);
-			if (chans[i]->gainalloc)
-				kfree(chans[i]->rxgain);
-			chans[i]->gainalloc = 0;
-			chans[i]->rxgain = defgain;
-			chans[i]->txgain = defgain;
-			spin_unlock_irqrestore(&chans[i]->lock, flags);
-		} else {
-			/* This is a custom gain setting */
-			spin_lock_irqsave(&chans[i]->lock, flags);
-			if (chans[i]->gainalloc)
-				kfree(chans[i]->rxgain);
-			chans[i]->gainalloc = 1;
-			chans[i]->rxgain = rxgain;
-			chans[i]->txgain = txgain;
-			spin_unlock_irqrestore(&chans[i]->lock, flags);
-		}
-		if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
-			return -EFAULT;
-		break;
+		return dahdi_ioctl_setgains(node, file, cmd, data, unit);
 	case DAHDI_SPANSTAT:
 		size_to_copy = sizeof(struct dahdi_spaninfo);
 		if (copy_from_user(&stack.spaninfo, (struct dahdi_spaninfo *) data, size_to_copy))




More information about the svn-commits mailing list