aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/core/pcm_native.c16
-rw-r--r--sound/core/seq/seq_memory.c13
-rw-r--r--sound/core/seq/seq_ports.c13
-rw-r--r--sound/pci/hda/hda_intel.c4
4 files changed, 33 insertions, 13 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index fadd3eb8e8bb..9106d8e2300e 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -74,6 +74,18 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
74static DEFINE_RWLOCK(snd_pcm_link_rwlock); 74static DEFINE_RWLOCK(snd_pcm_link_rwlock);
75static DECLARE_RWSEM(snd_pcm_link_rwsem); 75static DECLARE_RWSEM(snd_pcm_link_rwsem);
76 76
77/* Writer in rwsem may block readers even during its waiting in queue,
78 * and this may lead to a deadlock when the code path takes read sem
79 * twice (e.g. one in snd_pcm_action_nonatomic() and another in
80 * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to
81 * spin until it gets the lock.
82 */
83static inline void down_write_nonblock(struct rw_semaphore *lock)
84{
85 while (!down_write_trylock(lock))
86 cond_resched();
87}
88
77/** 89/**
78 * snd_pcm_stream_lock - Lock the PCM stream 90 * snd_pcm_stream_lock - Lock the PCM stream
79 * @substream: PCM substream 91 * @substream: PCM substream
@@ -1813,7 +1825,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
1813 res = -ENOMEM; 1825 res = -ENOMEM;
1814 goto _nolock; 1826 goto _nolock;
1815 } 1827 }
1816 down_write(&snd_pcm_link_rwsem); 1828 down_write_nonblock(&snd_pcm_link_rwsem);
1817 write_lock_irq(&snd_pcm_link_rwlock); 1829 write_lock_irq(&snd_pcm_link_rwlock);
1818 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || 1830 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1819 substream->runtime->status->state != substream1->runtime->status->state || 1831 substream->runtime->status->state != substream1->runtime->status->state ||
@@ -1860,7 +1872,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
1860 struct snd_pcm_substream *s; 1872 struct snd_pcm_substream *s;
1861 int res = 0; 1873 int res = 0;
1862 1874
1863 down_write(&snd_pcm_link_rwsem); 1875 down_write_nonblock(&snd_pcm_link_rwsem);
1864 write_lock_irq(&snd_pcm_link_rwlock); 1876 write_lock_irq(&snd_pcm_link_rwlock);
1865 if (!snd_pcm_stream_linked(substream)) { 1877 if (!snd_pcm_stream_linked(substream)) {
1866 res = -EALREADY; 1878 res = -EALREADY;
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 801076687bb1..c850345c43b5 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -383,15 +383,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
383 383
384 if (snd_BUG_ON(!pool)) 384 if (snd_BUG_ON(!pool))
385 return -EINVAL; 385 return -EINVAL;
386 if (pool->ptr) /* should be atomic? */
387 return 0;
388 386
389 pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size); 387 cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
390 if (!pool->ptr) 388 if (!cellptr)
391 return -ENOMEM; 389 return -ENOMEM;
392 390
393 /* add new cells to the free cell list */ 391 /* add new cells to the free cell list */
394 spin_lock_irqsave(&pool->lock, flags); 392 spin_lock_irqsave(&pool->lock, flags);
393 if (pool->ptr) {
394 spin_unlock_irqrestore(&pool->lock, flags);
395 vfree(cellptr);
396 return 0;
397 }
398
399 pool->ptr = cellptr;
395 pool->free = NULL; 400 pool->free = NULL;
396 401
397 for (cell = 0; cell < pool->size; cell++) { 402 for (cell = 0; cell < pool->size; cell++) {
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 921fb2bd8fad..fe686ee41c6d 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -535,19 +535,22 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
535 bool is_src, bool ack) 535 bool is_src, bool ack)
536{ 536{
537 struct snd_seq_port_subs_info *grp; 537 struct snd_seq_port_subs_info *grp;
538 struct list_head *list;
539 bool empty;
538 540
539 grp = is_src ? &port->c_src : &port->c_dest; 541 grp = is_src ? &port->c_src : &port->c_dest;
542 list = is_src ? &subs->src_list : &subs->dest_list;
540 down_write(&grp->list_mutex); 543 down_write(&grp->list_mutex);
541 write_lock_irq(&grp->list_lock); 544 write_lock_irq(&grp->list_lock);
542 if (is_src) 545 empty = list_empty(list);
543 list_del(&subs->src_list); 546 if (!empty)
544 else 547 list_del_init(list);
545 list_del(&subs->dest_list);
546 grp->exclusive = 0; 548 grp->exclusive = 0;
547 write_unlock_irq(&grp->list_lock); 549 write_unlock_irq(&grp->list_lock);
548 up_write(&grp->list_mutex); 550 up_write(&grp->list_mutex);
549 551
550 unsubscribe_port(client, port, grp, &subs->info, ack); 552 if (!empty)
553 unsubscribe_port(client, port, grp, &subs->info, ack);
551} 554}
552 555
553/* connect two ports */ 556/* connect two ports */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 4045dca3d699..ce6b97f31390 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2168,10 +2168,10 @@ static void azx_remove(struct pci_dev *pci)
2168 struct hda_intel *hda; 2168 struct hda_intel *hda;
2169 2169
2170 if (card) { 2170 if (card) {
2171 /* flush the pending probing work */ 2171 /* cancel the pending probing work */
2172 chip = card->private_data; 2172 chip = card->private_data;
2173 hda = container_of(chip, struct hda_intel, chip); 2173 hda = container_of(chip, struct hda_intel, chip);
2174 flush_work(&hda->probe_work); 2174 cancel_work_sync(&hda->probe_work);
2175 2175
2176 snd_card_free(card); 2176 snd_card_free(card);
2177 } 2177 }