Skip to content

Commit

Permalink
ALSA: usb-audio: Handle invalid running state at releasing EP
Browse files Browse the repository at this point in the history
commit d6cda46 upstream.

When we stop an endpoint in release_urbs(), it ignores the
inconsistent endpoint state and tries to release the resources.
This shouldn't happen in theory, but it's still safer to abort the
release and let the caller proper error handling.

Also, stop_and_unlink_urbs() called from release_urbs() does two step
works, and it's more straightforward to split this to two functions
again, so that the call from the PCM trigger won't take the path with
sleeping.

This patch modifies the EP management code to adapt two points above.

Fixes: d0f09d1 ("ALSA: usb-audio: Refactoring endpoint URB deactivation")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210206203052.15606-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
tiwai authored and gregkh committed Mar 4, 2021
1 parent 85d5397 commit 5cee450
Showing 1 changed file with 21 additions and 19 deletions.
40 changes: 21 additions & 19 deletions sound/usb/endpoint.c
Expand Up @@ -868,24 +868,22 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
}

/*
* Stop and unlink active urbs.
* Stop active urbs
*
* This function checks and clears EP_FLAG_RUNNING state.
* When @wait_sync is set, it waits until all pending URBs are killed.
* This function moves the EP to STOPPING state if it's being RUNNING.
*/
static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
bool wait_sync)
static int stop_urbs(struct snd_usb_endpoint *ep, bool force)
{
unsigned int i;

if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */
return -EBADFD;

if (atomic_read(&ep->running))
if (!force && atomic_read(&ep->running))
return -EBUSY;

if (!test_and_clear_bit(EP_FLAG_RUNNING, &ep->flags))
goto out;
return 0;

set_bit(EP_FLAG_STOPPING, &ep->flags);
INIT_LIST_HEAD(&ep->ready_playback_urbs);
Expand All @@ -901,24 +899,25 @@ static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
}
}

out:
if (wait_sync)
return wait_clear_urbs(ep);
return 0;
}

/*
* release an endpoint's urbs
*/
static void release_urbs(struct snd_usb_endpoint *ep, int force)
static int release_urbs(struct snd_usb_endpoint *ep, bool force)
{
int i;
int i, err;

/* route incoming urbs to nirvana */
snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);

/* stop urbs */
stop_and_unlink_urbs(ep, force, true);
/* stop and unlink urbs */
err = stop_urbs(ep, force);
if (err)
return err;

wait_clear_urbs(ep);

for (i = 0; i < ep->nurbs; i++)
release_urb_ctx(&ep->urb[i]);
Expand All @@ -928,6 +927,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)

ep->syncbuf = NULL;
ep->nurbs = 0;
return 0;
}

/*
Expand Down Expand Up @@ -1118,7 +1118,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
return 0;

out_of_memory:
release_urbs(ep, 0);
release_urbs(ep, false);
return -ENOMEM;
}

Expand Down Expand Up @@ -1162,7 +1162,7 @@ static int sync_ep_set_params(struct snd_usb_endpoint *ep)
return 0;

out_of_memory:
release_urbs(ep, 0);
release_urbs(ep, false);
return -ENOMEM;
}

Expand All @@ -1180,7 +1180,9 @@ static int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
int err;

/* release old buffers, if any */
release_urbs(ep, 0);
err = release_urbs(ep, false);
if (err < 0)
return err;

ep->datainterval = fmt->datainterval;
ep->maxpacksize = fmt->maxpacksize;
Expand Down Expand Up @@ -1433,7 +1435,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
WRITE_ONCE(ep->sync_source->sync_sink, NULL);

if (!atomic_dec_return(&ep->running))
stop_and_unlink_urbs(ep, false, false);
stop_urbs(ep, false);
}

/**
Expand All @@ -1446,7 +1448,7 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
*/
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
{
release_urbs(ep, 1);
release_urbs(ep, true);
}

/**
Expand Down

0 comments on commit 5cee450

Please sign in to comment.