Merge branch 'tty-splice' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds...
[sfrench/cifs-2.6.git] / drivers / tty / tty_io.c
index 8846d3b99845a34ced2ea303e6d5b8ff10ddbe21..c7763743a3d645836546514a21356f829bd88f30 100644 (file)
@@ -207,7 +207,7 @@ void tty_add_file(struct tty_struct *tty, struct file *file)
        spin_unlock(&tty->files_lock);
 }
 
-/**
+/*
  * tty_free_file - free file->private_data
  *
  * This shall be used only for fail path handling when tty_add_file was not
@@ -517,8 +517,6 @@ 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
@@ -545,9 +543,33 @@ void tty_wakeup(struct tty_struct *tty)
 
 EXPORT_SYMBOL_GPL(tty_wakeup);
 
+/**
+ *     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.  It returns the
+ *     filp for the redirect, which must be fput when the operations on
+ *     the tty are completed.
+ */
+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
@@ -570,7 +592,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
 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;
@@ -578,13 +600,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);
 
@@ -1129,7 +1145,7 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
        return tty_write(iocb, iter);
 }
 
-/**
+/*
  *     tty_send_xchar  -       send priority character
  *
  *     Send a high priority character to the tty even if stopped
@@ -1207,6 +1223,7 @@ 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
+ *     @file:   file object
  *     @idx:    the minor number
  *
  *     Return the tty, if found. If not found, return NULL or ERR_PTR() if the
@@ -1558,6 +1575,8 @@ EXPORT_SYMBOL(tty_kref_put);
 
 /**
  *     release_tty             -       release tty structure memory
+ *     @tty: tty device release
+ *     @idx: index of the tty device release
  *
  *     Release both @tty and a possible linked partner (think pty pair),
  *     and decrement the refcount of the backing module.
@@ -1935,22 +1954,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;
@@ -1965,7 +1969,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) {
@@ -1983,7 +1987,42 @@ out:
        tty_driver_kref_put(driver);
        return tty;
 }
-EXPORT_SYMBOL_GPL(tty_kopen);
+
+/**
+ *     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.
+ *
+ *     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_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
+ *
+ *     Opens an already existing tty for in-kernel use. Compared to
+ *     tty_kopen_exclusive() above it doesn't ensure to be the only user.
+ *
+ *     Locking is 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
@@ -2528,15 +2567,36 @@ 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 -EINVAL;
+}
+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;
@@ -3032,7 +3092,7 @@ static struct device *tty_get_device(struct tty_struct *tty)
 }
 
 
-/**
+/*
  *     alloc_tty_struct
  *
  *     This subroutine allocates and initializes a tty structure.