diff options
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 1436 |
1 files changed, 764 insertions, 672 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 5a6f36b391d9..de06c3c2ff70 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -33,7 +33,7 @@ * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. - * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 + * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. * -- ctm@ardi.com, 9Sep95 @@ -99,8 +99,8 @@ #include <linux/serial.h> #include <linux/ratelimit.h> #include <linux/compat.h> - #include <linux/uaccess.h> +#include <linux/termios_internal.h> #include <linux/kbd_kern.h> #include <linux/vt_kern.h> @@ -108,6 +108,7 @@ #include <linux/kmod.h> #include <linux/nsproxy.h> +#include "tty.h" #undef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP @@ -130,25 +131,22 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ .c_ospeed = 38400, /* .c_line = N_TTY, */ }; - EXPORT_SYMBOL(tty_std_termios); /* This list gets poked at by procfs and various bits of boot up code. This - could do with some rationalisation such as pulling the tty proc function - into this file */ + * could do with some rationalisation such as pulling the tty proc function + * into this file. + */ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ /* Mutex to protect creating and releasing a tty */ DEFINE_MUTEX(tty_mutex); -static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); -static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); -ssize_t redirected_tty_write(struct file *, const char __user *, - size_t, loff_t *); +static ssize_t tty_read(struct kiocb *, struct iov_iter *); +static ssize_t tty_write(struct kiocb *, struct iov_iter *); static __poll_t tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); -long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #ifdef CONFIG_COMPAT static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -160,20 +158,18 @@ static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); /** - * free_tty_struct - free a disused tty - * @tty: tty struct to free + * free_tty_struct - free a disused tty + * @tty: tty struct to free * - * Free the write buffers, tty queue and tty memory itself. + * Free the write buffers, tty queue and tty memory itself. * - * Locking: none. Must be called after tty is definitely unused + * Locking: none. Must be called after tty is definitely unused */ - static void free_tty_struct(struct tty_struct *tty) { tty_ldisc_deinit(tty); put_device(tty->dev); - kfree(tty->write_buf); - tty->magic = 0xDEADDEAD; + kvfree(tty->write_buf); kfree(tty); } @@ -210,6 +206,7 @@ void tty_add_file(struct tty_struct *tty, struct file *file) /** * tty_free_file - free file->private_data + * @file: to free private_data of * * This shall be used only for fail path handling when tty_add_file was not * called yet. @@ -235,22 +232,20 @@ static void tty_del_file(struct file *file) } /** - * tty_name - return tty naming - * @tty: tty structure + * tty_name - return tty naming + * @tty: tty structure * - * Convert a tty structure into a name. The name reflects the kernel - * naming policy and if udev is in use may not reflect user space + * Convert a tty structure into a name. The name reflects the kernel naming + * policy and if udev is in use may not reflect user space * - * Locking: none + * Locking: none */ - const char *tty_name(const struct tty_struct *tty) { if (!tty) /* Hmm. NULL pointer. That's fun. */ return "NULL tty"; return tty->name; } - EXPORT_SYMBOL(tty_name); const char *tty_driver_name(const struct tty_struct *tty) @@ -269,11 +264,6 @@ static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, imajor(inode), iminor(inode), routine); return 1; } - if (tty->magic != TTY_MAGIC) { - pr_warn("(%d:%d): %s: bad magic number\n", - imajor(inode), iminor(inode), routine); - return 1; - } #endif return 0; } @@ -306,22 +296,22 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) } /** - * get_tty_driver - find device of a tty - * @dev_t: device identifier - * @index: returns the index of the tty + * get_tty_driver - find device of a tty + * @device: device identifier + * @index: returns the index of the tty * - * This routine returns a tty driver structure, given a device number - * and also passes back the index number. + * This routine returns a tty driver structure, given a device number and also + * passes back the index number. * - * Locking: caller must hold tty_mutex + * Locking: caller must hold tty_mutex */ - static struct tty_driver *get_tty_driver(dev_t device, int *index) { struct tty_driver *p; list_for_each_entry(p, &tty_drivers, tty_drivers) { dev_t base = MKDEV(p->major, p->minor_start); + if (device < base || device >= base + p->num) continue; *index = device - base; @@ -331,17 +321,17 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) } /** - * tty_dev_name_to_number - return dev_t for device name - * @name: user space name of device under /dev - * @number: pointer to dev_t that this function will populate + * tty_dev_name_to_number - return dev_t for device name + * @name: user space name of device under /dev + * @number: pointer to dev_t that this function will populate * - * This function converts device names like ttyS0 or ttyUSB1 into dev_t - * like (4, 64) or (188, 1). If no corresponding driver is registered then - * the function returns -ENODEV. + * This function converts device names like ttyS0 or ttyUSB1 into dev_t like + * (4, 64) or (188, 1). If no corresponding driver is registered then the + * function returns -%ENODEV. * - * Locking: this acquires tty_mutex to protect the tty_drivers list from - * being modified while we are traversing it, and makes sure to - * release it before exiting. + * Locking: this acquires tty_mutex to protect the tty_drivers list from + * being modified while we are traversing it, and makes sure to + * release it before exiting. */ int tty_dev_name_to_number(const char *name, dev_t *number) { @@ -383,13 +373,12 @@ EXPORT_SYMBOL_GPL(tty_dev_name_to_number); #ifdef CONFIG_CONSOLE_POLL /** - * tty_find_polling_driver - find device of a polled tty - * @name: name string to match - * @line: pointer to resulting tty line nr + * tty_find_polling_driver - find device of a polled tty + * @name: name string to match + * @line: pointer to resulting tty line nr * - * This routine returns a tty driver structure, given a name - * and the condition that the tty driver is capable of polled - * operation. + * This routine returns a tty driver structure, given a name and the condition + * that the tty driver is capable of polled operation. */ struct tty_driver *tty_find_polling_driver(char *name, int *line) { @@ -432,14 +421,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) EXPORT_SYMBOL_GPL(tty_find_polling_driver); #endif -static ssize_t hung_up_tty_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t hung_up_tty_read(struct kiocb *iocb, struct iov_iter *to) { return 0; } -static ssize_t hung_up_tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t hung_up_tty_write(struct kiocb *iocb, struct iov_iter *from) { return -EIO; } @@ -477,8 +464,10 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file) static const struct file_operations tty_fops = { .llseek = no_llseek, - .read = tty_read, - .write = tty_write, + .read_iter = tty_read, + .write_iter = tty_write, + .splice_read = generic_file_splice_read, + .splice_write = iter_file_splice_write, .poll = tty_poll, .unlocked_ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, @@ -490,8 +479,10 @@ static const struct file_operations tty_fops = { static const struct file_operations console_fops = { .llseek = no_llseek, - .read = tty_read, - .write = redirected_tty_write, + .read_iter = tty_read, + .write_iter = redirected_tty_write, + .splice_read = generic_file_splice_read, + .splice_write = iter_file_splice_write, .poll = tty_poll, .unlocked_ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, @@ -502,8 +493,8 @@ static const struct file_operations console_fops = { static const struct file_operations hung_up_tty_fops = { .llseek = no_llseek, - .read = hung_up_tty_read, - .write = hung_up_tty_write, + .read_iter = hung_up_tty_read, + .write_iter = hung_up_tty_write, .poll = hung_up_tty_poll, .unlocked_ioctl = hung_up_tty_ioctl, .compat_ioctl = hung_up_tty_compat_ioctl, @@ -514,17 +505,14 @@ static const struct file_operations hung_up_tty_fops = { static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; -extern void tty_sysctl_init(void); - /** - * tty_wakeup - request more data - * @tty: terminal + * tty_wakeup - request more data + * @tty: terminal * - * Internal and external helper for wakeups of tty. This function - * informs the line discipline if present that the driver is ready - * to receive more output data. + * Internal and external helper for wakeups of tty. This function informs the + * line discipline if present that the driver is ready to receive more output + * data. */ - void tty_wakeup(struct tty_struct *tty) { struct tty_ldisc *ld; @@ -539,35 +527,58 @@ void tty_wakeup(struct tty_struct *tty) } wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); } - EXPORT_SYMBOL_GPL(tty_wakeup); /** - * __tty_hangup - actual handler for hangup events - * @work: tty device + * tty_release_redirect - Release a redirect on a pty if present + * @tty: tty device + * + * This is available to the pty code so if the master closes, if the slave is a + * redirect it can release the redirect. + */ +static struct file *tty_release_redirect(struct tty_struct *tty) +{ + struct file *f = NULL; + + spin_lock(&redirect_lock); + if (redirect && file_tty(redirect) == tty) { + f = redirect; + redirect = NULL; + } + spin_unlock(&redirect_lock); + + return f; +} + +/** + * __tty_hangup - actual handler for hangup events + * @tty: tty device + * @exit_session: if non-zero, signal all foreground group processes * - * This can be called by a "kworker" kernel thread. That is process - * synchronous but doesn't hold any locks, so we need to make sure we - * have the appropriate locks for what we're doing. + * This can be called by a "kworker" kernel thread. That is process synchronous + * but doesn't hold any locks, so we need to make sure we have the appropriate + * locks for what we're doing. * - * The hangup event clears any pending redirections onto the hung up - * device. It ensures future writes will error and it does the needed - * line discipline hangup and signal delivery. The tty object itself - * remains intact. + * The hangup event clears any pending redirections onto the hung up device. It + * ensures future writes will error and it does the needed line discipline + * hangup and signal delivery. The tty object itself remains intact. + * + * Locking: + * * BTM + * + * * redirect lock for undoing redirection + * * file list lock for manipulating list of ttys + * * tty_ldiscs_lock from called functions + * * termios_rwsem resetting termios data + * * tasklist_lock to walk task list for hangup event + * + * * ->siglock to protect ->signal/->sighand * - * Locking: - * BTM - * redirect lock for undoing redirection - * file list lock for manipulating list of ttys - * tty_ldiscs_lock from called functions - * termios_rwsem resetting termios data - * tasklist_lock to walk task list for hangup event - * ->siglock to protect ->signal/->sighand */ static void __tty_hangup(struct tty_struct *tty, int exit_session) { struct file *cons_filp = NULL; - struct file *filp, *f = NULL; + struct file *filp, *f; struct tty_file_private *priv; int closecount = 0, n; int refs; @@ -575,13 +586,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) if (!tty) return; - - spin_lock(&redirect_lock); - if (redirect && file_tty(redirect) == tty) { - f = redirect; - redirect = NULL; - } - spin_unlock(&redirect_lock); + f = tty_release_redirect(tty); tty_lock(tty); @@ -599,17 +604,18 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) set_bit(TTY_HUPPING, &tty->flags); /* inuse_filps is protected by the single tty lock, - this really needs to change if we want to flush the - workqueue with the lock held */ + * this really needs to change if we want to flush the + * workqueue with the lock held. + */ check_tty_count(tty, "tty_hangup"); spin_lock(&tty->files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ list_for_each_entry(priv, &tty->tty_files, list) { filp = priv->file; - if (filp->f_op->write == redirected_tty_write) + if (filp->f_op->write_iter == redirected_tty_write) cons_filp = filp; - if (filp->f_op->write != tty_write) + if (filp->f_op->write_iter != tty_write) continue; closecount++; __tty_fasync(-1, filp, 0); /* can't block */ @@ -624,15 +630,15 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) tty_ldisc_hangup(tty, cons_filp != NULL); - spin_lock_irq(&tty->ctrl_lock); + spin_lock_irq(&tty->ctrl.lock); clear_bit(TTY_THROTTLED, &tty->flags); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->session = NULL; - tty->pgrp = NULL; - tty->ctrl_status = 0; - spin_unlock_irq(&tty->ctrl_lock); + put_pid(tty->ctrl.session); + put_pid(tty->ctrl.pgrp); + tty->ctrl.session = NULL; + tty->ctrl.pgrp = NULL; + tty->ctrl.pktstatus = 0; + spin_unlock_irq(&tty->ctrl.lock); /* * If one of the devices matches a console pointer, we @@ -668,45 +674,40 @@ static void do_tty_hangup(struct work_struct *work) } /** - * tty_hangup - trigger a hangup event - * @tty: tty to hangup + * tty_hangup - trigger a hangup event + * @tty: tty to hangup * - * A carrier loss (virtual or otherwise) has occurred on this like - * schedule a hangup sequence to run after this event. + * A carrier loss (virtual or otherwise) has occurred on @tty. Schedule a + * hangup sequence to run after this event. */ - void tty_hangup(struct tty_struct *tty) { tty_debug_hangup(tty, "hangup\n"); schedule_work(&tty->hangup_work); } - EXPORT_SYMBOL(tty_hangup); /** - * tty_vhangup - process vhangup - * @tty: tty to hangup + * tty_vhangup - process vhangup + * @tty: tty to hangup * - * The user has asked via system call for the terminal to be hung up. - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. + * The user has asked via system call for the terminal to be hung up. We do + * this synchronously so that when the syscall returns the process is complete. + * That guarantee is necessary for security reasons. */ - void tty_vhangup(struct tty_struct *tty) { tty_debug_hangup(tty, "vhangup\n"); __tty_hangup(tty, 0); } - EXPORT_SYMBOL(tty_vhangup); /** - * tty_vhangup_self - process vhangup for own ctty + * tty_vhangup_self - process vhangup for own ctty * - * Perform a vhangup on the current controlling tty + * Perform a vhangup on the current controlling tty */ - void tty_vhangup_self(void) { struct tty_struct *tty; @@ -719,16 +720,15 @@ void tty_vhangup_self(void) } /** - * tty_vhangup_session - hangup session leader exit - * @tty: tty to hangup + * tty_vhangup_session - hangup session leader exit + * @tty: tty to hangup * - * The session leader is exiting and hanging up its controlling terminal. - * Every process in the foreground process group is signalled SIGHUP. + * The session leader is exiting and hanging up its controlling terminal. + * Every process in the foreground process group is signalled %SIGHUP. * - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. + * We do this synchronously so that when the syscall returns the process is + * complete. That guarantee is necessary for security reasons. */ - void tty_vhangup_session(struct tty_struct *tty) { tty_debug_hangup(tty, "session hangup\n"); @@ -736,85 +736,78 @@ void tty_vhangup_session(struct tty_struct *tty) } /** - * tty_hung_up_p - was tty hung up - * @filp: file pointer of tty + * tty_hung_up_p - was tty hung up + * @filp: file pointer of tty * - * Return true if the tty has been subject to a vhangup or a carrier - * loss + * Return: true if the tty has been subject to a vhangup or a carrier loss */ - int tty_hung_up_p(struct file *filp) { return (filp && filp->f_op == &hung_up_tty_fops); } - EXPORT_SYMBOL(tty_hung_up_p); -/** - * stop_tty - propagate flow control - * @tty: tty to stop - * - * Perform flow control to the driver. May be called - * on an already stopped device and will not re-call the driver - * method. - * - * This functionality is used by both the line disciplines for - * halting incoming flow and by the driver. It may therefore be - * called from any context, may be under the tty atomic_write_lock - * but not always. - * - * Locking: - * flow_lock - */ - void __stop_tty(struct tty_struct *tty) { - if (tty->stopped) + if (tty->flow.stopped) return; - tty->stopped = 1; + tty->flow.stopped = true; if (tty->ops->stop) tty->ops->stop(tty); } +/** + * stop_tty - propagate flow control + * @tty: tty to stop + * + * Perform flow control to the driver. May be called on an already stopped + * device and will not re-call the &tty_driver->stop() method. + * + * This functionality is used by both the line disciplines for halting incoming + * flow and by the driver. It may therefore be called from any context, may be + * under the tty %atomic_write_lock but not always. + * + * Locking: + * flow.lock + */ void stop_tty(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->flow_lock, flags); + spin_lock_irqsave(&tty->flow.lock, flags); __stop_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); + spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(stop_tty); -/** - * start_tty - propagate flow control - * @tty: tty to start - * - * Start a tty that has been stopped if at all possible. If this - * tty was previous stopped and is now being started, the driver - * start method is invoked and the line discipline woken. - * - * Locking: - * flow_lock - */ - void __start_tty(struct tty_struct *tty) { - if (!tty->stopped || tty->flow_stopped) + if (!tty->flow.stopped || tty->flow.tco_stopped) return; - tty->stopped = 0; + tty->flow.stopped = false; if (tty->ops->start) tty->ops->start(tty); tty_wakeup(tty); } +/** + * start_tty - propagate flow control + * @tty: tty to start + * + * Start a tty that has been stopped if at all possible. If @tty was previously + * stopped and is now being started, the &tty_driver->start() method is invoked + * and the line discipline woken. + * + * Locking: + * flow.lock + */ void start_tty(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->flow_lock, flags); + spin_lock_irqsave(&tty->flow.lock, flags); __start_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); + spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(start_tty); @@ -832,25 +825,88 @@ static void tty_update_time(struct timespec64 *time) time->tv_sec = sec; } -/** - * tty_read - read method for tty device files - * @file: pointer to tty file - * @buf: user buffer - * @count: size of user buffer - * @ppos: unused +/* + * Iterate on the ldisc ->read() function until we've gotten all + * the data the ldisc has for us. * - * Perform the read system call function on this terminal device. Checks - * for hung up devices before calling the line discipline method. + * The "cookie" is something that the ldisc read function can fill + * in to let us know that there is more data to be had. * - * Locking: - * Locks the line discipline internally while needed. Multiple - * read calls may be outstanding in parallel. + * We promise to continue to call the ldisc until it stops returning + * data or clears the cookie. The cookie may be something that the + * ldisc maintains state for and needs to free. */ +static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, + struct file *file, struct iov_iter *to) +{ + int retval = 0; + void *cookie = NULL; + unsigned long offset = 0; + char kernel_buf[64]; + size_t count = iov_iter_count(to); + + do { + int size, copied; + + size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count; + size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset); + if (!size) + break; + + if (size < 0) { + /* Did we have an earlier error (ie -EFAULT)? */ + if (retval) + break; + retval = size; + + /* + * -EOVERFLOW means we didn't have enough space + * for a whole packet, and we shouldn't return + * a partial result. + */ + if (retval == -EOVERFLOW) + offset = 0; + break; + } + + copied = copy_to_iter(kernel_buf, size, to); + offset += copied; + count -= copied; -static ssize_t tty_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) + /* + * If the user copy failed, we still need to do another ->read() + * call if we had a cookie to let the ldisc clear up. + * + * But make sure size is zeroed. + */ + if (unlikely(copied != size)) { + count = 0; + retval = -EFAULT; + } + } while (cookie); + + /* We always clear tty buffer in case they contained passwords */ + memzero_explicit(kernel_buf, sizeof(kernel_buf)); + return offset ? offset : retval; +} + + +/** + * tty_read - read method for tty device files + * @iocb: kernel I/O control block + * @to: destination for the data read + * + * Perform the read system call function on this terminal device. Checks + * for hung up devices before calling the line discipline method. + * + * Locking: + * Locks the line discipline internally while needed. Multiple read calls + * may be outstanding in parallel. + */ +static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) { int i; + struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; @@ -861,14 +917,14 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, return -EIO; /* We want to wait for the line discipline to sort out in this - situation */ + * situation. + */ ld = tty_ldisc_ref_wait(tty); if (!ld) - return hung_up_tty_read(file, buf, count, ppos); + return hung_up_tty_read(iocb, to); + i = -EIO; if (ld->ops->read) - i = ld->ops->read(tty, file, buf, count); - else - i = -EIO; + i = iterate_tty_read(ld, tty, file, to); tty_ldisc_deref(ld); if (i > 0) @@ -902,9 +958,9 @@ static inline ssize_t do_tty_write( ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t), struct tty_struct *tty, struct file *file, - const char __user *buf, - size_t count) + struct iov_iter *from) { + size_t count = iov_iter_count(from); ssize_t ret, written = 0; unsigned int chunk; @@ -924,9 +980,6 @@ static inline ssize_t do_tty_write( * layer has problems with bigger chunks. It will * claim to be able to handle more characters than * it actually does. - * - * FIXME: This can probably go away now except that 64K chunks - * are too likely to fail unless switched to vmalloc... */ chunk = 2048; if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) @@ -941,12 +994,12 @@ static inline ssize_t do_tty_write( if (chunk < 1024) chunk = 1024; - buf_chunk = kmalloc(chunk, GFP_KERNEL); + buf_chunk = kvmalloc(chunk, GFP_KERNEL | __GFP_RETRY_MAYFAIL); if (!buf_chunk) { ret = -ENOMEM; goto out; } - kfree(tty->write_buf); + kvfree(tty->write_buf); tty->write_cnt = chunk; tty->write_buf = buf_chunk; } @@ -954,16 +1007,26 @@ static inline ssize_t do_tty_write( /* Do the write .. */ for (;;) { size_t size = count; + if (size > chunk) size = chunk; + ret = -EFAULT; - if (copy_from_user(tty->write_buf, buf, size)) + if (copy_from_iter(tty->write_buf, size, from) != size) break; + ret = write(tty, file, tty->write_buf, size); if (ret <= 0) break; + written += ret; - buf += ret; + if (ret > size) + break; + + /* FIXME! Have Al check this! */ + if (ret != size) + iov_iter_revert(from, size-ret); + count -= ret; if (!count) break; @@ -986,13 +1049,12 @@ out: * @tty: the destination tty_struct * @msg: the message to write * - * This is used for messages that need to be redirected to a specific tty. - * We don't put it into the syslog queue right now maybe in the future if - * really needed. + * This is used for messages that need to be redirected to a specific tty. We + * don't put it into the syslog queue right now maybe in the future if really + * needed. * * We must still hold the BTM and test the CLOSING flag for the moment. */ - void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { @@ -1003,53 +1065,52 @@ void tty_write_message(struct tty_struct *tty, char *msg) tty_unlock(tty); tty_write_unlock(tty); } - return; } - -/** - * tty_write - write method for tty device file - * @file: tty file pointer - * @buf: user data to write - * @count: bytes to write - * @ppos: unused - * - * Write data to a tty device via the line discipline. - * - * Locking: - * Locks the line discipline as required - * Writes to the tty driver are serialized by the atomic_write_lock - * and are then processed in chunks to the device. The line discipline - * write method will not be invoked in parallel for each device. - */ - -static ssize_t tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from) { struct tty_struct *tty = file_tty(file); - struct tty_ldisc *ld; + struct tty_ldisc *ld; ssize_t ret; if (tty_paranoia_check(tty, file_inode(file), "tty_write")) return -EIO; if (!tty || !tty->ops->write || tty_io_error(tty)) - return -EIO; + return -EIO; /* Short term debug to catch buggy drivers */ if (tty->ops->write_room == NULL) tty_err(tty, "missing write_room method\n"); ld = tty_ldisc_ref_wait(tty); if (!ld) - return hung_up_tty_write(file, buf, count, ppos); + return hung_up_tty_write(iocb, from); if (!ld->ops->write) ret = -EIO; else - ret = do_tty_write(ld->ops->write, tty, file, buf, count); + ret = do_tty_write(ld->ops->write, tty, file, from); tty_ldisc_deref(ld); return ret; } -ssize_t redirected_tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) +/** + * tty_write - write method for tty device file + * @iocb: kernel I/O control block + * @from: iov_iter with data to write + * + * Write data to a tty device via the line discipline. + * + * Locking: + * Locks the line discipline as required + * Writes to the tty driver are serialized by the atomic_write_lock + * and are then processed in chunks to the device. The line + * discipline write method will not be invoked in parallel for + * each device. + */ +static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from) +{ + return file_tty_write(iocb->ki_filp, iocb, from); +} + +ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) { struct file *p = NULL; @@ -1058,26 +1119,32 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, p = get_file(redirect); spin_unlock(&redirect_lock); + /* + * We know the redirected tty is just another tty, we can + * call file_tty_write() directly with that file pointer. + */ if (p) { ssize_t res; - res = vfs_write(p, buf, count, &p->f_pos); + + res = file_tty_write(p, iocb, iter); fput(p); return res; } - return tty_write(file, buf, count, ppos); + return tty_write(iocb, iter); } /** - * tty_send_xchar - send priority character + * tty_send_xchar - send priority character + * @tty: the tty to send to + * @ch: xchar to send * - * Send a high priority character to the tty even if stopped + * Send a high priority character to the tty even if stopped. * - * Locking: none for xchar method, write ordering for write method. + * Locking: none for xchar method, write ordering for write method. */ - int tty_send_xchar(struct tty_struct *tty, char ch) { - int was_stopped = tty->stopped; + bool was_stopped = tty->flow.stopped; if (tty->ops->send_xchar) { down_read(&tty->termios_rwsem); @@ -1100,21 +1167,20 @@ int tty_send_xchar(struct tty_struct *tty, char ch) return 0; } -static char ptychar[] = "pqrstuvwxyzabcde"; - /** - * pty_line_name - generate name for a pty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 6 bytes + * pty_line_name - generate name for a pty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 6 bytes * - * Generate a name from a driver reference and write it to the output - * buffer. + * Generate a name from a @driver reference and write it to the output buffer + * @p. * - * Locking: None + * Locking: None */ static void pty_line_name(struct tty_driver *driver, int index, char *p) { + static const char ptychar[] = "pqrstuvwxyzabcde"; int i = index + driver->name_base; /* ->name is initialized to "ttyp", but "tty" is expected */ sprintf(p, "%s%c%x", @@ -1123,15 +1189,15 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_line_name - generate name for a tty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 7 bytes + * tty_line_name - generate name for a tty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 7 bytes * - * Generate a name from a driver reference and write it to the output - * buffer. + * Generate a name from a @driver reference and write it to the output buffer + * @p. * - * Locking: None + * Locking: None */ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) { @@ -1143,14 +1209,15 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_driver_lookup_tty() - find an existing tty, if any - * @driver: the driver for the tty - * @idx: the minor number + * tty_driver_lookup_tty() - find an existing tty, if any + * @driver: the driver for the tty + * @file: file object + * @idx: the minor number * - * Return the tty, if found. If not found, return NULL or ERR_PTR() if the - * driver lookup() method returns an error. + * Return: the tty, if found. If not found, return %NULL or ERR_PTR() if the + * driver lookup() method returns an error. * - * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. + * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. */ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct file *file, int idx) @@ -1171,13 +1238,12 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, } /** - * tty_init_termios - helper for termios setup - * @tty: the tty to set up + * tty_init_termios - helper for termios setup + * @tty: the tty to set up * - * Initialise the termios structure for this tty. This runs under - * the tty_mutex currently so we can be relaxed about ordering. + * Initialise the termios structure for this tty. This runs under the + * %tty_mutex currently so we can be relaxed about ordering. */ - void tty_init_termios(struct tty_struct *tty) { struct ktermios *tp; @@ -1200,6 +1266,14 @@ void tty_init_termios(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_init_termios); +/** + * tty_standard_install - usual tty->ops->install + * @driver: the driver for the tty + * @tty: the tty + * + * If the @driver overrides @tty->ops->install, it still can call this function + * to perform the standard install operations. + */ int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) { tty_init_termios(tty); @@ -1211,16 +1285,15 @@ int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_standard_install); /** - * tty_driver_install_tty() - install a tty entry in the driver - * @driver: the driver for the tty - * @tty: the tty + * tty_driver_install_tty() - install a tty entry in the driver + * @driver: the driver for the tty + * @tty: the tty * - * Install a tty object into the driver tables. The tty->index field - * will be set by the time this is called. This method is responsible - * for ensuring any need additional structures are allocated and - * configured. + * Install a tty object into the driver tables. The @tty->index field will be + * set by the time this is called. This method is responsible for ensuring any + * need additional structures are allocated and configured. * - * Locking: tty_mutex for now + * Locking: tty_mutex for now */ static int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty) @@ -1230,14 +1303,14 @@ static int tty_driver_install_tty(struct tty_driver *driver, } /** - * tty_driver_remove_tty() - remove a tty from the driver tables - * @driver: the driver for the tty - * @idx: the minor number + * tty_driver_remove_tty() - remove a tty from the driver tables + * @driver: the driver for the tty + * @tty: tty to remove * - * Remvoe a tty object from the driver tables. The tty->index field - * will be set by the time this is called. + * Remove a tty object from the driver tables. The tty->index field will be set + * by the time this is called. * - * Locking: tty_mutex for now + * Locking: tty_mutex for now */ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) { @@ -1247,14 +1320,14 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * driver->ttys[tty->index] = NULL; } -/* - * tty_reopen() - fast re-open of an open tty - * @tty - the tty to open +/** + * tty_reopen() - fast re-open of an open tty + * @tty: the tty to open * - * Return 0 on success, -errno on error. - * Re-opens on master ptys are not allowed and return -EIO. + * Re-opens on master ptys are not allowed and return -%EIO. * - * Locking: Caller must hold tty_lock + * Locking: Caller must hold tty_lock + * Return: 0 on success, -errno on error. */ static int tty_reopen(struct tty_struct *tty) { @@ -1292,29 +1365,28 @@ static int tty_reopen(struct tty_struct *tty) } /** - * tty_init_dev - initialise a tty device - * @driver: tty driver we are opening a device on - * @idx: device index - * @ret_tty: returned tty structure + * tty_init_dev - initialise a tty device + * @driver: tty driver we are opening a device on + * @idx: device index + * + * Prepare a tty device. This may not be a "new" clean device but could also be + * an active device. The pty drivers require special handling because of this. * - * Prepare a tty device. This may not be a "new" clean device but - * could also be an active device. The pty drivers require special - * handling because of this. + * Locking: + * The function is called under the tty_mutex, which protects us from the + * tty struct or driver itself going away. * - * Locking: - * The function is called under the tty_mutex, which - * protects us from the tty struct or driver itself going away. + * On exit the tty device has the line discipline attached and a reference + * count of 1. If a pair was created for pty/tty use and the other was a pty + * master then it too has a reference count of 1. * - * On exit the tty device has the line discipline attached and - * a reference count of 1. If a pair was created for pty/tty use - * and the other was a pty master then it too has a reference count of 1. + * WSH 06/09/97: Rewritten to remove races and properly clean up after a failed + * open. The new code protects the open with a mutex, so it's really quite + * straightforward. The mutex locking can probably be relaxed for the (most + * common) case of reopening a tty. * - * WSH 06/09/97: Rewritten to remove races and properly clean up after a - * failed open. The new code protects the open with a mutex, so it's - * really quite straightforward. The mutex locking can probably be - * relaxed for the (most common) case of reopening a tty. + * Return: new tty structure */ - struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) { struct tty_struct *tty; @@ -1405,7 +1477,7 @@ void tty_save_termios(struct tty_struct *tty) /* Stash the termios data */ tp = tty->driver->termios[idx]; if (tp == NULL) { - tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + tp = kmalloc(sizeof(*tp), GFP_KERNEL); if (tp == NULL) return; tty->driver->termios[idx] = tp; @@ -1415,10 +1487,10 @@ void tty_save_termios(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_save_termios); /** - * tty_flush_works - flush all works of a tty/pty pair - * @tty: tty device to flush works for (or either end of a pty pair) + * tty_flush_works - flush all works of a tty/pty pair + * @tty: tty device to flush works for (or either end of a pty pair) * - * Sync flush all works belonging to @tty (and the 'other' tty). + * Sync flush all works belonging to @tty (and the 'other' tty). */ static void tty_flush_works(struct tty_struct *tty) { @@ -1431,19 +1503,19 @@ static void tty_flush_works(struct tty_struct *tty) } /** - * release_one_tty - release tty structure memory - * @kref: kref of tty we are obliterating + * release_one_tty - release tty structure memory + * @work: work of tty we are obliterating * - * Releases memory associated with a tty structure, and clears out the - * driver table slots. This function is called when a device is no longer - * in use. It also gets called when setup of a device fails. + * Releases memory associated with a tty structure, and clears out the + * driver table slots. This function is called when a device is no longer + * in use. It also gets called when setup of a device fails. * - * Locking: - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. + * Locking: + * takes the file list lock internally when working on the list of ttys + * that the driver keeps. * - * This method gets called from a work queue so that the driver private - * cleanup ops can sleep (needed for USB at least) + * This method gets called from a work queue so that the driver private + * cleanup ops can sleep (needed for USB at least) */ static void release_one_tty(struct work_struct *work) { @@ -1455,7 +1527,6 @@ static void release_one_tty(struct work_struct *work) if (tty->ops->cleanup) tty->ops->cleanup(tty); - tty->magic = 0; tty_driver_kref_put(driver); module_put(owner); @@ -1463,8 +1534,8 @@ static void release_one_tty(struct work_struct *work) list_del_init(&tty->tty_files); spin_unlock(&tty->files_lock); - put_pid(tty->pgrp); - put_pid(tty->session); + put_pid(tty->ctrl.pgrp); + put_pid(tty->ctrl.session); free_tty_struct(tty); } @@ -1473,19 +1544,19 @@ static void queue_release_one_tty(struct kref *kref) struct tty_struct *tty = container_of(kref, struct tty_struct, kref); /* The hangup queue is now free so we can reuse it rather than - waste a chunk of memory for each port */ + * waste a chunk of memory for each port. + */ INIT_WORK(&tty->hangup_work, release_one_tty); schedule_work(&tty->hangup_work); } /** - * tty_kref_put - release a tty kref - * @tty: tty device + * tty_kref_put - release a tty kref + * @tty: tty device * - * Release a reference to a tty device and if need be let the kref - * layer destruct the object for us + * Release a reference to the @tty device and if need be let the kref layer + * destruct the object for us. */ - void tty_kref_put(struct tty_struct *tty) { if (tty) @@ -1494,16 +1565,17 @@ void tty_kref_put(struct tty_struct *tty) EXPORT_SYMBOL(tty_kref_put); /** - * release_tty - release tty structure memory - * - * Release both @tty and a possible linked partner (think pty pair), - * and decrement the refcount of the backing module. + * release_tty - release tty structure memory + * @tty: tty device release + * @idx: index of the tty device release * - * Locking: - * tty_mutex - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. + * Release both @tty and a possible linked partner (think pty pair), + * and decrement the refcount of the backing module. * + * Locking: + * tty_mutex + * takes the file list lock internally when working on the list of ttys + * that the driver keeps. */ static void release_tty(struct tty_struct *tty, int idx) { @@ -1514,10 +1586,12 @@ static void release_tty(struct tty_struct *tty, int idx) tty->ops->shutdown(tty); tty_save_termios(tty); tty_driver_remove_tty(tty->driver, tty); - tty->port->itty = NULL; + if (tty->port) + tty->port->itty = NULL; if (tty->link) tty->link->port->itty = NULL; - tty_buffer_cancel_work(tty->port); + if (tty->port) + tty_buffer_cancel_work(tty->port); if (tty->link) tty_buffer_cancel_work(tty->link->port); @@ -1526,13 +1600,12 @@ static void release_tty(struct tty_struct *tty, int idx) } /** - * tty_release_checks - check a tty before real release - * @tty: tty to check - * @o_tty: link of @tty (if any) - * @idx: index of the tty + * tty_release_checks - check a tty before real release + * @tty: tty to check + * @idx: index of the tty * - * Performs some paranoid checking before true release of the @tty. - * This is a no-op unless TTY_PARANOIA_CHECK is defined. + * Performs some paranoid checking before true release of the @tty. This is a + * no-op unless %TTY_PARANOIA_CHECK is defined. */ static int tty_release_checks(struct tty_struct *tty, int idx) { @@ -1569,12 +1642,12 @@ static int tty_release_checks(struct tty_struct *tty, int idx) } /** - * tty_kclose - closes tty opened by tty_kopen - * @tty: tty device + * tty_kclose - closes tty opened by tty_kopen + * @tty: tty device * - * Performs the final steps to release and free a tty device. It is the - * same as tty_release_struct except that it also resets TTY_PORT_KOPENED - * flag on tty->port. + * Performs the final steps to release and free a tty device. It is the same as + * tty_release_struct() except that it also resets %TTY_PORT_KOPENED flag on + * @tty->port. */ void tty_kclose(struct tty_struct *tty) { @@ -1583,7 +1656,7 @@ void tty_kclose(struct tty_struct *tty) */ tty_ldisc_release(tty); - /* Wait for pending work before tty destruction commmences */ + /* Wait for pending work before tty destruction commences */ tty_flush_works(tty); tty_debug_hangup(tty, "freeing structure\n"); @@ -1599,12 +1672,12 @@ void tty_kclose(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_kclose); /** - * tty_release_struct - release a tty struct - * @tty: tty device - * @idx: index of the tty + * tty_release_struct - release a tty struct + * @tty: tty device + * @idx: index of the tty * - * Performs the final steps to release and free a tty device. It is - * roughly the reverse of tty_init_dev. + * Performs the final steps to release and free a tty device. It is roughly the + * reverse of tty_init_dev(). */ void tty_release_struct(struct tty_struct *tty, int idx) { @@ -1628,24 +1701,23 @@ void tty_release_struct(struct tty_struct *tty, int idx) EXPORT_SYMBOL_GPL(tty_release_struct); /** - * tty_release - vfs callback for close - * @inode: inode of tty - * @filp: file pointer for handle to tty + * tty_release - vfs callback for close + * @inode: inode of tty + * @filp: file pointer for handle to tty * - * Called the last time each file handle is closed that references - * this tty. There may however be several such references. + * Called the last time each file handle is closed that references this tty. + * There may however be several such references. * - * Locking: - * Takes bkl. See tty_release_dev + * Locking: + * Takes BKL. See tty_release_dev(). * - * Even releasing the tty structures is a tricky business.. We have - * to be very careful that the structures are all released at the - * same time, as interrupts might otherwise get the wrong pointers. + * Even releasing the tty structures is a tricky business. We have to be very + * careful that the structures are all released at the same time, as interrupts + * might otherwise get the wrong pointers. * * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ - int tty_release(struct inode *inode, struct file *filp) { struct tty_struct *tty = file_tty(filp); @@ -1762,9 +1834,9 @@ int tty_release(struct inode *inode, struct file *filp) */ if (!tty->count) { read_lock(&tasklist_lock); - session_clear_tty(tty->session); + session_clear_tty(tty->ctrl.session); if (o_tty) - session_clear_tty(o_tty->session); + session_clear_tty(o_tty->ctrl.session); read_unlock(&tasklist_lock); } @@ -1775,7 +1847,8 @@ int tty_release(struct inode *inode, struct file *filp) tty_unlock(tty); /* At this point, the tty->count == 0 should ensure a dead tty - cannot be re-opened by a racing opener */ + * cannot be re-opened by a racing opener. + */ if (!final) return 0; @@ -1787,15 +1860,15 @@ int tty_release(struct inode *inode, struct file *filp) } /** - * tty_open_current_tty - get locked tty of current task - * @device: device number - * @filp: file pointer to tty - * @return: locked tty of the current task iff @device is /dev/tty + * tty_open_current_tty - get locked tty of current task + * @device: device number + * @filp: file pointer to tty + * @return: locked tty of the current task iff @device is /dev/tty * - * Performs a re-open of the current task's controlling tty. + * Performs a re-open of the current task's controlling tty. * - * We cannot return driver and index like for the other nodes because - * devpts will not work then. It expects inodes to be from devpts FS. + * We cannot return driver and index like for the other nodes because devpts + * will not work then. It expects inodes to be from devpts FS. */ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) { @@ -1823,16 +1896,17 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) } /** - * tty_lookup_driver - lookup a tty driver for a given device file - * @device: device number - * @filp: file pointer to tty - * @index: index for the device in the @return driver - * @return: driver for this inode (with increased refcount) + * tty_lookup_driver - lookup a tty driver for a given device file + * @device: device number + * @filp: file pointer to tty + * @index: index for the device in the @return driver * - * If @return is not erroneous, the caller is responsible to decrement the - * refcount by tty_driver_kref_put. + * If returned value is not erroneous, the caller is responsible to decrement + * the refcount by tty_driver_kref_put(). * - * Locking: tty_mutex protects get_tty_driver + * Locking: %tty_mutex protects get_tty_driver() + * + * Return: driver for this inode (with increased refcount) */ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, int *index) @@ -1843,6 +1917,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, #ifdef CONFIG_VT case MKDEV(TTY_MAJOR, 0): { extern struct tty_driver *console_driver; + driver = tty_driver_kref_get(console_driver); *index = fg_console; break; @@ -1850,6 +1925,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, #endif case MKDEV(TTYAUX_MAJOR, 1): { struct tty_driver *console_driver = console_device(index); + if (console_driver) { driver = tty_driver_kref_get(console_driver); if (driver && filp) { @@ -1871,22 +1947,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, return driver; } -/** - * tty_kopen - open a tty device for kernel - * @device: dev_t of device to open - * - * Opens tty exclusively for kernel. Performs the driver lookup, - * makes sure it's not already opened and performs the first-time - * tty initialization. - * - * Returns the locked initialized &tty_struct - * - * Claims the global tty_mutex to serialize: - * - concurrent first-time tty initialization - * - concurrent tty driver removal w/ lookup - * - concurrent tty removal from driver table - */ -struct tty_struct *tty_kopen(dev_t device) +static struct tty_struct *tty_kopen(dev_t device, int shared) { struct tty_struct *tty; struct tty_driver *driver; @@ -1901,7 +1962,7 @@ struct tty_struct *tty_kopen(dev_t device) /* check whether we're reopening an existing tty */ tty = tty_driver_lookup_tty(driver, NULL, index); - if (IS_ERR(tty)) + if (IS_ERR(tty) || shared) goto out; if (tty) { @@ -1919,22 +1980,57 @@ out: tty_driver_kref_put(driver); return tty; } -EXPORT_SYMBOL_GPL(tty_kopen); /** - * tty_open_by_driver - open a tty device - * @device: dev_t of device to open - * @filp: file pointer to tty + * tty_kopen_exclusive - open a tty device for kernel + * @device: dev_t of device to open + * + * Opens tty exclusively for kernel. Performs the driver lookup, makes sure + * it's not already opened and performs the first-time tty initialization. + * + * Claims the global %tty_mutex to serialize: + * * concurrent first-time tty initialization + * * concurrent tty driver removal w/ lookup + * * concurrent tty removal from driver table * - * Performs the driver lookup, checks for a reopen, or otherwise - * performs the first-time tty initialization. + * Return: the locked initialized &tty_struct + */ +struct tty_struct *tty_kopen_exclusive(dev_t device) +{ + return tty_kopen(device, 0); +} +EXPORT_SYMBOL_GPL(tty_kopen_exclusive); + +/** + * tty_kopen_shared - open a tty device for shared in-kernel use + * @device: dev_t of device to open * - * Returns the locked initialized or re-opened &tty_struct + * Opens an already existing tty for in-kernel use. Compared to + * tty_kopen_exclusive() above it doesn't ensure to be the only user. * - * Claims the global tty_mutex to serialize: - * - concurrent first-time tty initialization - * - concurrent tty driver removal w/ lookup - * - concurrent tty removal from driver table + * Locking: identical to tty_kopen() above. + */ +struct tty_struct *tty_kopen_shared(dev_t device) +{ + return tty_kopen(device, 1); +} +EXPORT_SYMBOL_GPL(tty_kopen_shared); + +/** + * tty_open_by_driver - open a tty device + * @device: dev_t of device to open + * @filp: file pointer to tty + * + * Performs the driver lookup, checks for a reopen, or otherwise performs the + * first-time tty initialization. + * + * + * Claims the global tty_mutex to serialize: + * * concurrent first-time tty initialization + * * concurrent tty driver removal w/ lookup + * * concurrent tty removal from driver table + * + * Return: the locked initialized or re-opened &tty_struct */ static struct tty_struct *tty_open_by_driver(dev_t device, struct file *filp) @@ -1989,29 +2085,28 @@ out: } /** - * tty_open - open a tty device - * @inode: inode of device file - * @filp: file pointer to tty + * tty_open - open a tty device + * @inode: inode of device file + * @filp: file pointer to tty * - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. + * tty_open() and tty_release() keep up the tty count that contains the number + * of opens done on a tty. We cannot use the inode-count, as different inodes + * might point to the same tty. * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) + * Open-counting is needed for pty masters, as well as for keeping track of + * serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. + * The termios state of a pty is reset on the first open so that settings don't + * persist across reuse. * - * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. - * tty->count should protect the rest. - * ->siglock protects ->signal/->sighand + * Locking: + * * %tty_mutex protects tty, tty_lookup_driver() and tty_init_dev(). + * * @tty->count should protect the rest. + * * ->siglock protects ->signal/->sighand * - * Note: the tty_unlock/lock cases without a ref are only safe due to - * tty_mutex + * Note: the tty_unlock/lock cases without a ref are only safe due to %tty_mutex */ - static int tty_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; @@ -2083,19 +2178,17 @@ retry_open: } - /** - * tty_poll - check tty status - * @filp: file being polled - * @wait: poll wait structures to update + * tty_poll - check tty status + * @filp: file being polled + * @wait: poll wait structures to update * - * Call the line discipline polling method to obtain the poll - * status of the device. + * Call the line discipline polling method to obtain the poll status of the + * device. * - * Locking: locks called line discipline but ldisc poll method - * may be re-entered freely by other callers. + * Locking: locks called line discipline but ldisc poll method may be + * re-entered freely by other callers. */ - static __poll_t tty_poll(struct file *filp, poll_table *wait) { struct tty_struct *tty = file_tty(filp); @@ -2131,16 +2224,16 @@ static int __tty_fasync(int fd, struct file *filp, int on) enum pid_type type; struct pid *pid; - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (tty->pgrp) { - pid = tty->pgrp; + spin_lock_irqsave(&tty->ctrl.lock, flags); + if (tty->ctrl.pgrp) { + pid = tty->ctrl.pgrp; type = PIDTYPE_PGID; } else { pid = task_pid(current); type = PIDTYPE_TGID; } get_pid(pid); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); __f_setown(filp, pid, type, 0); put_pid(pid); retval = 0; @@ -2163,22 +2256,18 @@ static int tty_fasync(int fd, struct file *filp, int on) } /** - * tiocsti - fake input character - * @tty: tty to fake input into - * @p: pointer to character + * tiocsti - fake input character + * @tty: tty to fake input into + * @p: pointer to character * - * Fake input to a tty device. Does the necessary locking and - * input management. + * Fake input to a tty device. Does the necessary locking and input management. * - * FIXME: does not honour flow control ?? + * FIXME: does not honour flow control ?? * - * Locking: - * Called functions take tty_ldiscs_lock - * current->signal->tty check is safe without locks - * - * FIXME: may race normal receive processing + * Locking: + * * Called functions take tty_ldiscs_lock + * * current->signal->tty check is safe without locks */ - static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; @@ -2192,23 +2281,24 @@ static int tiocsti(struct tty_struct *tty, char __user *p) ld = tty_ldisc_ref_wait(tty); if (!ld) return -EIO; + tty_buffer_lock_exclusive(tty->port); if (ld->ops->receive_buf) ld->ops->receive_buf(tty, &ch, &mbz, 1); + tty_buffer_unlock_exclusive(tty->port); tty_ldisc_deref(ld); return 0; } /** - * tiocgwinsz - implement window query ioctl - * @tty; tty - * @arg: user buffer for result + * tiocgwinsz - implement window query ioctl + * @tty: tty + * @arg: user buffer for result * - * Copies the kernel idea of the window size into the user buffer. + * Copies the kernel idea of the window size into the user buffer. * - * Locking: tty->winsize_mutex is taken to ensure the winsize data - * is consistent. + * Locking: @tty->winsize_mutex is taken to ensure the winsize data is + * consistent. */ - static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) { int err; @@ -2217,19 +2307,17 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); mutex_unlock(&tty->winsize_mutex); - return err ? -EFAULT: 0; + return err ? -EFAULT : 0; } /** - * tty_do_resize - resize event - * @tty: tty being resized - * @rows: rows (character) - * @cols: cols (character) + * tty_do_resize - resize event + * @tty: tty being resized + * @ws: new dimensions * - * Update the termios variables and send the necessary signals to - * peform a terminal resize correctly + * Update the termios variables and send the necessary signals to peform a + * terminal resize correctly. */ - int tty_do_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp; @@ -2253,23 +2341,23 @@ done: EXPORT_SYMBOL(tty_do_resize); /** - * tiocswinsz - implement window size set ioctl - * @tty; tty side of tty - * @arg: user buffer for result + * tiocswinsz - implement window size set ioctl + * @tty: tty side of tty + * @arg: user buffer for result * - * Copies the user idea of the window size to the kernel. Traditionally - * this is just advisory information but for the Linux console it - * actually has driver level meaning and triggers a VC resize. + * Copies the user idea of the window size to the kernel. Traditionally this is + * just advisory information but for the Linux console it actually has driver + * level meaning and triggers a VC resize. * - * Locking: - * Driver dependent. The default do_resize method takes the - * tty termios mutex and ctrl_lock. The console takes its own lock - * then calls into the default method. + * Locking: + * Driver dependent. The default do_resize method takes the tty termios + * mutex and ctrl.lock. The console takes its own lock then calls into the + * default method. */ - static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) { struct winsize tmp_ws; + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; @@ -2280,20 +2368,20 @@ static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) } /** - * tioccons - allow admin to move logical console - * @file: the file to become console + * tioccons - allow admin to move logical console + * @file: the file to become console * - * Allow the administrator to move the redirected console device + * Allow the administrator to move the redirected console device. * - * Locking: uses redirect_lock to guard the redirect information + * Locking: uses redirect_lock to guard the redirect information */ - static int tioccons(struct file *file) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (file->f_op->write == redirected_tty_write) { + if (file->f_op->write_iter == redirected_tty_write) { struct file *f; + spin_lock(&redirect_lock); f = redirect; redirect = NULL; @@ -2302,6 +2390,12 @@ static int tioccons(struct file *file) fput(f); return 0; } + if (file->f_op->write_iter != tty_write) + return -ENOTTY; + if (!(file->f_mode & FMODE_WRITE)) + return -EBADF; + if (!(file->f_mode & FMODE_CAN_WRITE)) + return -EINVAL; spin_lock(&redirect_lock); if (redirect) { spin_unlock(&redirect_lock); @@ -2313,15 +2407,14 @@ static int tioccons(struct file *file) } /** - * tiocsetd - set line discipline - * @tty: tty device - * @p: pointer to user data + * tiocsetd - set line discipline + * @tty: tty device + * @p: pointer to user data * - * Set the line discipline according to user request. + * Set the line discipline according to user request. * - * Locking: see tty_set_ldisc, this function is just a helper + * Locking: see tty_set_ldisc(), this function is just a helper */ - static int tiocsetd(struct tty_struct *tty, int __user *p) { int disc; @@ -2336,16 +2429,15 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) } /** - * tiocgetd - get line discipline - * @tty: tty device - * @p: pointer to user data + * tiocgetd - get line discipline + * @tty: tty device + * @p: pointer to user data * - * Retrieves the line discipline id directly from the ldisc. + * Retrieves the line discipline id directly from the ldisc. * - * Locking: waits for ldisc reference (in case the line discipline - * is changing or the tty is being hungup) + * Locking: waits for ldisc reference (in case the line discipline is changing + * or the @tty is being hungup) */ - static int tiocgetd(struct tty_struct *tty, int __user *p) { struct tty_ldisc *ld; @@ -2360,18 +2452,16 @@ static int tiocgetd(struct tty_struct *tty, int __user *p) } /** - * send_break - performed time break - * @tty: device to break on - * @duration: timeout in mS + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS * - * Perform a timed break on hardware that lacks its own driver level - * timed break functionality. - * - * Locking: - * atomic_write_lock serializes + * Perform a timed break on hardware that lacks its own driver level timed + * break functionality. * + * Locking: + * @tty->atomic_write_lock serializes */ - static int send_break(struct tty_struct *tty, unsigned int duration) { int retval; @@ -2400,20 +2490,18 @@ out: } /** - * tty_tiocmget - get modem status - * @tty: tty device - * @file: user file pointer - * @p: pointer to result + * tty_tiocmget - get modem status + * @tty: tty device + * @p: pointer to result * - * Obtain the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. + * Obtain the modem status bits from the tty driver if the feature is + * supported. Return -%ENOTTY if it is not available. * - * Locking: none (up to the driver) + * Locking: none (up to the driver) */ - static int tty_tiocmget(struct tty_struct *tty, int __user *p) { - int retval = -EINVAL; + int retval = -ENOTTY; if (tty->ops->tiocmget) { retval = tty->ops->tiocmget(tty); @@ -2425,17 +2513,16 @@ static int tty_tiocmget(struct tty_struct *tty, int __user *p) } /** - * tty_tiocmset - set modem status - * @tty: tty device - * @cmd: command - clear bits, set bits or set all - * @p: pointer to desired bits + * tty_tiocmset - set modem status + * @tty: tty device + * @cmd: command - clear bits, set bits or set all + * @p: pointer to desired bits * - * Set the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. + * Set the modem status bits from the tty driver if the feature + * is supported. Return -%ENOTTY if it is not available. * - * Locking: none (up to the driver) + * Locking: none (up to the driver) */ - static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, unsigned __user *p) { @@ -2443,7 +2530,7 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, unsigned int set, clear, val; if (tty->ops->tiocmset == NULL) - return -EINVAL; + return -ENOTTY; retval = get_user(val, p); if (retval) @@ -2466,40 +2553,66 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, return tty->ops->tiocmset(tty, set, clear); } +/** + * tty_get_icount - get tty statistics + * @tty: tty device + * @icount: output parameter + * + * Gets a copy of the @tty's icount statistics. + * + * Locking: none (up to the driver) + */ +int tty_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + memset(icount, 0, sizeof(*icount)); + + if (tty->ops->get_icount) + return tty->ops->get_icount(tty, icount); + else + return -ENOTTY; +} +EXPORT_SYMBOL_GPL(tty_get_icount); + static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) { - int retval = -EINVAL; struct serial_icounter_struct icount; - memset(&icount, 0, sizeof(icount)); - if (tty->ops->get_icount) - retval = tty->ops->get_icount(tty, &icount); + int retval; + + retval = tty_get_icount(tty, &icount); if (retval != 0) return retval; + if (copy_to_user(arg, &icount, sizeof(icount))) return -EFAULT; return 0; } -static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) +static int tty_set_serial(struct tty_struct *tty, struct serial_struct *ss) { - static DEFINE_RATELIMIT_STATE(depr_flags, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); char comm[TASK_COMM_LEN]; - struct serial_struct v; int flags; - if (copy_from_user(&v, ss, sizeof(struct serial_struct))) - return -EFAULT; + flags = ss->flags & ASYNC_DEPRECATED; - flags = v.flags & ASYNC_DEPRECATED; + if (flags) + pr_warn_ratelimited("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", + __func__, get_task_comm(comm, current), flags); - if (flags && __ratelimit(&depr_flags)) - pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", - __func__, get_task_comm(comm, current), flags); if (!tty->ops->set_serial) return -ENOTTY; - return tty->ops->set_serial(tty, &v); + + return tty->ops->set_serial(tty, ss); +} + +static int tty_tiocsserial(struct tty_struct *tty, struct serial_struct __user *ss) +{ + struct serial_struct v; + + if (copy_from_user(&v, ss, sizeof(*ss))) + return -EFAULT; + + return tty_set_serial(tty, &v); } static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user *ss) @@ -2507,11 +2620,11 @@ static int tty_tiocgserial(struct tty_struct *tty, struct serial_struct __user * struct serial_struct v; int err; - memset(&v, 0, sizeof(struct serial_struct)); + memset(&v, 0, sizeof(v)); if (!tty->ops->get_serial) return -ENOTTY; err = tty->ops->get_serial(tty, &v); - if (!err && copy_to_user(ss, &v, sizeof(struct serial_struct))) + if (!err && copy_to_user(ss, &v, sizeof(v))) err = -EFAULT; return err; } @@ -2585,6 +2698,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGEXCL: { int excl = test_bit(TTY_EXCLUSIVE, &tty->flags); + return put_user(excl, (int __user *)p); } case TIOCGETD: @@ -2599,6 +2713,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGDEV: { unsigned int ret = new_encode_dev(tty_devnum(real_tty)); + return put_user(ret, (unsigned int __user *)p); } /* @@ -2662,7 +2777,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return hung_up_tty_ioctl(file, cmd, arg); retval = -EINVAL; if (ld->ops->ioctl) { - retval = ld->ops->ioctl(tty, file, cmd, arg); + retval = ld->ops->ioctl(tty, cmd, arg); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -2673,39 +2788,34 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) #ifdef CONFIG_COMPAT struct serial_struct32 { - compat_int_t type; - compat_int_t line; - compat_uint_t port; - compat_int_t irq; - compat_int_t flags; - compat_int_t xmit_fifo_size; - compat_int_t custom_divisor; - compat_int_t baud_base; - unsigned short close_delay; - char io_type; - char reserved_char[1]; - compat_int_t hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - compat_uint_t iomem_base; - unsigned short iomem_reg_shift; - unsigned int port_high; - /* compat_ulong_t iomap_base FIXME */ - compat_int_t reserved[1]; + compat_int_t type; + compat_int_t line; + compat_uint_t port; + compat_int_t irq; + compat_int_t flags; + compat_int_t xmit_fifo_size; + compat_int_t custom_divisor; + compat_int_t baud_base; + unsigned short close_delay; + char io_type; + char reserved_char; + compat_int_t hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + compat_uint_t iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + /* compat_ulong_t iomap_base FIXME */ + compat_int_t reserved; }; static int compat_tty_tiocsserial(struct tty_struct *tty, struct serial_struct32 __user *ss) { - static DEFINE_RATELIMIT_STATE(depr_flags, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - char comm[TASK_COMM_LEN]; struct serial_struct32 v32; struct serial_struct v; - int flags; - if (copy_from_user(&v32, ss, sizeof(struct serial_struct32))) + if (copy_from_user(&v32, ss, sizeof(*ss))) return -EFAULT; memcpy(&v, &v32, offsetof(struct serial_struct32, iomem_base)); @@ -2714,14 +2824,7 @@ static int compat_tty_tiocsserial(struct tty_struct *tty, v.port_high = v32.port_high; v.iomap_base = 0; - flags = v.flags & ASYNC_DEPRECATED; - - if (flags && __ratelimit(&depr_flags)) - pr_warn("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", - __func__, get_task_comm(comm, current), flags); - if (!tty->ops->set_serial) - return -ENOTTY; - return tty->ops->set_serial(tty, &v); + return tty_set_serial(tty, &v); } static int compat_tty_tiocgserial(struct tty_struct *tty, @@ -2743,7 +2846,7 @@ static int compat_tty_tiocgserial(struct tty_struct *tty, 0xfffffff : ptr_to_compat(v.iomem_base); v32.iomem_reg_shift = v.iomem_reg_shift; v32.port_high = v.port_high; - if (copy_to_user(ss, &v32, sizeof(struct serial_struct32))) + if (copy_to_user(ss, &v32, sizeof(v32))) err = -EFAULT; } return err; @@ -2853,10 +2956,10 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, if (!ld) return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) - retval = ld->ops->compat_ioctl(tty, file, cmd, arg); + retval = ld->ops->compat_ioctl(tty, cmd, arg); if (retval == -ENOIOCTLCMD && ld->ops->ioctl) - retval = ld->ops->ioctl(tty, file, - (unsigned long)compat_ptr(cmd), arg); + retval = ld->ops->ioctl(tty, (unsigned long)compat_ptr(cmd), + arg); tty_ldisc_deref(ld); return retval; @@ -2865,11 +2968,11 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, static int this_tty(const void *t, struct file *file, unsigned fd) { - if (likely(file->f_op->read != tty_read)) + if (likely(file->f_op->read_iter != tty_read)) return 0; return file_tty(file) != t ? 0 : fd + 1; } - + /* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this @@ -2891,16 +2994,14 @@ static int this_tty(const void *t, struct file *file, unsigned fd) */ void __do_SAK(struct tty_struct *tty) { -#ifdef TTY_SOFT_SAK - tty_hangup(tty); -#else struct task_struct *g, *p; struct pid *session; - int i; + int i; + unsigned long flags; - if (!tty) - return; - session = tty->session; + spin_lock_irqsave(&tty->ctrl.lock, flags); + session = get_pid(tty->ctrl.session); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); tty_ldisc_flush(tty); @@ -2919,7 +3020,8 @@ void __do_SAK(struct tty_struct *tty) if (p->signal->tty == tty) { tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n", task_pid_nr(p), p->comm); - group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, + PIDTYPE_SID); continue; } task_lock(p); @@ -2927,12 +3029,13 @@ void __do_SAK(struct tty_struct *tty) if (i != 0) { tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n", task_pid_nr(p), p->comm, i - 1); - group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, + PIDTYPE_SID); } task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); -#endif + put_pid(session); } static void do_SAK_work(struct work_struct *work) @@ -2954,41 +3057,41 @@ void do_SAK(struct tty_struct *tty) return; schedule_work(&tty->SAK_work); } - EXPORT_SYMBOL(do_SAK); /* Must put_device() after it's unused! */ static struct device *tty_get_device(struct tty_struct *tty) { dev_t devt = tty_devnum(tty); + return class_find_device_by_devt(tty_class, devt); } /** - * alloc_tty_struct + * alloc_tty_struct - allocate a new tty + * @driver: driver which will handle the returned tty + * @idx: minor of the tty * - * This subroutine allocates and initializes a tty structure. + * This subroutine allocates and initializes a tty structure. * - * Locking: none - tty in question is not exposed at this point + * Locking: none - @tty in question is not exposed at this point */ - struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) { struct tty_struct *tty; - tty = kzalloc(sizeof(*tty), GFP_KERNEL); + tty = kzalloc(sizeof(*tty), GFP_KERNEL_ACCOUNT); if (!tty) return NULL; kref_init(&tty->kref); - tty->magic = TTY_MAGIC; if (tty_ldisc_init(tty)) { kfree(tty); return NULL; } - tty->session = NULL; - tty->pgrp = NULL; + tty->ctrl.session = NULL; + tty->ctrl.pgrp = NULL; mutex_init(&tty->legacy_mutex); mutex_init(&tty->throttle_mutex); init_rwsem(&tty->termios_rwsem); @@ -2998,8 +3101,8 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_write_lock); - spin_lock_init(&tty->ctrl_lock); - spin_lock_init(&tty->flow_lock); + spin_lock_init(&tty->ctrl.lock); + spin_lock_init(&tty->flow.lock); spin_lock_init(&tty->files_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); @@ -3014,17 +3117,18 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) } /** - * tty_put_char - write one character to a tty - * @tty: tty - * @ch: character + * tty_put_char - write one character to a tty + * @tty: tty + * @ch: character to write * - * Write one byte to the tty using the provided put_char method - * if present. Returns the number of characters successfully output. + * Write one byte to the @tty using the provided @tty->ops->put_char() method + * if present. * - * Note: the specific put_char operation in the driver layer may go - * away soon. Don't call it directly, use this method + * Note: the specific put_char operation in the driver layer may go + * away soon. Don't call it directly, use this method + * + * Return: the number of characters successfully output. */ - int tty_put_char(struct tty_struct *tty, unsigned char ch) { if (tty->ops->put_char) @@ -3053,24 +3157,23 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, } /** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the %TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. + * Locking: ?? * - * Locking: ?? + * Return: A pointer to the struct device for this tty device (or + * ERR_PTR(-EFOO) on error). */ - struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { @@ -3085,24 +3188,23 @@ static void tty_device_create_release(struct device *dev) } /** - * tty_register_device_attr - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. - * @drvdata: Driver data to be set to device. - * @attr_grp: Attribute group to be set on device. + * tty_register_device_attr - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to %NULL safely. + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). + * This call is required to be made to register an individual tty device if the + * tty driver's flags have the %TTY_DRIVER_DYNAMIC_DEV bit set. If that bit is + * not set, this function should not be called by a tty driver. * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. + * Locking: ?? * - * Locking: ?? + * Return: A pointer to the struct device for this tty device (or + * ERR_PTR(-EFOO) on error). */ struct device *tty_register_device_attr(struct tty_driver *driver, unsigned index, struct device *device, @@ -3175,16 +3277,15 @@ err_put: EXPORT_SYMBOL_GPL(tty_register_device_attr); /** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device * - * If a tty device is registered with a call to tty_register_device() then - * this function must be called when the tty device is gone. + * If a tty device is registered with a call to tty_register_device() then + * this function must be called when the tty device is gone. * - * Locking: ?? + * Locking: ?? */ - void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, @@ -3200,10 +3301,10 @@ EXPORT_SYMBOL(tty_unregister_device); * __tty_alloc_driver -- allocate tty driver * @lines: count of lines this driver can handle at most * @owner: module which is responsible for this driver - * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags + * @flags: some of %TTY_DRIVER_ flags, will be set in driver->flags * * This should not be called directly, some of the provided macros should be - * used instead. Use IS_ERR and friends on @retval. + * used instead. Use IS_ERR() and friends on @retval. */ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, unsigned long flags) @@ -3215,12 +3316,11 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) return ERR_PTR(-EINVAL); - driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); + driver = kzalloc(sizeof(*driver), GFP_KERNEL); if (!driver) return ERR_PTR(-ENOMEM); kref_init(&driver->kref); - driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; driver->owner = owner; driver->flags = flags; @@ -3290,26 +3390,22 @@ static void destruct_tty_driver(struct kref *kref) kfree(driver); } +/** + * tty_driver_kref_put -- drop a reference to a tty driver + * @driver: driver of which to drop the reference + * + * The final put will destroy and free up the driver. + */ void tty_driver_kref_put(struct tty_driver *driver) { kref_put(&driver->kref, destruct_tty_driver); } EXPORT_SYMBOL(tty_driver_kref_put); -void tty_set_operations(struct tty_driver *driver, - const struct tty_operations *op) -{ - driver->ops = op; -}; -EXPORT_SYMBOL(tty_set_operations); - -void put_tty_driver(struct tty_driver *d) -{ - tty_driver_kref_put(d); -} -EXPORT_SYMBOL(put_tty_driver); - -/* +/** + * tty_register_driver -- register a tty driver + * @driver: driver to register + * * Called by a tty driver to register itself. */ int tty_register_driver(struct tty_driver *driver) @@ -3371,24 +3467,20 @@ err: } EXPORT_SYMBOL(tty_register_driver); -/* +/** + * tty_unregister_driver -- unregister a tty driver + * @driver: driver to unregister + * * Called by a tty driver to unregister itself. */ -int tty_unregister_driver(struct tty_driver *driver) +void tty_unregister_driver(struct tty_driver *driver) { -#if 0 - /* FIXME */ - if (driver->refcount) - return -EBUSY; -#endif unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); - return 0; } - EXPORT_SYMBOL(tty_unregister_driver); dev_t tty_devnum(struct tty_struct *tty) |