diff options
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 40 |
1 files changed, 28 insertions, 12 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index a96f26a63fa..a37e6330db8 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1726,6 +1726,23 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count, return i; } +void tty_write_unlock(struct tty_struct *tty) +{ + mutex_unlock(&tty->atomic_write_lock); + wake_up_interruptible(&tty->write_wait); +} + +int tty_write_lock(struct tty_struct *tty, int ndelay) +{ + if (!mutex_trylock(&tty->atomic_write_lock)) { + if (ndelay) + return -EAGAIN; + if (mutex_lock_interruptible(&tty->atomic_write_lock)) + return -ERESTARTSYS; + } + return 0; +} + /* * Split writes up in sane blocksizes to avoid * denial-of-service type attacks @@ -1737,13 +1754,12 @@ static inline ssize_t do_tty_write( const char __user *buf, size_t count) { - ssize_t ret = 0, written = 0; + ssize_t ret, written = 0; unsigned int chunk; - /* FIXME: O_NDELAY ... */ - if (mutex_lock_interruptible(&tty->atomic_write_lock)) { - return -ERESTARTSYS; - } + ret = tty_write_lock(tty, file->f_flags & O_NDELAY); + if (ret < 0) + return ret; /* * We chunk up writes into a temporary buffer. This @@ -1776,8 +1792,8 @@ static inline ssize_t do_tty_write( buf = kmalloc(chunk, GFP_KERNEL); if (!buf) { - mutex_unlock(&tty->atomic_write_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } kfree(tty->write_buf); tty->write_cnt = chunk; @@ -1812,7 +1828,8 @@ static inline ssize_t do_tty_write( inode->i_mtime = current_fs_time(inode->i_sb); ret = written; } - mutex_unlock(&tty->atomic_write_lock); +out: + tty_write_unlock(tty); return ret; } @@ -3163,14 +3180,13 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) static int send_break(struct tty_struct *tty, unsigned int duration) { - if (mutex_lock_interruptible(&tty->atomic_write_lock)) + if (tty_write_lock(tty, 0) < 0) return -EINTR; tty->driver->break_ctl(tty, -1); - if (!signal_pending(current)) { + if (!signal_pending(current)) msleep_interruptible(duration); - } tty->driver->break_ctl(tty, 0); - mutex_unlock(&tty->atomic_write_lock); + tty_write_unlock(tty); if (signal_pending(current)) return -EINTR; return 0; |