Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9001b8e4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull sound fixes from Takashi Iwai:
 "This update contains again a few more fixes for ALSA core stuff
  although it's no longer high flux: two race fixes in sequencer and one
  PCM race fix for non-atomic PCM ops.

  In addition, HD-audio gained a similar fix for race at reloading the
  driver"

* tag 'sound-4.5-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: pcm: Fix rwsem deadlock for non-atomic PCM stream
  ALSA: seq: Fix double port list deletion
  ALSA: hda - Cancel probe work instead of flush at remove
  ALSA: seq: Fix leak of pool buffer at concurrent writes
parents 705d43db 67ec1072
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -74,6 +74,18 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
static DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);

/* Writer in rwsem may block readers even during its waiting in queue,
 * and this may lead to a deadlock when the code path takes read sem
 * twice (e.g. one in snd_pcm_action_nonatomic() and another in
 * snd_pcm_stream_lock()).  As a (suboptimal) workaround, let writer to
 * spin until it gets the lock.
 */
static inline void down_write_nonblock(struct rw_semaphore *lock)
{
	while (!down_write_trylock(lock))
		cond_resched();
}

/**
 * snd_pcm_stream_lock - Lock the PCM stream
 * @substream: PCM substream
@@ -1813,7 +1825,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
		res = -ENOMEM;
		goto _nolock;
	}
	down_write(&snd_pcm_link_rwsem);
	down_write_nonblock(&snd_pcm_link_rwsem);
	write_lock_irq(&snd_pcm_link_rwlock);
	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
	    substream->runtime->status->state != substream1->runtime->status->state ||
@@ -1860,7 +1872,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
	struct snd_pcm_substream *s;
	int res = 0;

	down_write(&snd_pcm_link_rwsem);
	down_write_nonblock(&snd_pcm_link_rwsem);
	write_lock_irq(&snd_pcm_link_rwlock);
	if (!snd_pcm_stream_linked(substream)) {
		res = -EALREADY;
+9 −4
Original line number Diff line number Diff line
@@ -383,15 +383,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)

	if (snd_BUG_ON(!pool))
		return -EINVAL;
	if (pool->ptr)			/* should be atomic? */
		return 0;

	pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
	if (!pool->ptr)
	cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
	if (!cellptr)
		return -ENOMEM;

	/* add new cells to the free cell list */
	spin_lock_irqsave(&pool->lock, flags);
	if (pool->ptr) {
		spin_unlock_irqrestore(&pool->lock, flags);
		vfree(cellptr);
		return 0;
	}

	pool->ptr = cellptr;
	pool->free = NULL;

	for (cell = 0; cell < pool->size; cell++) {
+8 −5
Original line number Diff line number Diff line
@@ -535,18 +535,21 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
					bool is_src, bool ack)
{
	struct snd_seq_port_subs_info *grp;
	struct list_head *list;
	bool empty;

	grp = is_src ? &port->c_src : &port->c_dest;
	list = is_src ? &subs->src_list : &subs->dest_list;
	down_write(&grp->list_mutex);
	write_lock_irq(&grp->list_lock);
	if (is_src)
		list_del(&subs->src_list);
	else
		list_del(&subs->dest_list);
	empty = list_empty(list);
	if (!empty)
		list_del_init(list);
	grp->exclusive = 0;
	write_unlock_irq(&grp->list_lock);
	up_write(&grp->list_mutex);

	if (!empty)
		unsubscribe_port(client, port, grp, &subs->info, ack);
}

+2 −2
Original line number Diff line number Diff line
@@ -2168,10 +2168,10 @@ static void azx_remove(struct pci_dev *pci)
	struct hda_intel *hda;

	if (card) {
		/* flush the pending probing work */
		/* cancel the pending probing work */
		chip = card->private_data;
		hda = container_of(chip, struct hda_intel, chip);
		flush_work(&hda->probe_work);
		cancel_work_sync(&hda->probe_work);

		snd_card_free(card);
	}