Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <arnd@arndb.de>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Arnd Bergmann and committed by
Greg Kroah-Hartman
591cee0a f8e87cb4

+18 -8
+18 -8
drivers/tty/amiserial.c
··· 1248 1248 struct async_icount cprev, cnow; /* kernel counter temps */ 1249 1249 void __user *argp = (void __user *)arg; 1250 1250 unsigned long flags; 1251 + DEFINE_WAIT(wait); 1252 + int ret; 1251 1253 1252 1254 if (serial_paranoia_check(info, tty->name, "rs_ioctl")) 1253 1255 return -ENODEV; ··· 1290 1288 cprev = info->icount; 1291 1289 local_irq_restore(flags); 1292 1290 while (1) { 1293 - interruptible_sleep_on(&info->tport.delta_msr_wait); 1294 - /* see if a signal did it */ 1295 - if (signal_pending(current)) 1296 - return -ERESTARTSYS; 1291 + prepare_to_wait(&info->tport.delta_msr_wait, 1292 + &wait, TASK_INTERRUPTIBLE); 1297 1293 local_irq_save(flags); 1298 1294 cnow = info->icount; /* atomic copy */ 1299 1295 local_irq_restore(flags); 1300 1296 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 1301 - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) 1302 - return -EIO; /* no change => error */ 1297 + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { 1298 + ret = -EIO; /* no change => error */ 1299 + break; 1300 + } 1303 1301 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 1304 1302 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 1305 1303 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 1306 1304 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { 1307 - return 0; 1305 + ret = 0; 1306 + break; 1307 + } 1308 + schedule(); 1309 + /* see if a signal did it */ 1310 + if (signal_pending(current)) { 1311 + ret = -ERESTARTSYS; 1312 + break; 1308 1313 } 1309 1314 cprev = cnow; 1310 1315 } 1311 - /* NOTREACHED */ 1316 + finish_wait(&info->tport.delta_msr_wait, &wait); 1317 + return ret; 1312 1318 1313 1319 case TIOCSERGWILD: 1314 1320 case TIOCSERSWILD: