This is the second attempt to get the BKL out of the TTY code. I've updated the patches to be based on top of Alan's series and improved a number of things. This series still introduces a new Big TTY Mutex that is based on the earlier implementation of the Big Kernel Semaphore, but comes with a number of changes: - based on the mutex code instead of a semaphore, so we can use all the mutex debugging. - no autorelease on sleep, which is what most of the series is about. - limited to one subsystem only. - ability to annotate nested locking so we can eventually turn it into a non-recursive mutex, once all the recursive users stay around. The first eight patches convert all the code using the BKL in the TTY layer and related drivers to the new interface, and patch 9/13 then adds the real mutex implementation as an experimental configuration option. When that option is disabled, the behaviour should be basically unchanged regarding serialization against other subsystems using the BKL. The final four patches are new and do some real cleanup, intended to improve the TTY locking towards moving the BTM out. These are not required for the big picture of the BKL removal, nothing else depends on this. I'd still like to hear from Alan if he thinks this part is useful for his work on the problem or if we should just leave it out. Arnd Bergmann (13): tty: replace BKL with a new tty_lock tty: make atomic_write_lock release tty_lock tty: make tty_port->mutex nest under tty_lock tty: make termios mutex nest under tty_lock tty: make ldisc_mutex nest under tty_lock tty: never hold BTM while getting tty_mutex tty: give up BTM in acquire_console_sem tty: release tty lock when blocking tty: implement BTM as mutex instead of BKL tty: untangle locking of wait_until_sent tty: remove tty_lock_nested tty: remove release_tty_lock/reacquire_tty_lock tty: turn ldisc_mutex into a regular mutex drivers/char/Makefile | 1 + ...
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/tty_io.c | 2 +-
drivers/char/tty_ldisc.c | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index b1a40a1..82c723a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1284,7 +1284,7 @@ static int tty_reopen(struct tty_struct *tty)
tty->count++;
tty->driver = driver; /* N.B. why do this every time?? */
- mutex_lock(&tty->ldisc_mutex);
+ mutex_lock_tty_on(&tty->ldisc_mutex);
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
mutex_unlock(&tty->ldisc_mutex);
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index f0efca2..630e1ef 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -582,7 +582,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_wait_until_sent(tty, 0);
- mutex_lock(&tty->ldisc_mutex);
+ mutex_lock_tty_off(&tty->ldisc_mutex);
/*
* We could be midstream of another ldisc change which has
@@ -593,7 +593,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
mutex_unlock(&tty->ldisc_mutex);
wait_event(tty_ldisc_wait,
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
- mutex_lock(&tty->ldisc_mutex);
+ mutex_lock_tty_off(&tty->ldisc_mutex);
}
tty_lock();
@@ -634,7 +634,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
flush_scheduled_work();
- mutex_lock(&tty->ldisc_mutex);
+ mutex_lock_tty_off(&tty->ldisc_mutex);
tty_lock();
if (test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
@@ -781,7 +781,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*
* Avoid racing set_ldisc or tty_ldisc_release
*/
- mutex_lock(&tty->ldisc_mutex);
+ mutex_lock_tty_on(&tty->ldisc_mutex);
tty_ldisc_halt(tty);
/* At this point we have a closed ldisc and we want to
reopen it. We could defer this to the next open but
@@ -856,7 +856,7 @@ void ...tty_port->mutex has a lock order problem with
tty_lock. By using mutex_lock_tty to drop tty_lock
while waiting for tty_port->mutex we can work
around this.
Make sure that we document for each mutex_lock(port->mutex)
whether we hold the BTM or not, in the hope that this
helps us eliminate the BTM eventually.
All users of tty_port_hangup call that with the BTM held,
except for stl_cleanup_panels. Take the BTM explicitly
there to make the locking more consistent.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/cyclades.c | 2 +-
drivers/char/isicom.c | 4 ++--
drivers/char/istallion.c | 4 ++--
drivers/char/moxa.c | 6 +++---
drivers/char/mxser.c | 10 +++++-----
drivers/char/riscom8.c | 4 ++--
drivers/char/rocket.c | 6 +++---
drivers/char/specialix.c | 4 ++--
drivers/char/stallion.c | 10 ++++++----
drivers/char/synclink.c | 8 ++++----
drivers/char/synclink_gt.c | 8 ++++----
drivers/char/synclinkmp.c | 10 +++++-----
drivers/char/tty_port.c | 4 ++--
drivers/mmc/card/sdio_uart.c | 2 +-
drivers/serial/pmac_zilog.c | 4 ++--
drivers/serial/serial_core.c | 32 ++++++++++++++++----------------
drivers/usb/serial/opticon.c | 2 +-
17 files changed, 61 insertions(+), 59 deletions(-)
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 51acfe3..5b3b419 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -2359,7 +2359,7 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- mutex_lock(&info->port.mutex);
+ mutex_lock_tty_off(&info->port.mutex);
if (!capable(CAP_SYS_ADMIN)) {
if (new_serial.close_delay != info->port.close_delay ||
new_serial.baud_base != info->baud ||
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 078d69f..2c46fd6 100644
--- ...All users are nonrecursive now, and we don't call release_tty_lock()
in places where it's not held to start with, so it is safe to
replace it with tty_lock().
Same for reacquire_tty_lock()/tty_unlock().
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/tty_ldisc.c | 8 +++---
drivers/char/tty_mutex.c | 35 ------------------------
include/linux/tty.h | 65 ++++++++++++---------------------------------
kernel/printk.c | 9 ++++--
4 files changed, 28 insertions(+), 89 deletions(-)
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index c71a94a..0c0e935 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -537,9 +537,9 @@ static int tty_ldisc_halt(struct tty_struct *tty)
int ret;
clear_bit(TTY_LDISC, &tty->flags);
if (tty_locked()) {
- __release_tty_lock();
+ tty_unlock();
ret = cancel_delayed_work_sync(&tty->buf.work);
- __reacquire_tty_lock();
+ tty_lock();
} else {
ret = cancel_delayed_work_sync(&tty->buf.work);
@@ -870,9 +870,9 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
*/
tty_ldisc_halt(tty);
- release_tty_lock(current);
+ tty_unlock();
flush_scheduled_work();
- reacquire_tty_lock(current);
+ tty_lock();
mutex_lock_tty_on(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
diff --git a/drivers/char/tty_mutex.c b/drivers/char/tty_mutex.c
index 6bd47e1..5fd3332 100644
--- a/drivers/char/tty_mutex.c
+++ b/drivers/char/tty_mutex.c
@@ -24,41 +24,6 @@
static DEFINE_MUTEX(big_tty_mutex);
/*
- * Re-acquire the kernel semaphore.
- *
- * This function is called with preemption off.
- *
- * We are executing in schedule() so the code must be extremely careful
- * about recursion, both due to the down() and due to the enabling of
- * preemption. schedule() will re-check the preemption flag after
- * reacquiring the semaphore.
- */
-int __lockfunc __reacquire_tty_lock(void)
-{
- struct task_struct *task = ...This changes all remaining users of tty_lock_nested to be non-recursive, which lets us kill this function. As a consequence, we won't need to keep the lock count any more, which allows more simplifications later. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- drivers/char/pty.c | 2 +- drivers/char/selection.c | 4 ++-- drivers/char/tty_io.c | 41 ++++++++++++++++++++--------------------- drivers/char/tty_ldisc.c | 3 +-- drivers/char/tty_mutex.c | 15 --------------- drivers/serial/crisv10.c | 7 ++++--- include/linux/tty.h | 17 +---------------- 7 files changed, 29 insertions(+), 60 deletions(-) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 889de89..76de961 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -62,7 +62,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (tty->driver == ptm_driver) devpts_pty_kill(tty->link); #endif - tty_vhangup(tty->link); + tty_vhangup_locked(tty->link); } } diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 85211a3..8e314bb 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -313,7 +313,8 @@ int paste_selection(struct tty_struct *tty) struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); - tty_lock_nested(); /* always called with BTM from vt_ioctl */ + /* always called with BTM from vt_ioctl */ + WARN_ON(!tty_locked()); acquire_console_sem(); poke_blanked_console(); @@ -338,6 +339,5 @@ int paste_selection(struct tty_struct *tty) __set_current_state(TASK_RUNNING); tty_ldisc_deref(ld); - tty_unlock(); return 0; } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e1b2fca..4e16b34 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -492,10 +492,8 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * tasklist_lock to walk task list for hangup event * ->siglock to protect ->signal/->sighand */ -static void do_tty_hangup(struct work_struct ...
Most of these are always called without the BTM held.
Annotate them so we know in the future which places
to look at. If we can change the code to never
get termios_mutex while holding the BTM, this
will solve all lock-order problems between the two.
tty_set_termios_ldisc and tty_reset_termios are currently
the only functions that always get termios_mutex while
already holding the BTM.
tty_throttle and tty_unthrottle are called from
receive_buf which in turn is called from a lot
of places. It needs more investigation to prove
that we never hold the BTM while calling these
two.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/pty.c | 2 +-
drivers/char/tty_io.c | 4 ++--
drivers/char/tty_ioctl.c | 37 ++++++++++++++++++++-----------------
drivers/char/tty_ldisc.c | 4 ++--
drivers/net/irda/irtty-sir.c | 5 +++--
drivers/staging/strip/strip.c | 2 +-
6 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 384e79f..dbb144b 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -232,7 +232,7 @@ int pty_resize(struct tty_struct *tty, struct winsize *ws)
struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */
- mutex_lock(&tty->termios_mutex);
+ mutex_lock_tty_off(&tty->termios_mutex);
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 8331dd3..b1a40a1 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2035,7 +2035,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{
int err;
- mutex_lock(&tty->termios_mutex);
+ mutex_lock_tty_off(&tty->termios_mutex);
err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
mutex_unlock(&tty->termios_mutex);
@@ -2058,7 +2058,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
unsigned long flags;
/* Lock the tty ...Update: I have verified that this one is not needed at all, because we never take the BTM/BKL while holding termios_mutex. This is very helpful and will significantly simplify things towards the end. With this patch removed, my patch 13 (ldisc_mutex cleanup) can potentially be applied again, I still need to check some corner cases with line disciplines calling tty_driver_flush_buffer and with v253_open calling tty->ops-write under BTM+ldisc_mutex. If no tty driver ever takes or releases the BTM/BKL in their flush_buffer or write functions, things should be fine. Arnd --
atomic_write_lock never nests below BTM as far
as I can tell, so this can eventually get
reverted again unless it triggers bugs.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/tty_io.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 3bf2c75..8331dd3 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -912,10 +912,15 @@ void tty_write_unlock(struct tty_struct *tty)
int tty_write_lock(struct tty_struct *tty, int ndelay)
{
+ /*
+ * code inspection has shown that this is never called
+ * with the BTM held. Make sure this stays that way.
+ */
+ WARN_ON_ONCE(tty_locked());
if (!mutex_trylock(&tty->atomic_write_lock)) {
if (ndelay)
return -EAGAIN;
- if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ if (mutex_lock_interruptible_tty(&tty->atomic_write_lock))
return -ERESTARTSYS;
}
return 0;
@@ -1024,7 +1029,7 @@ out:
void tty_write_message(struct tty_struct *tty, char *msg)
{
if (tty) {
- mutex_lock(&tty->atomic_write_lock);
+ mutex_lock_tty_off(&tty->atomic_write_lock);
tty_lock();
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
tty_unlock();
--
1.7.0.4
--
On Wed, 5 May 2010 00:33:41 +0200 That appears correct to me as a working assumpion as well --
tty_mutex is never taken with the BTM held, except for
two corner cases that are worked around here.
We give up the BTM before calling tty_release() in the
error path of tty_open().
Similarly, we reorder the locking in ptmx_open()
to get tty_mutex before the BTM.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/char/pty.c | 22 ++++++++--------------
drivers/char/tty_io.c | 13 +++++++------
2 files changed, 15 insertions(+), 20 deletions(-)
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index dbb144b..889de89 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -626,7 +626,7 @@ static const struct tty_operations pty_unix98_ops = {
* allocated_ptys_lock handles the list of free pty numbers
*/
-static int __ptmx_open(struct inode *inode, struct file *filp)
+static int ptmx_open(struct inode *inode, struct file *filp)
{
struct tty_struct *tty;
int retval;
@@ -635,11 +635,14 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
/* find a device that is not in use. */
+ tty_lock();
index = devpts_new_index(inode);
+ tty_unlock();
if (index < 0)
return index;
mutex_lock(&tty_mutex);
+ tty_lock();
tty = tty_init_dev(ptm_driver, index, 1);
mutex_unlock(&tty_mutex);
@@ -657,24 +660,15 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
goto out1;
retval = ptm_driver->ops->open(tty, filp);
- if (!retval)
- return 0;
+ if (retval)
+ tty_release(inode, filp);
out1:
- tty_release(inode, filp);
+ tty_unlock();
return retval;
out:
devpts_kill_index(inode, index);
- return retval;
-}
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
- int ret;
-
- tty_lock();
- ret = __ptmx_open(inode, filp);
tty_unlock();
- return ret;
+ return retval;
}
static struct file_operations ptmx_fops;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 82c723a..e1b2fca 100644
--- ...Some wait_until_sent versions require the big tty mutex, others don't and some callers of wait_until_sent already hold it while other don't. That leads to recursive use of the BTM in these functions, which we're trying to get rid of. This patch changes both the implementations and the users of wait_until_sent so that the device driver implementations are always called with the lock held so they don't need to get it themselves. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- drivers/char/amiserial.c | 6 +++--- drivers/char/generic_serial.c | 2 +- drivers/char/hvc_console.c | 2 +- drivers/char/hvcs.c | 2 +- drivers/char/ip2/ip2main.c | 20 +++++++++++++++++--- drivers/char/serial167.c | 6 +++--- drivers/char/specialix.c | 2 +- drivers/char/tty_ioctl.c | 36 ++++++++++++++++++++++++++++++++++-- drivers/char/tty_port.c | 2 +- drivers/isdn/i4l/isdn_tty.c | 2 +- drivers/serial/68328serial.c | 2 +- drivers/serial/68360serial.c | 5 ++--- drivers/serial/crisv10.c | 12 +++++++----- drivers/serial/serial_core.c | 5 +---- include/linux/tty.h | 1 + net/irda/ircomm/ircomm_tty.c | 2 +- 16 files changed, 76 insertions(+), 31 deletions(-) diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 5bd382e..bfcf520 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1479,7 +1479,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ tty->closing = 1; if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + tty_wait_until_sent_locked(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1537,7 +1537,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) orig_jiffies = jiffies; - tty_lock_nested(); /* tty_wait_until_sent is called ...
I don't think we care - the driver is a mess, its probably not been used Semi-defunct at best This makes me think that now might be a good time to consign the broken crap to the bitbucket unless someone stands up with hardware and who wants to maintain it. --
Ok, that simplifies things, at least we can call
tty->ops->wait_until_sent(tty, timeout) while holding
the BTM then, even with the next patch that makes it
These, and most of the others in this patch call tty_wait_until_sent()
from their close() function. That contains the lines
if (wait_event_interruptible_timeout(tty->write_wait,
!tty_chars_in_buffer(tty), timeout) >= 0) {
Part of what my patch does is to give up the BTM when already
holding it, to mimic the BKL behavior.
If you can confirm that this wait_event never blocks indefinitely
or has to wait for the BTM from another function, that could just
be removed. Otherwise, it probably needs to become something ugly
like
if (tty_chars_in_buffer(tty)) {
if (tty_locked()) {
tty_unlock();
wait = wait_event_interruptible_timeout(tty->write_wait,
!tty_chars_in_buffer(tty), timeout) >= 0);
tty_lock();
} else {
wait = wait_event_interruptible_timeout(tty->write_wait,
!tty_chars_in_buffer(tty), timeout) >= 0);
}
if (wait && tty->ops->wait_until_sent)
tty->ops->wait_until_sent(tty, timeout);
}
I already had to introduce a few of these constructs to make the BTM
non-recursive, but I'd prefer to keep the number as low as possible
Fine with me.
While I technically own a 16-port specialix card somewhere in my
parents' basement, I'm not exactly interested in maintaining the
driver.
Arnd
--
I will be glad to do this, moving these drivers to the staging tree so that they can be removed in 6-8 months, much like some wireless drivers are about to have happen to them. So, which ones should I move? How about to start with the ones you listed above: drivers/char/amiserial.c drivers/char/generic_serial.c drivers/char/ip2/ip2main.c drivers/char/serial167.c drivers/char/specialix.c drivers/serial/68328serial.c drivers/serial/68360serial.c drivers/serial/crisv10.c Any others you want to see move out of the tree? thanks, greg k-h --
Generic serial covers several old drivers that are defunct drivers/char/rio/ drivers/char/vme_scc drivers/char/ser_a2232 drivers/char/sx/ Leave specialix.c for now - that one is probably salvagable fairly easily and I think has a couple of users. --
ircomm_tty is fairly common hardware, afaict, it is just not used often. Main use case would be backup of your phone numbers, afaict. It would be good to keep it for once-in-a-blue-moon use... Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html --
On Mon, 24 May 2010 21:00:38 +0200 Fine - send patches. Last time I looked at it I couldn't believe it still worked and the last box I had with Irda capability exploded (literally) some years ago. I don't I've seen an Irda capable phone for a while either. --
As a preparation for replacing the big kernel lock in the TTY layer, wrap all the callers in new macros tty_lock, tty_lock_nested and tty_unlock. Every user of tty_lock_nested should come with a comment explaining why we could get the lock recursively. This will help turning the BTM into a nonrecursive lock. We also need to deal with lock order problems that are currently solved by the BKL autorelease semantics. For this, we get new macros that can be used to replace sleeping calls like mutex_lock() or wait_event(). We start using these in the next patches. Signed-off-by: Arnd Bergmann <arnd@arndb.de> --- drivers/char/amiserial.c | 16 ++-- drivers/char/briq_panel.c | 6 +- drivers/char/n_hdlc.c | 16 ++-- drivers/char/n_r3964.c | 8 +- drivers/char/pty.c | 4 +- drivers/char/selection.c | 4 +- drivers/char/serial167.c | 4 +- drivers/char/sx.c | 12 ++-- drivers/char/tty_io.c | 113 +++++++++++++++------------ drivers/char/tty_ldisc.c | 24 +++--- drivers/char/vc_screen.c | 4 +- drivers/char/vt_ioctl.c | 10 +- drivers/isdn/i4l/isdn_common.c | 20 +++--- drivers/isdn/i4l/isdn_tty.c | 8 +- drivers/serial/68360serial.c | 4 +- drivers/serial/crisv10.c | 4 +- drivers/serial/serial_core.c | 10 +- drivers/usb/serial/usb-serial.c | 18 ++-- drivers/video/console/vgacon.c | 4 +- include/linux/tty.h | 169 +++++++++++++++++++++++++++++++++++++++ 20 files changed, 321 insertions(+), 137 deletions(-) diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 56b2767..5bd382e 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1071,7 +1071,7 @@ static int get_serial_info(struct async_struct * info, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - lock_kernel(); + tty_lock(); tmp.type = state->type; tmp.line = ...
On Wed, 5 May 2010 00:33:39 +0200 I've updated the patches I first sent out with the fixes for the problems you found and send out a new set. --
Ok, I've rebased my patches on top of those now and pushed to git.kernel.org:/pub/scm/linux/kernel/git/arnd/playground.git#bkl/tty, minus my patch 13/13, which I already mentioned was broken. Arnd --
