diff options
| -rw-r--r-- | sound/core/pcm_native.c | 16 | ||||
| -rw-r--r-- | sound/core/seq/seq_memory.c | 13 | ||||
| -rw-r--r-- | sound/core/seq/seq_ports.c | 13 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 4 |
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); | |||
| 74 | static DEFINE_RWLOCK(snd_pcm_link_rwlock); | 74 | static DEFINE_RWLOCK(snd_pcm_link_rwlock); |
| 75 | static DECLARE_RWSEM(snd_pcm_link_rwsem); | 75 | static 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 | */ | ||
| 83 | static 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 | } |
