aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/oss/dmasound
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-01-02 13:07:50 +0100
committerTakashi Iwai <tiwai@suse.de>2014-01-14 16:12:07 +0100
commit1a1e0a80ceb766852e8abd5d4c3d9475611a7d85 (patch)
tree0efe9224215eca736bbf6a06538651eb54b9516f /sound/oss/dmasound
parentsound: oss: midibuf: fix sleep_on races (diff)
downloadwireguard-linux-1a1e0a80ceb766852e8abd5d4c3d9475611a7d85.tar.xz
wireguard-linux-1a1e0a80ceb766852e8abd5d4c3d9475611a7d85.zip
sound: oss: dmasound: kill SLEEP() macro to avoid race
The use of interruptible_sleep_on_timeout in the dmasound driver is questionable and we want to kill off all sleep_on variants. This replaces the calls with wait_event_interruptible_timeout where possible, to wait for a particular event instead of blocking in a racy way. In the sq_write function, the easiest solution is an open-coded prepare_to_wait loop. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/oss/dmasound')
-rw-r--r--sound/oss/dmasound/dmasound.h1
-rw-r--r--sound/oss/dmasound/dmasound_core.c28
2 files changed, 19 insertions, 10 deletions
diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h
index 1308d8d34186..01019f06fa91 100644
--- a/sound/oss/dmasound/dmasound.h
+++ b/sound/oss/dmasound/dmasound.h
@@ -239,7 +239,6 @@ struct sound_queue {
int busy, syncing, xruns, died;
};
-#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
#define WAKE_UP(queue) (wake_up_interruptible(&queue))
extern struct sound_queue dmasound_write_sq;
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index bac43b5b6e95..f4ee85a4c42f 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -619,15 +619,27 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
}
while (uLeft) {
+ DEFINE_WAIT(wait);
+
while (write_sq.count >= write_sq.max_active) {
+ prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
sq_play();
- if (write_sq.non_blocking)
+ if (write_sq.non_blocking) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(write_sq.action_queue);
- if (signal_pending(current))
+ }
+ if (write_sq.count < write_sq.max_active)
+ break;
+
+ schedule_timeout(HZ);
+ if (signal_pending(current)) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EINTR;
+ }
}
+ finish_wait(&write_sq.action_queue, &wait);
+
/* Here, we can avoid disabling the interrupt by first
* copying and translating the data, and then updating
* the write_sq variables. Until this is done, the interrupt
@@ -707,11 +719,8 @@ static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
if (file->f_flags & O_NONBLOCK)
return rc;
rc = -EINTR;
- while (sq->busy) {
- SLEEP(sq->open_queue);
- if (signal_pending(current))
- return rc;
- }
+ if (wait_event_interruptible(sq->open_queue, !sq->busy))
+ return rc;
rc = 0;
#else
/* OSS manual says we will return EBUSY regardless
@@ -844,7 +853,8 @@ static int sq_fsync(void)
sq_play(); /* there may be an incomplete frame waiting */
while (write_sq.active) {
- SLEEP(write_sq.sync_queue);
+ wait_event_interruptible_timeout(write_sq.sync_queue,
+ !write_sq.active, HZ);
if (signal_pending(current)) {
/* While waiting for audio output to drain, an
* interrupt occurred. Stop audio output immediately