diff options
| author | Takashi Iwai <tiwai@suse.de> | 2018-01-08 08:03:53 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2018-01-08 10:40:26 -0500 |
| commit | 900498a34a3ac9c611e9b425094c8106bdd7dc1c (patch) | |
| tree | 844ccba051c0491b8e7d74879e6a8d20f11c6e53 | |
| parent | 29159a4ed7044c52e3e2cf1a9fb55cec4745c60b (diff) | |
ALSA: pcm: Allow aborting mutex lock at OSS read/write loops
PCM OSS read/write loops keep taking the mutex lock for the whole
read/write, and this might take very long when the exceptionally high
amount of data is given. Also, since it invokes with mutex_lock(),
the concurrent read/write becomes unbreakable.
This patch tries to address these issues by replacing mutex_lock()
with mutex_lock_interruptible(), and also splits / re-takes the lock
at each read/write period chunk, so that it can switch the context
more finely if requested.
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/core/oss/pcm_oss.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e317964bd2ea..c2db7e905f7d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
| @@ -1334,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha | |||
| 1334 | 1334 | ||
| 1335 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) | 1335 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) |
| 1336 | return tmp; | 1336 | return tmp; |
| 1337 | mutex_lock(&runtime->oss.params_lock); | ||
| 1338 | while (bytes > 0) { | 1337 | while (bytes > 0) { |
| 1338 | if (mutex_lock_interruptible(&runtime->oss.params_lock)) { | ||
| 1339 | tmp = -ERESTARTSYS; | ||
| 1340 | break; | ||
| 1341 | } | ||
| 1339 | if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { | 1342 | if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { |
| 1340 | tmp = bytes; | 1343 | tmp = bytes; |
| 1341 | if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) | 1344 | if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) |
| @@ -1379,18 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha | |||
| 1379 | xfer += tmp; | 1382 | xfer += tmp; |
| 1380 | if ((substream->f_flags & O_NONBLOCK) != 0 && | 1383 | if ((substream->f_flags & O_NONBLOCK) != 0 && |
| 1381 | tmp != runtime->oss.period_bytes) | 1384 | tmp != runtime->oss.period_bytes) |
| 1382 | break; | 1385 | tmp = -EAGAIN; |
| 1383 | } | 1386 | } |
| 1387 | err: | ||
| 1388 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1389 | if (tmp < 0) | ||
| 1390 | break; | ||
| 1384 | if (signal_pending(current)) { | 1391 | if (signal_pending(current)) { |
| 1385 | tmp = -ERESTARTSYS; | 1392 | tmp = -ERESTARTSYS; |
| 1386 | goto err; | 1393 | break; |
| 1387 | } | 1394 | } |
| 1395 | tmp = 0; | ||
| 1388 | } | 1396 | } |
| 1389 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1390 | return xfer; | ||
| 1391 | |||
| 1392 | err: | ||
| 1393 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1394 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; | 1397 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; |
| 1395 | } | 1398 | } |
| 1396 | 1399 | ||
| @@ -1438,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use | |||
| 1438 | 1441 | ||
| 1439 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) | 1442 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) |
| 1440 | return tmp; | 1443 | return tmp; |
| 1441 | mutex_lock(&runtime->oss.params_lock); | ||
| 1442 | while (bytes > 0) { | 1444 | while (bytes > 0) { |
| 1445 | if (mutex_lock_interruptible(&runtime->oss.params_lock)) { | ||
| 1446 | tmp = -ERESTARTSYS; | ||
| 1447 | break; | ||
| 1448 | } | ||
| 1443 | if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { | 1449 | if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { |
| 1444 | if (runtime->oss.buffer_used == 0) { | 1450 | if (runtime->oss.buffer_used == 0) { |
| 1445 | tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); | 1451 | tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); |
| @@ -1470,16 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use | |||
| 1470 | bytes -= tmp; | 1476 | bytes -= tmp; |
| 1471 | xfer += tmp; | 1477 | xfer += tmp; |
| 1472 | } | 1478 | } |
| 1479 | err: | ||
| 1480 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1481 | if (tmp < 0) | ||
| 1482 | break; | ||
| 1473 | if (signal_pending(current)) { | 1483 | if (signal_pending(current)) { |
| 1474 | tmp = -ERESTARTSYS; | 1484 | tmp = -ERESTARTSYS; |
| 1475 | goto err; | 1485 | break; |
| 1476 | } | 1486 | } |
| 1487 | tmp = 0; | ||
| 1477 | } | 1488 | } |
| 1478 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1479 | return xfer; | ||
| 1480 | |||
| 1481 | err: | ||
| 1482 | mutex_unlock(&runtime->oss.params_lock); | ||
| 1483 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; | 1489 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; |
| 1484 | } | 1490 | } |
| 1485 | 1491 | ||
