diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-02-10 04:44:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:22 -0500 |
commit | c6256c68248cfccbeec07ced442ffe395fa393e8 (patch) | |
tree | 24acdd2d3875680de114e8d50d50835b2705315b /arch/um | |
parent | d5c9ffc6c6d15d4f655236e26942a21ad61fe3ad (diff) |
[PATCH] uml: fix previous console locking
Eliminate the open_mutex after complaints from Blaisorblade. It turns out
that the tty count provides the information needed to tell whether we are the
first opener or last closer.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/drivers/line.c | 48 | ||||
-rw-r--r-- | arch/um/include/line.h | 1 |
2 files changed, 8 insertions, 41 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 433e572fb196..0e1e9a20a4d6 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -425,42 +425,15 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) | |||
425 | * However, in this case, mconsole requests can come in "from the | 425 | * However, in this case, mconsole requests can come in "from the |
426 | * side", and race with opens and closes. | 426 | * side", and race with opens and closes. |
427 | * | 427 | * |
428 | * The problem comes from line_setup not wanting to sleep if | 428 | * mconsole config requests will want to be sure the device isn't in |
429 | * the device is open or being opened. This can happen because the | 429 | * use, and get_config, open, and close will want a stable |
430 | * first opener of a device is responsible for setting it up on the | 430 | * configuration. The checking and modification of the configuration |
431 | * host, and that can sleep. The open of a port device will sleep | 431 | * is done under a spinlock. Checking whether the device is in use is |
432 | * until someone telnets to it. | 432 | * line->tty->count > 1, also under the spinlock. |
433 | * | 433 | * |
434 | * The obvious solution of putting everything under a mutex fails | 434 | * tty->count serves to decide whether the device should be enabled or |
435 | * because then trying (and failing) to change the configuration of an | 435 | * disabled on the host. If it's equal to 1, then we are doing the |
436 | * open(ing) device will block until the open finishes. The right | 436 | * first open or last close. Otherwise, open and close just return. |
437 | * thing to happen is for it to fail immediately. | ||
438 | * | ||
439 | * We can put the opening (and closing) of the host device under a | ||
440 | * separate lock, but that has to be taken before the count lock is | ||
441 | * released. Otherwise, you open a window in which another open can | ||
442 | * come through and assume that the host side is opened and working. | ||
443 | * | ||
444 | * So, if the tty count is one, open will take the open mutex | ||
445 | * inside the count lock. Otherwise, it just returns. This will sleep | ||
446 | * if the last close is pending, and will block a setup or get_config, | ||
447 | * but that should not last long. | ||
448 | * | ||
449 | * So, what we end up with is that open and close take the count lock. | ||
450 | * If the first open or last close are happening, then the open mutex | ||
451 | * is taken inside the count lock and the host opening or closing is done. | ||
452 | * | ||
453 | * setup and get_config only take the count lock. setup modifies the | ||
454 | * device configuration only if the open count is zero. Arbitrarily | ||
455 | * long blocking of setup doesn't happen because something would have to be | ||
456 | * waiting for an open to happen. However, a second open with | ||
457 | * tty->count == 1 can't happen, and a close can't happen until the open | ||
458 | * had finished. | ||
459 | * | ||
460 | * We can't maintain our own count here because the tty layer doesn't | ||
461 | * match opens and closes. It will call close if an open failed, and | ||
462 | * a tty hangup will result in excess closes. So, we rely on | ||
463 | * tty->count instead. It is one on both the first open and last close. | ||
464 | */ | 437 | */ |
465 | 438 | ||
466 | int line_open(struct line *lines, struct tty_struct *tty) | 439 | int line_open(struct line *lines, struct tty_struct *tty) |
@@ -476,7 +449,6 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
476 | if(tty->count > 1) | 449 | if(tty->count > 1) |
477 | goto out_unlock; | 450 | goto out_unlock; |
478 | 451 | ||
479 | mutex_lock(&line->open_mutex); | ||
480 | spin_unlock(&line->count_lock); | 452 | spin_unlock(&line->count_lock); |
481 | 453 | ||
482 | tty->driver_data = line; | 454 | tty->driver_data = line; |
@@ -493,7 +465,6 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
493 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | 465 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
494 | &tty->winsize.ws_col); | 466 | &tty->winsize.ws_col); |
495 | 467 | ||
496 | mutex_unlock(&line->open_mutex); | ||
497 | return err; | 468 | return err; |
498 | 469 | ||
499 | out_unlock: | 470 | out_unlock: |
@@ -523,7 +494,6 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
523 | if(tty->count > 1) | 494 | if(tty->count > 1) |
524 | goto out_unlock; | 495 | goto out_unlock; |
525 | 496 | ||
526 | mutex_lock(&line->open_mutex); | ||
527 | spin_unlock(&line->count_lock); | 497 | spin_unlock(&line->count_lock); |
528 | 498 | ||
529 | line->tty = NULL; | 499 | line->tty = NULL; |
@@ -534,7 +504,6 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
534 | line->sigio = 0; | 504 | line->sigio = 0; |
535 | } | 505 | } |
536 | 506 | ||
537 | mutex_unlock(&line->open_mutex); | ||
538 | return; | 507 | return; |
539 | 508 | ||
540 | out_unlock: | 509 | out_unlock: |
@@ -755,7 +724,6 @@ void lines_init(struct line *lines, int nlines, struct chan_opts *opts) | |||
755 | for(i = 0; i < nlines; i++){ | 724 | for(i = 0; i < nlines; i++){ |
756 | line = &lines[i]; | 725 | line = &lines[i]; |
757 | INIT_LIST_HEAD(&line->chan_list); | 726 | INIT_LIST_HEAD(&line->chan_list); |
758 | mutex_init(&line->open_mutex); | ||
759 | 727 | ||
760 | if(line->init_str == NULL) | 728 | if(line->init_str == NULL) |
761 | continue; | 729 | continue; |
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 3477a858eaa9..1223f2c844b4 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h | |||
@@ -35,7 +35,6 @@ struct line { | |||
35 | spinlock_t count_lock; | 35 | spinlock_t count_lock; |
36 | int valid; | 36 | int valid; |
37 | 37 | ||
38 | struct mutex open_mutex; | ||
39 | char *init_str; | 38 | char *init_str; |
40 | int init_pri; | 39 | int init_pri; |
41 | struct list_head chan_list; | 40 | struct list_head chan_list; |