mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-28 21:02:43 +01:00
tty/amiserial: avoid interruptible_sleep_on
interruptible_sleep_on is generally problematic and we want to get rid of it. In case of TIOCMIWAIT, that race is actually in user space and does not get fixed since we can only detect changes after entering the ioctl handler, but it removes one more caller. This instance can not be trivially replaced with wait_event, so I chose to open-code the wait loop using prepare_to_wait/finish_wait. Signed-off-by: Arnd Bergmann <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
This commit is contained in:
1 parent
f8e87cb4a1
commit
591cee0a35
1 file changed
+18
-8
+18
-8
@@ -1248,6 +1248,8 @@ static int rs_ioctl(struct tty_struct *tty,
|
||||
struct async_icount cprev, cnow; /* kernel counter temps */
|
||||
void __user *argp = (void __user *)arg;
|
||||
unsigned long flags;
|
||||
DEFINE_WAIT(wait);
|
||||
int ret;
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
|
||||
return -ENODEV;
|
||||
@@ -1288,25 +1290,33 @@ static int rs_ioctl(struct tty_struct *tty,
|
||||
cprev = info->icount;
|
||||
local_irq_restore(flags);
|
||||
while (1) {
|
||||
interruptible_sleep_on(&info->tport.delta_msr_wait);
|
||||
/* see if a signal did it */
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
prepare_to_wait(&info->tport.delta_msr_wait,
|
||||
&wait, TASK_INTERRUPTIBLE);
|
||||
local_irq_save(flags);
|
||||
cnow = info->icount; /* atomic copy */
|
||||
local_irq_restore(flags);
|
||||
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
|
||||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
||||
return -EIO; /* no change => error */
|
||||
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
|
||||
ret = -EIO; /* no change => error */
|
||||
break;
|
||||
}
|
||||
if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
||||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
||||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
|
||||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
|
||||
return 0;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
schedule();
|
||||
/* see if a signal did it */
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
cprev = cnow;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
finish_wait(&info->tport.delta_msr_wait, &wait);
|
||||
return ret;
|
||||
|
||||
case TIOCSERGWILD:
|
||||
case TIOCSERSWILD:
|
||||
|
||||
Reference in new issue
Block a user