From 631ced0f71707ae43dbe6c18488df4be5a0c0343 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Mon, 31 Jan 2011 17:59:01 +0000 Subject: dahdi: Experimentally remove dependency on the Big Kernel Lock. With the release of Linux 2.6.37, the Big Kernel Lock is now a compile time option. This change adds a mutex around the one place in the code that we already knew was dependent on the lock_kernel/unlock_kernel calls for serialization and drops the other calls to lock_kernel/unlock_kernel if CONFIG_BKL is not defined. This is *mostly* the dahdi-no-bkl.patch with a few minor whitespace changes, the global_dialparmslock made static, and a warning added to let people know they are running an experimental configuration. (issue #18604) Reported by: jkroon Patches: dahdi-no-bkl.patch uploaded by jkroon (license 714) Signed-off-by: Jaco Kroon Signed-off-by: Shaun Ruffell Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=9721 git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/branches/2.4@9725 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/dahdi-base.c | 82 ++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 2b39523..ffa2a59 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -48,8 +48,9 @@ #include #include #include +#include -#ifdef HAVE_UNLOCKED_IOCTL +#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) #include #endif @@ -91,7 +92,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) #ifndef CONFIG_BKL -#error You must have CONFIG_BKL lock defined to build DAHDI +#warning "No CONFIG_BKL is an experimental configuration." #endif #endif @@ -317,6 +318,8 @@ static struct dahdi_dialparams global_dialparams = { .mfr2_tonelen = DEFAULT_MFR2_LENGTH, }; +static DEFINE_MUTEX(global_dialparamslock); + static int dahdi_chan_ioctl(struct file *file, unsigned int cmd, unsigned long data, int unit); #if defined(CONFIG_DAHDI_MMX) || defined(ECHO_CAN_FP) @@ -3069,7 +3072,7 @@ static int ioctl_load_zone(unsigned long data) size_t size; int res; int x; - void *slab, *ptr; + void *slab = NULL, *ptr; struct dahdi_zone *z; struct dahdi_tone *t; void __user * user_data = (void __user *)data; @@ -3087,21 +3090,21 @@ static int ioctl_load_zone(unsigned long data) if ((work->th.count < 0) || (work->th.count > MAX_TONES)) { module_printk(KERN_NOTICE, "Too many tones included\n"); - kfree(work); - return -EINVAL; + res = -EINVAL; + goto error_exit; } space = size = sizeof(*z) + work->th.count * sizeof(*t); if (size > MAX_SIZE) { - kfree(work); - return -E2BIG; + res = -E2BIG; + goto error_exit; } z = ptr = slab = kzalloc(size, GFP_KERNEL); if (!z) { - kfree(work); - return -ENOMEM; + res = -ENOMEM; + goto error_exit; } ptr = (char *) ptr + sizeof(*z); @@ -3112,8 +3115,8 @@ static int ioctl_load_zone(unsigned long data) for (x = 0; x < DAHDI_MAX_CADENCE; x++) z->ringcadence[x] = work->th.ringcadence[x]; + mutex_lock(&global_dialparamslock); atomic_set(&z->refcount, 0); - for (x = 0; x < work->th.count; x++) { enum { REGULAR_TONE, @@ -3124,18 +3127,16 @@ static int ioctl_load_zone(unsigned long data) } tone_type; if (space < sizeof(*t)) { - kfree(slab); - kfree(work); module_printk(KERN_NOTICE, "Insufficient tone zone space\n"); - return -EINVAL; + res = -EINVAL; + goto unlock_error_exit; } res = copy_from_user(&work->td, user_data, sizeof(work->td)); if (res) { - kfree(slab); - kfree(work); - return -EFAULT; + res = -EFAULT; + goto unlock_error_exit; } user_data += sizeof(work->td); @@ -3157,9 +3158,8 @@ static int ioctl_load_zone(unsigned long data) module_printk(KERN_NOTICE, "Invalid 'next' pointer: %d\n", work->next[x]); - kfree(slab); - kfree(work); - return -EINVAL; + res = -EINVAL; + goto unlock_error_exit; } } else if ((work->td.tone >= DAHDI_TONE_DTMF_BASE) && (work->td.tone <= DAHDI_TONE_DTMF_MAX)) { @@ -3185,9 +3185,8 @@ static int ioctl_load_zone(unsigned long data) module_printk(KERN_NOTICE, "Invalid tone (%d) defined\n", work->td.tone); - kfree(slab); - kfree(work); - return -EINVAL; + res = -EINVAL; + goto unlock_error_exit; } t->fac1 = work->td.fac1; @@ -3243,6 +3242,7 @@ static int ioctl_load_zone(unsigned long data) break; } } + mutex_unlock(&global_dialparamslock); for (x = 0; x < work->th.count; x++) { if (work->samples[x]) @@ -3259,6 +3259,14 @@ static int ioctl_load_zone(unsigned long data) } kfree(work); + return 0; + +unlock_error_exit: + mutex_unlock(&global_dialparamslock); + +error_exit: + kfree(work); + kfree(slab); return res; } @@ -4542,6 +4550,8 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da if (copy_from_user(&tdp, user_data, sizeof(tdp))) return -EFAULT; + mutex_lock(&global_dialparamslock); + if ((tdp.dtmf_tonelen >= 10) && (tdp.dtmf_tonelen <= 4000)) { global_dialparams.dtmf_tonelen = tdp.dtmf_tonelen; } @@ -4583,13 +4593,17 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da mfr1_silence.tonesamples = global_dialparams.mfv1_tonelen * DAHDI_CHUNKSIZE; mfr2_silence.tonesamples = global_dialparams.mfr2_tonelen * DAHDI_CHUNKSIZE; + mutex_unlock(&global_dialparamslock); + break; } case DAHDI_GET_DIALPARAMS: { struct dahdi_dialparams tdp; + mutex_lock(&global_dialparamslock); tdp = global_dialparams; + mutex_unlock(&global_dialparamslock); if (copy_to_user(user_data, &tdp, sizeof(tdp))) return -EFAULT; break; @@ -5904,19 +5918,15 @@ static int dahdi_prechan_ioctl(struct file *file, unsigned int cmd, unsigned lon return 0; } -#ifdef HAVE_UNLOCKED_IOCTL -static long dahdi_ioctl(struct file *file, unsigned int cmd, unsigned long data) -#else -static int dahdi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long data) -#endif +static long +dahdi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long data) { int unit = UNIT(file); struct dahdi_chan *chan; struct dahdi_timer *timer; int ret; -#ifdef HAVE_UNLOCKED_IOCTL +#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) lock_kernel(); #endif @@ -5968,12 +5978,20 @@ static int dahdi_ioctl(struct inode *inode, struct file *file, ret = dahdi_chan_ioctl(file, cmd, data, unit); unlock_exit: -#ifdef HAVE_UNLOCKED_IOCTL +#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL) unlock_kernel(); #endif return ret; } +#ifndef HAVE_UNLOCKED_IOCTL +static int dahdi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data) +{ + return dahdi_unlocked_ioctl(file, cmd, data); +} +#endif + #ifdef HAVE_COMPAT_IOCTL static long dahdi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long data) @@ -5981,7 +5999,7 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd, if (cmd == DAHDI_SFCONFIG) return -ENOTTY; /* Not supported yet */ - return dahdi_ioctl(file, cmd, data); + return dahdi_unlocked_ioctl(file, cmd, data); } #endif @@ -8678,7 +8696,7 @@ static struct file_operations dahdi_fops = { .open = dahdi_open, .release = dahdi_release, #ifdef HAVE_UNLOCKED_IOCTL - .unlocked_ioctl = dahdi_ioctl, + .unlocked_ioctl = dahdi_unlocked_ioctl, #ifdef HAVE_COMPAT_IOCTL .compat_ioctl = dahdi_ioctl_compat, #endif -- cgit v1.2.3