Created
January 15, 2016 15:28
-
-
Save dvyukov/dc29dbfd320126285fd8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c | |
index b64f20d..13cfa81 100644 | |
--- a/sound/core/seq/seq_clientmgr.c | |
+++ b/sound/core/seq/seq_clientmgr.c | |
@@ -1962,7 +1962,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, | |
* No restrictions so for a user client we can clear | |
* the whole fifo | |
*/ | |
- if (client->type == USER_CLIENT) | |
+ if (client->type == USER_CLIENT && client->data.user.fifo) | |
snd_seq_fifo_clear(client->data.user.fifo); | |
} | |
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c | |
index 7dfd0f4..0bec02e 100644 | |
--- a/sound/core/seq/seq_queue.c | |
+++ b/sound/core/seq/seq_queue.c | |
@@ -142,8 +142,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked) | |
static void queue_delete(struct snd_seq_queue *q) | |
{ | |
/* stop and release the timer */ | |
+ mutex_lock(&q->timer_mutex); | |
snd_seq_timer_stop(q->timer); | |
snd_seq_timer_close(q); | |
+ mutex_unlock(&q->timer_mutex); | |
/* wait until access free */ | |
snd_use_lock_sync(&q->use_lock); | |
/* release resources... */ | |
diff --git a/sound/core/timer.c b/sound/core/timer.c | |
index 31f40f0..4e8d7bf 100644 | |
--- a/sound/core/timer.c | |
+++ b/sound/core/timer.c | |
@@ -73,7 +73,7 @@ struct snd_timer_user { | |
struct timespec tstamp; /* trigger tstamp */ | |
wait_queue_head_t qchange_sleep; | |
struct fasync_struct *fasync; | |
- struct mutex tread_sem; | |
+ struct mutex ioctl_lock; | |
}; | |
/* list of timers */ | |
@@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) | |
slave->slave_id == master->slave_id) { | |
list_move_tail(&slave->open_list, &master->slave_list_head); | |
spin_lock_irq(&slave_active_lock); | |
+ spin_lock(&master->timer->lock); | |
slave->master = master; | |
slave->timer = master->timer; | |
if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) | |
list_add_tail(&slave->active_list, | |
&master->slave_active_head); | |
+ spin_unlock(&master->timer->lock); | |
spin_unlock_irq(&slave_active_lock); | |
} | |
} | |
@@ -346,15 +348,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |
timer->hw.close) | |
timer->hw.close(timer); | |
/* remove slave links */ | |
+ spin_lock_irq(&slave_active_lock); | |
+ spin_lock(&timer->lock); | |
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, | |
open_list) { | |
- spin_lock_irq(&slave_active_lock); | |
- _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); | |
list_move_tail(&slave->open_list, &snd_timer_slave_list); | |
slave->master = NULL; | |
slave->timer = NULL; | |
- spin_unlock_irq(&slave_active_lock); | |
+ list_del_init(&slave->ack_list); | |
+ list_del_init(&slave->active_list); | |
} | |
+ spin_unlock(&timer->lock); | |
+ spin_unlock_irq(&slave_active_lock); | |
mutex_unlock(®ister_mutex); | |
} | |
out: | |
@@ -441,9 +446,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) | |
spin_lock_irqsave(&slave_active_lock, flags); | |
timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; | |
- if (timeri->master) | |
+ if (timeri->master && timeri->timer) { | |
+ spin_lock(&timeri->timer->lock); | |
list_add_tail(&timeri->active_list, | |
&timeri->master->slave_active_head); | |
+ spin_unlock(&timeri->timer->lock); | |
+ } | |
spin_unlock_irqrestore(&slave_active_lock, flags); | |
return 1; /* delayed start */ | |
} | |
@@ -489,6 +497,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, | |
if (!keep_flag) { | |
spin_lock_irqsave(&slave_active_lock, flags); | |
timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | |
+ list_del_init(&timeri->ack_list); | |
+ list_del_init(&timeri->active_list); | |
spin_unlock_irqrestore(&slave_active_lock, flags); | |
} | |
goto __end; | |
@@ -694,7 +704,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |
} else { | |
ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | |
if (--timer->running) | |
- list_del(&ti->active_list); | |
+ list_del_init(&ti->active_list); | |
} | |
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || | |
(ti->flags & SNDRV_TIMER_IFLG_FAST)) | |
@@ -1253,7 +1263,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) | |
return -ENOMEM; | |
spin_lock_init(&tu->qlock); | |
init_waitqueue_head(&tu->qchange_sleep); | |
- mutex_init(&tu->tread_sem); | |
+ mutex_init(&tu->ioctl_lock); | |
tu->ticks = 1; | |
tu->queue_size = 128; | |
tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), | |
@@ -1273,8 +1283,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) | |
if (file->private_data) { | |
tu = file->private_data; | |
file->private_data = NULL; | |
+ mutex_lock(&tu->ioctl_lock); | |
if (tu->timeri) | |
snd_timer_close(tu->timeri); | |
+ mutex_unlock(&tu->ioctl_lock); | |
kfree(tu->queue); | |
kfree(tu->tqueue); | |
kfree(tu); | |
@@ -1512,7 +1524,6 @@ static int snd_timer_user_tselect(struct file *file, | |
int err = 0; | |
tu = file->private_data; | |
- mutex_lock(&tu->tread_sem); | |
if (tu->timeri) { | |
snd_timer_close(tu->timeri); | |
tu->timeri = NULL; | |
@@ -1556,7 +1567,6 @@ static int snd_timer_user_tselect(struct file *file, | |
} | |
__err: | |
- mutex_unlock(&tu->tread_sem); | |
return err; | |
} | |
@@ -1769,7 +1779,7 @@ enum { | |
SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), | |
}; | |
-static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |
+static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |
unsigned long arg) | |
{ | |
struct snd_timer_user *tu; | |
@@ -1786,17 +1796,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |
{ | |
int xarg; | |
- mutex_lock(&tu->tread_sem); | |
- if (tu->timeri) { /* too late */ | |
- mutex_unlock(&tu->tread_sem); | |
+ if (tu->timeri) /* too late */ | |
return -EBUSY; | |
- } | |
- if (get_user(xarg, p)) { | |
- mutex_unlock(&tu->tread_sem); | |
+ if (get_user(xarg, p)) | |
return -EFAULT; | |
- } | |
tu->tread = xarg ? 1 : 0; | |
- mutex_unlock(&tu->tread_sem); | |
return 0; | |
} | |
case SNDRV_TIMER_IOCTL_GINFO: | |
@@ -1829,6 +1833,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |
return -ENOTTY; | |
} | |
+static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |
+ unsigned long arg) | |
+{ | |
+ struct snd_timer_user *tu = file->private_data; | |
+ long ret; | |
+ | |
+ mutex_lock(&tu->ioctl_lock); | |
+ ret = __snd_timer_user_ioctl(file, cmd, arg); | |
+ mutex_unlock(&tu->ioctl_lock); | |
+ return ret; | |
+} | |
+ | |
static int snd_timer_user_fasync(int fd, struct file * file, int on) | |
{ | |
struct snd_timer_user *tu; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment