aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/amiserial.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-01-02 07:07:38 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-07 20:05:21 -0500
commit591cee0a35632031cd925392a1bce507dcfe9ea8 (patch)
treedeb6628428c2f3b88f98846f1928658dbf43cb34 /drivers/tty/amiserial.c
parentf8e87cb4a19aa5f5a1ce22e130da0f4a7fa2d5f3 (diff)
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>
Diffstat (limited to 'drivers/tty/amiserial.c')
-rw-r--r--drivers/tty/amiserial.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 71630a2af42c..979e7c3ea2cb 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1248,6 +1248,8 @@ static int rs_ioctl(struct tty_struct *tty,
1248 struct async_icount cprev, cnow; /* kernel counter temps */ 1248 struct async_icount cprev, cnow; /* kernel counter temps */
1249 void __user *argp = (void __user *)arg; 1249 void __user *argp = (void __user *)arg;
1250 unsigned long flags; 1250 unsigned long flags;
1251 DEFINE_WAIT(wait);
1252 int ret;
1251 1253
1252 if (serial_paranoia_check(info, tty->name, "rs_ioctl")) 1254 if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
1253 return -ENODEV; 1255 return -ENODEV;
@@ -1288,25 +1290,33 @@ static int rs_ioctl(struct tty_struct *tty,
1288 cprev = info->icount; 1290 cprev = info->icount;
1289 local_irq_restore(flags); 1291 local_irq_restore(flags);
1290 while (1) { 1292 while (1) {
1291 interruptible_sleep_on(&info->tport.delta_msr_wait); 1293 prepare_to_wait(&info->tport.delta_msr_wait,
1292 /* see if a signal did it */ 1294 &wait, TASK_INTERRUPTIBLE);
1293 if (signal_pending(current))
1294 return -ERESTARTSYS;
1295 local_irq_save(flags); 1295 local_irq_save(flags);
1296 cnow = info->icount; /* atomic copy */ 1296 cnow = info->icount; /* atomic copy */
1297 local_irq_restore(flags); 1297 local_irq_restore(flags);
1298 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 1298 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
1299 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) 1299 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
1300 return -EIO; /* no change => error */ 1300 ret = -EIO; /* no change => error */
1301 break;
1302 }
1301 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 1303 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
1302 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 1304 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
1303 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || 1305 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
1304 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { 1306 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
1305 return 0; 1307 ret = 0;
1308 break;
1309 }
1310 schedule();
1311 /* see if a signal did it */
1312 if (signal_pending(current)) {
1313 ret = -ERESTARTSYS;
1314 break;
1306 } 1315 }
1307 cprev = cnow; 1316 cprev = cnow;
1308 } 1317 }
1309 /* NOTREACHED */ 1318 finish_wait(&info->tport.delta_msr_wait, &wait);
1319 return ret;
1310 1320
1311 case TIOCSERGWILD: 1321 case TIOCSERGWILD:
1312 case TIOCSERSWILD: 1322 case TIOCSERSWILD: