Skip to content

Commit 0e279dc

Browse files
committed
ALSA: pcm: Fix refcount_inc() on zero usage
The recent rewrite of PCM link lock management introduced the refcount in snd_pcm_group object, managed by the kernel refcount_t API. This caused unexpected kernel warnings when the kernel is built with CONFIG_REFCOUNT_FULL=y. As the warning line indicates, the problem is obviously that we start with refcount=0 and do refcount_inc() for adding each PCM link, while refcount_t API doesn't like refcount_inc() performed on zero. For adapting the proper refcount_t usage, this patch changes the logic slightly: - The initial refcount is 1, assuming the single list entry - The refcount is incremented / decremented at each PCM link addition and deletion - ... which allows us concentrating only on the refcount as a release condition Fixes: f57f3df ("ALSA: pcm: More fine-grained PCM link locking") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204221 Reported-and-tested-by: Duncan Overbruck <[email protected]> Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 70256b4 commit 0e279dc

File tree

1 file changed

+5
-4
lines changed

1 file changed

+5
-4
lines changed

sound/core/pcm_native.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
7777
spin_lock_init(&group->lock);
7878
mutex_init(&group->mutex);
7979
INIT_LIST_HEAD(&group->substreams);
80-
refcount_set(&group->refs, 0);
80+
refcount_set(&group->refs, 1);
8181
}
8282

8383
/* define group lock helpers */
@@ -1096,8 +1096,7 @@ static void snd_pcm_group_unref(struct snd_pcm_group *group,
10961096

10971097
if (!group)
10981098
return;
1099-
do_free = refcount_dec_and_test(&group->refs) &&
1100-
list_empty(&group->substreams);
1099+
do_free = refcount_dec_and_test(&group->refs);
11011100
snd_pcm_group_unlock(group, substream->pcm->nonatomic);
11021101
if (do_free)
11031102
kfree(group);
@@ -2020,6 +2019,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
20202019
snd_pcm_group_lock_irq(target_group, nonatomic);
20212020
snd_pcm_stream_lock(substream1);
20222021
snd_pcm_group_assign(substream1, target_group);
2022+
refcount_inc(&target_group->refs);
20232023
snd_pcm_stream_unlock(substream1);
20242024
snd_pcm_group_unlock_irq(target_group, nonatomic);
20252025
_end:
@@ -2056,13 +2056,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
20562056
snd_pcm_group_lock_irq(group, nonatomic);
20572057

20582058
relink_to_local(substream);
2059+
refcount_dec(&group->refs);
20592060

20602061
/* detach the last stream, too */
20612062
if (list_is_singular(&group->substreams)) {
20622063
relink_to_local(list_first_entry(&group->substreams,
20632064
struct snd_pcm_substream,
20642065
link_list));
2065-
do_free = !refcount_read(&group->refs);
2066+
do_free = refcount_dec_and_test(&group->refs);
20662067
}
20672068

20682069
snd_pcm_group_unlock_irq(group, nonatomic);

0 commit comments

Comments
 (0)