@@ -85,7 +85,6 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
85
85
*
86
86
*/
87
87
88
- static DEFINE_RWLOCK (snd_pcm_link_rwlock );
89
88
static DECLARE_RWSEM (snd_pcm_link_rwsem );
90
89
91
90
/* Writer in rwsem may block readers even during its waiting in queue,
@@ -105,8 +104,24 @@ void snd_pcm_group_init(struct snd_pcm_group *group)
105
104
spin_lock_init (& group -> lock );
106
105
mutex_init (& group -> mutex );
107
106
INIT_LIST_HEAD (& group -> substreams );
107
+ refcount_set (& group -> refs , 0 );
108
108
}
109
109
110
+ /* define group lock helpers */
111
+ #define DEFINE_PCM_GROUP_LOCK (action , mutex_action ) \
112
+ static void snd_pcm_group_ ## action(struct snd_pcm_group *group, bool nonatomic) \
113
+ { \
114
+ if (nonatomic) \
115
+ mutex_ ## mutex_action(&group->mutex); \
116
+ else \
117
+ spin_ ## action(&group->lock); \
118
+ }
119
+
120
+ DEFINE_PCM_GROUP_LOCK (lock , lock );
121
+ DEFINE_PCM_GROUP_LOCK (unlock , unlock );
122
+ DEFINE_PCM_GROUP_LOCK (lock_irq , lock );
123
+ DEFINE_PCM_GROUP_LOCK (unlock_irq , unlock );
124
+
110
125
#define PCM_LOCK_DEFAULT 0
111
126
#define PCM_LOCK_IRQ 1
112
127
#define PCM_LOCK_IRQSAVE 2
@@ -116,21 +131,19 @@ static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substr
116
131
{
117
132
unsigned long flags = 0 ;
118
133
if (substream -> pcm -> nonatomic ) {
119
- down_read_nested (& snd_pcm_link_rwsem , SINGLE_DEPTH_NESTING );
120
134
mutex_lock (& substream -> self_group .mutex );
121
135
} else {
122
136
switch (mode ) {
123
137
case PCM_LOCK_DEFAULT :
124
- read_lock ( & snd_pcm_link_rwlock );
138
+ spin_lock ( & substream -> self_group . lock );
125
139
break ;
126
140
case PCM_LOCK_IRQ :
127
- read_lock_irq ( & snd_pcm_link_rwlock );
141
+ spin_lock_irq ( & substream -> self_group . lock );
128
142
break ;
129
143
case PCM_LOCK_IRQSAVE :
130
- read_lock_irqsave ( & snd_pcm_link_rwlock , flags );
144
+ spin_lock_irqsave ( & substream -> self_group . lock , flags );
131
145
break ;
132
146
}
133
- spin_lock (& substream -> self_group .lock );
134
147
}
135
148
return flags ;
136
149
}
@@ -140,19 +153,16 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream,
140
153
{
141
154
if (substream -> pcm -> nonatomic ) {
142
155
mutex_unlock (& substream -> self_group .mutex );
143
- up_read (& snd_pcm_link_rwsem );
144
156
} else {
145
- spin_unlock (& substream -> self_group .lock );
146
-
147
157
switch (mode ) {
148
158
case PCM_LOCK_DEFAULT :
149
- read_unlock ( & snd_pcm_link_rwlock );
159
+ spin_unlock ( & substream -> self_group . lock );
150
160
break ;
151
161
case PCM_LOCK_IRQ :
152
- read_unlock_irq ( & snd_pcm_link_rwlock );
162
+ spin_unlock_irq ( & substream -> self_group . lock );
153
163
break ;
154
164
case PCM_LOCK_IRQSAVE :
155
- read_unlock_irqrestore ( & snd_pcm_link_rwlock , flags );
165
+ spin_unlock_irqrestore ( & substream -> self_group . lock , flags );
156
166
break ;
157
167
}
158
168
}
@@ -1138,35 +1148,77 @@ static void snd_pcm_group_assign(struct snd_pcm_substream *substream,
1138
1148
list_move (& substream -> link_list , & new_group -> substreams );
1139
1149
}
1140
1150
1151
+ /*
1152
+ * Unref and unlock the group, but keep the stream lock;
1153
+ * when the group becomes empty and no longer referred, destroy itself
1154
+ */
1155
+ static void snd_pcm_group_unref (struct snd_pcm_group * group ,
1156
+ struct snd_pcm_substream * substream )
1157
+ {
1158
+ bool do_free ;
1159
+
1160
+ if (!group )
1161
+ return ;
1162
+ do_free = refcount_dec_and_test (& group -> refs ) &&
1163
+ list_empty (& group -> substreams );
1164
+ snd_pcm_group_unlock (group , substream -> pcm -> nonatomic );
1165
+ if (do_free )
1166
+ kfree (group );
1167
+ }
1168
+
1169
+ /*
1170
+ * Lock the group inside a stream lock and reference it;
1171
+ * return the locked group object, or NULL if not linked
1172
+ */
1173
+ static struct snd_pcm_group *
1174
+ snd_pcm_stream_group_ref (struct snd_pcm_substream * substream )
1175
+ {
1176
+ bool nonatomic = substream -> pcm -> nonatomic ;
1177
+ struct snd_pcm_group * group ;
1178
+ bool trylock ;
1179
+
1180
+ for (;;) {
1181
+ if (!snd_pcm_stream_linked (substream ))
1182
+ return NULL ;
1183
+ group = substream -> group ;
1184
+ /* block freeing the group object */
1185
+ refcount_inc (& group -> refs );
1186
+
1187
+ trylock = nonatomic ? mutex_trylock (& group -> mutex ) :
1188
+ spin_trylock (& group -> lock );
1189
+ if (trylock )
1190
+ break ; /* OK */
1191
+
1192
+ /* re-lock for avoiding ABBA deadlock */
1193
+ snd_pcm_stream_unlock (substream );
1194
+ snd_pcm_group_lock (group , nonatomic );
1195
+ snd_pcm_stream_lock (substream );
1196
+
1197
+ /* check the group again; the above opens a small race window */
1198
+ if (substream -> group == group )
1199
+ break ; /* OK */
1200
+ /* group changed, try again */
1201
+ snd_pcm_group_unref (group , substream );
1202
+ }
1203
+ return group ;
1204
+ }
1205
+
1141
1206
/*
1142
1207
* Note: call with stream lock
1143
1208
*/
1144
1209
static int snd_pcm_action (const struct action_ops * ops ,
1145
1210
struct snd_pcm_substream * substream ,
1146
1211
int state )
1147
1212
{
1213
+ struct snd_pcm_group * group ;
1148
1214
int res ;
1149
1215
1150
- if (!snd_pcm_stream_linked (substream ))
1151
- return snd_pcm_action_single (ops , substream , state );
1152
-
1153
- if (substream -> pcm -> nonatomic ) {
1154
- if (!mutex_trylock (& substream -> group -> mutex )) {
1155
- mutex_unlock (& substream -> self_group .mutex );
1156
- mutex_lock (& substream -> group -> mutex );
1157
- mutex_lock (& substream -> self_group .mutex );
1158
- }
1216
+ group = snd_pcm_stream_group_ref (substream );
1217
+ if (group )
1159
1218
res = snd_pcm_action_group (ops , substream , state , 1 );
1160
- mutex_unlock (& substream -> group -> mutex );
1161
- } else {
1162
- if (!spin_trylock (& substream -> group -> lock )) {
1163
- spin_unlock (& substream -> self_group .lock );
1164
- spin_lock (& substream -> group -> lock );
1165
- spin_lock (& substream -> self_group .lock );
1166
- }
1167
- res = snd_pcm_action_group (ops , substream , state , 1 );
1168
- spin_unlock (& substream -> group -> lock );
1169
- }
1219
+ else
1220
+ res = snd_pcm_action_single (ops , substream , state );
1221
+ snd_pcm_group_unref (group , substream );
1170
1222
return res ;
1171
1223
}
1172
1224
@@ -1193,6 +1245,7 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops,
1193
1245
{
1194
1246
int res ;
1195
1247
1248
+ /* Guarantee the group members won't change during non-atomic action */
1196
1249
down_read (& snd_pcm_link_rwsem );
1197
1250
if (snd_pcm_stream_linked (substream ))
1198
1251
res = snd_pcm_action_group (ops , substream , state , 0 );
@@ -1821,6 +1874,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1821
1874
struct snd_card * card ;
1822
1875
struct snd_pcm_runtime * runtime ;
1823
1876
struct snd_pcm_substream * s ;
1877
+ struct snd_pcm_group * group ;
1824
1878
wait_queue_entry_t wait ;
1825
1879
int result = 0 ;
1826
1880
int nonblock = 0 ;
@@ -1837,7 +1891,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1837
1891
} else if (substream -> f_flags & O_NONBLOCK )
1838
1892
nonblock = 1 ;
1839
1893
1840
- down_read (& snd_pcm_link_rwsem );
1841
1894
snd_pcm_stream_lock_irq (substream );
1842
1895
/* resume pause */
1843
1896
if (runtime -> status -> state == SNDRV_PCM_STATE_PAUSED )
@@ -1862,6 +1915,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1862
1915
}
1863
1916
/* find a substream to drain */
1864
1917
to_check = NULL ;
1918
+ group = snd_pcm_stream_group_ref (substream );
1865
1919
snd_pcm_group_for_each_entry (s , substream ) {
1866
1920
if (s -> stream != SNDRV_PCM_STREAM_PLAYBACK )
1867
1921
continue ;
@@ -1871,12 +1925,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1871
1925
break ;
1872
1926
}
1873
1927
}
1928
+ snd_pcm_group_unref (group , substream );
1874
1929
if (!to_check )
1875
1930
break ; /* all drained */
1876
1931
init_waitqueue_entry (& wait , current );
1877
1932
add_wait_queue (& to_check -> sleep , & wait );
1878
1933
snd_pcm_stream_unlock_irq (substream );
1879
- up_read (& snd_pcm_link_rwsem );
1880
1934
if (runtime -> no_period_wakeup )
1881
1935
tout = MAX_SCHEDULE_TIMEOUT ;
1882
1936
else {
@@ -1888,9 +1942,17 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1888
1942
tout = msecs_to_jiffies (tout * 1000 );
1889
1943
}
1890
1944
tout = schedule_timeout_interruptible (tout );
1891
- down_read ( & snd_pcm_link_rwsem );
1945
+
1892
1946
snd_pcm_stream_lock_irq (substream );
1893
- remove_wait_queue (& to_check -> sleep , & wait );
1947
+ group = snd_pcm_stream_group_ref (substream );
1948
+ snd_pcm_group_for_each_entry (s , substream ) {
1949
+ if (s -> runtime == to_check ) {
1950
+ remove_wait_queue (& to_check -> sleep , & wait );
1951
+ break ;
1952
+ }
1953
+ }
1954
+ snd_pcm_group_unref (group , substream );
1955
+
1894
1956
if (card -> shutdown ) {
1895
1957
result = - ENODEV ;
1896
1958
break ;
@@ -1910,7 +1972,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1910
1972
1911
1973
unlock :
1912
1974
snd_pcm_stream_unlock_irq (substream );
1913
- up_read (& snd_pcm_link_rwsem );
1914
1975
1915
1976
return result ;
1916
1977
}
@@ -1972,7 +2033,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
1972
2033
int res = 0 ;
1973
2034
struct snd_pcm_file * pcm_file ;
1974
2035
struct snd_pcm_substream * substream1 ;
1975
- struct snd_pcm_group * group ;
2036
+ struct snd_pcm_group * group , * target_group ;
2037
+ bool nonatomic = substream -> pcm -> nonatomic ;
1976
2038
struct fd f = fdget (fd );
1977
2039
1978
2040
if (!f .file )
@@ -1989,8 +2051,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
1989
2051
goto _nolock ;
1990
2052
}
1991
2053
snd_pcm_group_init (group );
2054
+
1992
2055
down_write_nonfifo (& snd_pcm_link_rwsem );
1993
- write_lock_irq (& snd_pcm_link_rwlock );
1994
2056
if (substream -> runtime -> status -> state == SNDRV_PCM_STATE_OPEN ||
1995
2057
substream -> runtime -> status -> state != substream1 -> runtime -> status -> state ||
1996
2058
substream -> pcm -> nonatomic != substream1 -> pcm -> nonatomic ) {
@@ -2001,13 +2063,21 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
2001
2063
res = - EALREADY ;
2002
2064
goto _end ;
2003
2065
}
2066
+
2067
+ snd_pcm_stream_lock_irq (substream );
2004
2068
if (!snd_pcm_stream_linked (substream )) {
2005
2069
snd_pcm_group_assign (substream , group );
2006
- group = NULL ;
2070
+ group = NULL ; /* assigned, don't free this one below */
2007
2071
}
2008
- snd_pcm_group_assign (substream1 , substream -> group );
2072
+ target_group = substream -> group ;
2073
+ snd_pcm_stream_unlock_irq (substream );
2074
+
2075
+ snd_pcm_group_lock_irq (target_group , nonatomic );
2076
+ snd_pcm_stream_lock (substream1 );
2077
+ snd_pcm_group_assign (substream1 , target_group );
2078
+ snd_pcm_stream_unlock (substream1 );
2079
+ snd_pcm_group_unlock_irq (target_group , nonatomic );
2009
2080
_end :
2010
- write_unlock_irq (& snd_pcm_link_rwlock );
2011
2081
up_write (& snd_pcm_link_rwsem );
2012
2082
_nolock :
2013
2083
kfree (group );
@@ -2018,22 +2088,27 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
2018
2088
2019
2089
static void relink_to_local (struct snd_pcm_substream * substream )
2020
2090
{
2091
+ snd_pcm_stream_lock (substream );
2021
2092
snd_pcm_group_assign (substream , & substream -> self_group );
2093
+ snd_pcm_stream_unlock (substream );
2022
2094
}
2023
2095
2024
2096
static int snd_pcm_unlink (struct snd_pcm_substream * substream )
2025
2097
{
2026
2098
struct snd_pcm_group * group ;
2099
+ bool nonatomic = substream -> pcm -> nonatomic ;
2100
+ bool do_free = false;
2027
2101
int res = 0 ;
2028
2102
2029
2103
down_write_nonfifo (& snd_pcm_link_rwsem );
2030
- write_lock_irq ( & snd_pcm_link_rwlock );
2104
+
2031
2105
if (!snd_pcm_stream_linked (substream )) {
2032
2106
res = - EALREADY ;
2033
2107
goto _end ;
2034
2108
}
2035
2109
2036
2110
group = substream -> group ;
2111
+ snd_pcm_group_lock_irq (group , nonatomic );
2037
2112
2038
2113
relink_to_local (substream );
2039
2114
@@ -2042,11 +2117,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
2042
2117
relink_to_local (list_first_entry (& group -> substreams ,
2043
2118
struct snd_pcm_substream ,
2044
2119
link_list ));
2045
- kfree ( group );
2120
+ do_free = ! refcount_read ( & group -> refs );
2046
2121
}
2047
2122
2123
+ snd_pcm_group_unlock_irq (group , nonatomic );
2124
+ if (do_free )
2125
+ kfree (group );
2126
+
2048
2127
_end :
2049
- write_unlock_irq (& snd_pcm_link_rwlock );
2050
2128
up_write (& snd_pcm_link_rwsem );
2051
2129
return res ;
2052
2130
}
0 commit comments