|
@@ -77,7 +77,8 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
|
|
|
DEFINE_RWLOCK(snd_pcm_link_rwlock);
|
|
|
EXPORT_SYMBOL(snd_pcm_link_rwlock);
|
|
|
|
|
|
-static DECLARE_RWSEM(snd_pcm_link_rwsem);
|
|
|
+DECLARE_RWSEM(snd_pcm_link_rwsem);
|
|
|
+EXPORT_SYMBOL(snd_pcm_link_rwsem);
|
|
|
|
|
|
static inline mm_segment_t snd_enter_user(void)
|
|
|
{
|
|
@@ -727,9 +728,14 @@ static int snd_pcm_action_group(struct action_ops *ops,
|
|
|
int res = 0;
|
|
|
|
|
|
snd_pcm_group_for_each_entry(s, substream) {
|
|
|
- if (do_lock && s != substream)
|
|
|
- spin_lock_nested(&s->self_group.lock,
|
|
|
- SINGLE_DEPTH_NESTING);
|
|
|
+ if (do_lock && s != substream) {
|
|
|
+ if (s->pcm->nonatomic)
|
|
|
+ mutex_lock_nested(&s->self_group.mutex,
|
|
|
+ SINGLE_DEPTH_NESTING);
|
|
|
+ else
|
|
|
+ spin_lock_nested(&s->self_group.lock,
|
|
|
+ SINGLE_DEPTH_NESTING);
|
|
|
+ }
|
|
|
res = ops->pre_action(s, state);
|
|
|
if (res < 0)
|
|
|
goto _unlock;
|
|
@@ -755,8 +761,12 @@ static int snd_pcm_action_group(struct action_ops *ops,
|
|
|
if (do_lock) {
|
|
|
/* unlock streams */
|
|
|
snd_pcm_group_for_each_entry(s1, substream) {
|
|
|
- if (s1 != substream)
|
|
|
- spin_unlock(&s1->self_group.lock);
|
|
|
+ if (s1 != substream) {
|
|
|
+ if (s->pcm->nonatomic)
|
|
|
+ mutex_unlock(&s1->self_group.mutex);
|
|
|
+ else
|
|
|
+ spin_unlock(&s1->self_group.lock);
|
|
|
+ }
|
|
|
if (s1 == s) /* end */
|
|
|
break;
|
|
|
}
|
|
@@ -784,6 +794,27 @@ static int snd_pcm_action_single(struct action_ops *ops,
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+/* call in mutex-protected context */
|
|
|
+static int snd_pcm_action_mutex(struct action_ops *ops,
|
|
|
+ struct snd_pcm_substream *substream,
|
|
|
+ int state)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+
|
|
|
+ if (snd_pcm_stream_linked(substream)) {
|
|
|
+ if (!mutex_trylock(&substream->group->mutex)) {
|
|
|
+ mutex_unlock(&substream->self_group.mutex);
|
|
|
+ mutex_lock(&substream->group->mutex);
|
|
|
+ mutex_lock(&substream->self_group.mutex);
|
|
|
+ }
|
|
|
+ res = snd_pcm_action_group(ops, substream, state, 1);
|
|
|
+ mutex_unlock(&substream->group->mutex);
|
|
|
+ } else {
|
|
|
+ res = snd_pcm_action_single(ops, substream, state);
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Note: call with stream lock
|
|
|
*/
|
|
@@ -793,6 +824,9 @@ static int snd_pcm_action(struct action_ops *ops,
|
|
|
{
|
|
|
int res;
|
|
|
|
|
|
+ if (substream->pcm->nonatomic)
|
|
|
+ return snd_pcm_action_mutex(ops, substream, state);
|
|
|
+
|
|
|
if (snd_pcm_stream_linked(substream)) {
|
|
|
if (!spin_trylock(&substream->group->lock)) {
|
|
|
spin_unlock(&substream->self_group.lock);
|
|
@@ -807,6 +841,29 @@ static int snd_pcm_action(struct action_ops *ops,
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
+static int snd_pcm_action_lock_mutex(struct action_ops *ops,
|
|
|
+ struct snd_pcm_substream *substream,
|
|
|
+ int state)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+
|
|
|
+ down_read(&snd_pcm_link_rwsem);
|
|
|
+ if (snd_pcm_stream_linked(substream)) {
|
|
|
+ mutex_lock(&substream->group->mutex);
|
|
|
+ mutex_lock_nested(&substream->self_group.mutex,
|
|
|
+ SINGLE_DEPTH_NESTING);
|
|
|
+ res = snd_pcm_action_group(ops, substream, state, 1);
|
|
|
+ mutex_unlock(&substream->self_group.mutex);
|
|
|
+ mutex_unlock(&substream->group->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&substream->self_group.mutex);
|
|
|
+ res = snd_pcm_action_single(ops, substream, state);
|
|
|
+ mutex_unlock(&substream->self_group.mutex);
|
|
|
+ }
|
|
|
+ up_read(&snd_pcm_link_rwsem);
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Note: don't use any locks before
|
|
|
*/
|
|
@@ -816,6 +873,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
|
|
|
{
|
|
|
int res;
|
|
|
|
|
|
+ if (substream->pcm->nonatomic)
|
|
|
+ return snd_pcm_action_lock_mutex(ops, substream, state);
|
|
|
+
|
|
|
read_lock_irq(&snd_pcm_link_rwlock);
|
|
|
if (snd_pcm_stream_linked(substream)) {
|
|
|
spin_lock(&substream->group->lock);
|
|
@@ -1634,7 +1694,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
|
|
down_write(&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) {
|
|
|
+ substream->runtime->status->state != substream1->runtime->status->state ||
|
|
|
+ substream->pcm->nonatomic != substream1->pcm->nonatomic) {
|
|
|
res = -EBADFD;
|
|
|
goto _end;
|
|
|
}
|
|
@@ -1646,6 +1707,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
|
|
substream->group = group;
|
|
|
group = NULL;
|
|
|
spin_lock_init(&substream->group->lock);
|
|
|
+ mutex_init(&substream->group->mutex);
|
|
|
INIT_LIST_HEAD(&substream->group->substreams);
|
|
|
list_add_tail(&substream->link_list, &substream->group->substreams);
|
|
|
substream->group->count = 1;
|