Skip to content

Commit

Permalink
sound: oss: dmasound: kill SLEEP() macro to avoid race
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Arnd Bergmann authored and Takashi Iwai committed Jan 14, 2014
1 parent 76439c2 commit 1a1e0a8
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 10 deletions.
1 change: 0 additions & 1 deletion sound/oss/dmasound/dmasound.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 19 additions & 9 deletions sound/oss/dmasound/dmasound_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 1a1e0a8

Please sign in to comment.