diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2008-04-30 03:53:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:40 -0400 |
commit | 04f378b198da233ca0aca341b113dc6579d46123 (patch) | |
tree | 696e7bd401125cee71ecaa2047c4273f38732554 /drivers/char/n_tty.c | |
parent | e52384426064bca0669a954736206adca7595d48 (diff) |
tty: BKL pushdown
- Push the BKL down into the line disciplines
- Switch the tty layer to unlocked_ioctl
- Introduce a new ctrl_lock spin lock for the control bits
- Eliminate much of the lock_kernel use in n_tty
- Prepare to (but don't yet) call the drivers with the lock dropped
on the paths that historically held the lock
BKL now primarily protects open/close/ldisc change in the tty layer
[jirislaby@gmail.com: a couple of fixes]
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r-- | drivers/char/n_tty.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 0c09409fa45d..001d9d875387 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -183,22 +183,24 @@ static void reset_buffer_flags(struct tty_struct *tty) | |||
183 | * at hangup) or when the N_TTY line discipline internally has to | 183 | * at hangup) or when the N_TTY line discipline internally has to |
184 | * clean the pending queue (for example some signals). | 184 | * clean the pending queue (for example some signals). |
185 | * | 185 | * |
186 | * FIXME: tty->ctrl_status is not spinlocked and relies on | 186 | * Locking: ctrl_lock |
187 | * lock_kernel() still. | ||
188 | */ | 187 | */ |
189 | 188 | ||
190 | static void n_tty_flush_buffer(struct tty_struct *tty) | 189 | static void n_tty_flush_buffer(struct tty_struct *tty) |
191 | { | 190 | { |
191 | unsigned long flags; | ||
192 | /* clear everything and unthrottle the driver */ | 192 | /* clear everything and unthrottle the driver */ |
193 | reset_buffer_flags(tty); | 193 | reset_buffer_flags(tty); |
194 | 194 | ||
195 | if (!tty->link) | 195 | if (!tty->link) |
196 | return; | 196 | return; |
197 | 197 | ||
198 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
198 | if (tty->link->packet) { | 199 | if (tty->link->packet) { |
199 | tty->ctrl_status |= TIOCPKT_FLUSHREAD; | 200 | tty->ctrl_status |= TIOCPKT_FLUSHREAD; |
200 | wake_up_interruptible(&tty->link->read_wait); | 201 | wake_up_interruptible(&tty->link->read_wait); |
201 | } | 202 | } |
203 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
202 | } | 204 | } |
203 | 205 | ||
204 | /** | 206 | /** |
@@ -264,7 +266,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) | |||
264 | * relevant in the world today. If you ever need them, add them here. | 266 | * relevant in the world today. If you ever need them, add them here. |
265 | * | 267 | * |
266 | * Called from both the receive and transmit sides and can be called | 268 | * Called from both the receive and transmit sides and can be called |
267 | * re-entrantly. Relies on lock_kernel() still. | 269 | * re-entrantly. Relies on lock_kernel() for tty->column state. |
268 | */ | 270 | */ |
269 | 271 | ||
270 | static int opost(unsigned char c, struct tty_struct *tty) | 272 | static int opost(unsigned char c, struct tty_struct *tty) |
@@ -275,6 +277,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
275 | if (!space) | 277 | if (!space) |
276 | return -1; | 278 | return -1; |
277 | 279 | ||
280 | lock_kernel(); | ||
278 | if (O_OPOST(tty)) { | 281 | if (O_OPOST(tty)) { |
279 | switch (c) { | 282 | switch (c) { |
280 | case '\n': | 283 | case '\n': |
@@ -323,6 +326,7 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
323 | } | 326 | } |
324 | } | 327 | } |
325 | tty->driver->put_char(tty, c); | 328 | tty->driver->put_char(tty, c); |
329 | unlock_kernel(); | ||
326 | return 0; | 330 | return 0; |
327 | } | 331 | } |
328 | 332 | ||
@@ -337,7 +341,8 @@ static int opost(unsigned char c, struct tty_struct *tty) | |||
337 | * the simple cases normally found and helps to generate blocks of | 341 | * the simple cases normally found and helps to generate blocks of |
338 | * symbols for the console driver and thus improve performance. | 342 | * symbols for the console driver and thus improve performance. |
339 | * | 343 | * |
340 | * Called from write_chan under the tty layer write lock. | 344 | * Called from write_chan under the tty layer write lock. Relies |
345 | * on lock_kernel for the tty->column state. | ||
341 | */ | 346 | */ |
342 | 347 | ||
343 | static ssize_t opost_block(struct tty_struct *tty, | 348 | static ssize_t opost_block(struct tty_struct *tty, |
@@ -353,6 +358,7 @@ static ssize_t opost_block(struct tty_struct *tty, | |||
353 | if (nr > space) | 358 | if (nr > space) |
354 | nr = space; | 359 | nr = space; |
355 | 360 | ||
361 | lock_kernel(); | ||
356 | for (i = 0, cp = buf; i < nr; i++, cp++) { | 362 | for (i = 0, cp = buf; i < nr; i++, cp++) { |
357 | switch (*cp) { | 363 | switch (*cp) { |
358 | case '\n': | 364 | case '\n': |
@@ -387,6 +393,7 @@ break_out: | |||
387 | if (tty->driver->flush_chars) | 393 | if (tty->driver->flush_chars) |
388 | tty->driver->flush_chars(tty); | 394 | tty->driver->flush_chars(tty); |
389 | i = tty->driver->write(tty, buf, i); | 395 | i = tty->driver->write(tty, buf, i); |
396 | unlock_kernel(); | ||
390 | return i; | 397 | return i; |
391 | } | 398 | } |
392 | 399 | ||
@@ -1194,6 +1201,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, | |||
1194 | * Perform job control management checks on this file/tty descriptor | 1201 | * Perform job control management checks on this file/tty descriptor |
1195 | * and if appropriate send any needed signals and return a negative | 1202 | * and if appropriate send any needed signals and return a negative |
1196 | * error code if action should be taken. | 1203 | * error code if action should be taken. |
1204 | * | ||
1205 | * FIXME: | ||
1206 | * Locking: None - redirected write test is safe, testing | ||
1207 | * current->signal should possibly lock current->sighand | ||
1208 | * pgrp locking ? | ||
1197 | */ | 1209 | */ |
1198 | 1210 | ||
1199 | static int job_control(struct tty_struct *tty, struct file *file) | 1211 | static int job_control(struct tty_struct *tty, struct file *file) |
@@ -1246,6 +1258,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, | |||
1246 | ssize_t size; | 1258 | ssize_t size; |
1247 | long timeout; | 1259 | long timeout; |
1248 | unsigned long flags; | 1260 | unsigned long flags; |
1261 | int packet; | ||
1249 | 1262 | ||
1250 | do_it_again: | 1263 | do_it_again: |
1251 | 1264 | ||
@@ -1289,16 +1302,19 @@ do_it_again: | |||
1289 | if (mutex_lock_interruptible(&tty->atomic_read_lock)) | 1302 | if (mutex_lock_interruptible(&tty->atomic_read_lock)) |
1290 | return -ERESTARTSYS; | 1303 | return -ERESTARTSYS; |
1291 | } | 1304 | } |
1305 | packet = tty->packet; | ||
1292 | 1306 | ||
1293 | add_wait_queue(&tty->read_wait, &wait); | 1307 | add_wait_queue(&tty->read_wait, &wait); |
1294 | while (nr) { | 1308 | while (nr) { |
1295 | /* First test for status change. */ | 1309 | /* First test for status change. */ |
1296 | if (tty->packet && tty->link->ctrl_status) { | 1310 | if (packet && tty->link->ctrl_status) { |
1297 | unsigned char cs; | 1311 | unsigned char cs; |
1298 | if (b != buf) | 1312 | if (b != buf) |
1299 | break; | 1313 | break; |
1314 | spin_lock_irqsave(&tty->link->ctrl_lock, flags); | ||
1300 | cs = tty->link->ctrl_status; | 1315 | cs = tty->link->ctrl_status; |
1301 | tty->link->ctrl_status = 0; | 1316 | tty->link->ctrl_status = 0; |
1317 | spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); | ||
1302 | if (tty_put_user(tty, cs, b++)) { | 1318 | if (tty_put_user(tty, cs, b++)) { |
1303 | retval = -EFAULT; | 1319 | retval = -EFAULT; |
1304 | b--; | 1320 | b--; |
@@ -1333,6 +1349,7 @@ do_it_again: | |||
1333 | retval = -ERESTARTSYS; | 1349 | retval = -ERESTARTSYS; |
1334 | break; | 1350 | break; |
1335 | } | 1351 | } |
1352 | /* FIXME: does n_tty_set_room need locking ? */ | ||
1336 | n_tty_set_room(tty); | 1353 | n_tty_set_room(tty); |
1337 | timeout = schedule_timeout(timeout); | 1354 | timeout = schedule_timeout(timeout); |
1338 | continue; | 1355 | continue; |
@@ -1340,7 +1357,7 @@ do_it_again: | |||
1340 | __set_current_state(TASK_RUNNING); | 1357 | __set_current_state(TASK_RUNNING); |
1341 | 1358 | ||
1342 | /* Deal with packet mode. */ | 1359 | /* Deal with packet mode. */ |
1343 | if (tty->packet && b == buf) { | 1360 | if (packet && b == buf) { |
1344 | if (tty_put_user(tty, TIOCPKT_DATA, b++)) { | 1361 | if (tty_put_user(tty, TIOCPKT_DATA, b++)) { |
1345 | retval = -EFAULT; | 1362 | retval = -EFAULT; |
1346 | b--; | 1363 | b--; |
@@ -1388,6 +1405,8 @@ do_it_again: | |||
1388 | break; | 1405 | break; |
1389 | } else { | 1406 | } else { |
1390 | int uncopied; | 1407 | int uncopied; |
1408 | /* The copy function takes the read lock and handles | ||
1409 | locking internally for this case */ | ||
1391 | uncopied = copy_from_read_buf(tty, &b, &nr); | 1410 | uncopied = copy_from_read_buf(tty, &b, &nr); |
1392 | uncopied += copy_from_read_buf(tty, &b, &nr); | 1411 | uncopied += copy_from_read_buf(tty, &b, &nr); |
1393 | if (uncopied) { | 1412 | if (uncopied) { |
@@ -1429,7 +1448,6 @@ do_it_again: | |||
1429 | goto do_it_again; | 1448 | goto do_it_again; |
1430 | 1449 | ||
1431 | n_tty_set_room(tty); | 1450 | n_tty_set_room(tty); |
1432 | |||
1433 | return retval; | 1451 | return retval; |
1434 | } | 1452 | } |
1435 | 1453 | ||