diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 10:25:51 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-02 10:26:01 -0800 |
commit | d2fde28ce793c09c1ea36d981cb6765174fd1eea (patch) | |
tree | d1922f6572702374900dace5dcbb9d794fecc522 | |
parent | 609e5b71d0eca163df017ecfcf917b149875e744 (diff) | |
parent | e65f0f8271b1b0452334e5da37fd35413a000de4 (diff) |
Merge branch 'tty-updates' from Alan
* tty-updates: (75 commits)
serial_8250: support for Sealevel Systems Model 7803 COMM+8
hso maintainers update patch
hso modem detect fix patch against Alan Cox'es tty tree
tty: Fix an ircomm warning and note another bug
drivers/char/cyclades.c: cy_pci_probe: fix error path
Serial: UART driver changes for Cavium OCTEON.
Serial: Allow port type to be specified when calling serial8250_register_port.
8250: Serial driver changes to support future Cavium OCTEON serial patches.
8250: Don't clobber spinlocks.
fix for tty-serial-move-port
tty: We want the port object to be persistent
__FUNCTION__ is gcc-specific, use __func__
serial: RS485 ioctl structure uses __u32 include linux/types.h
tty: Drop the lock_kernel in the private ioctl hook
synclink_cs: Convert to tty_port
tty: use port methods for the rocket driver
tty: kref the rocket driver
tty: make rocketport use standard port->flags
tty: Redo the rocket driver locking
tty: Make epca use the port helpers
...
64 files changed, 3538 insertions, 2604 deletions
diff --git a/Documentation/filesystems/devpts.txt b/Documentation/filesystems/devpts.txt new file mode 100644 index 00000000000..68dffd87f9b --- /dev/null +++ b/Documentation/filesystems/devpts.txt @@ -0,0 +1,132 @@ + +To support containers, we now allow multiple instances of devpts filesystem, +such that indices of ptys allocated in one instance are independent of indices +allocated in other instances of devpts. + +To preserve backward compatibility, this support for multiple instances is +enabled only if: + + - CONFIG_DEVPTS_MULTIPLE_INSTANCES=y, and + - '-o newinstance' mount option is specified while mounting devpts + +IOW, devpts now supports both single-instance and multi-instance semantics. + +If CONFIG_DEVPTS_MULTIPLE_INSTANCES=n, there is no change in behavior and +this referred to as the "legacy" mode. In this mode, the new mount options +(-o newinstance and -o ptmxmode) will be ignored with a 'bogus option' message +on console. + +If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and devpts is mounted without the +'newinstance' option (as in current start-up scripts) the new mount binds +to the initial kernel mount of devpts. This mode is referred to as the +'single-instance' mode and the current, single-instance semantics are +preserved, i.e PTYs are common across the system. + +The only difference between this single-instance mode and the legacy mode +is the presence of new, '/dev/pts/ptmx' node with permissions 0000, which +can safely be ignored. + +If CONFIG_DEVPTS_MULTIPLE_INSTANCES=y and 'newinstance' option is specified, +the mount is considered to be in the multi-instance mode and a new instance +of the devpts fs is created. Any ptys created in this instance are independent +of ptys in other instances of devpts. Like in the single-instance mode, the +/dev/pts/ptmx node is present. To effectively use the multi-instance mode, +open of /dev/ptmx must be a redirected to '/dev/pts/ptmx' using a symlink or +bind-mount. + +Eg: A container startup script could do the following: + + $ chmod 0666 /dev/pts/ptmx + $ rm /dev/ptmx + $ ln -s pts/ptmx /dev/ptmx + $ ns_exec -cm /bin/bash + + # We are now in new container + + $ umount /dev/pts + $ mount -t devpts -o newinstance lxcpts /dev/pts + $ sshd -p 1234 + +where 'ns_exec -cm /bin/bash' calls clone() with CLONE_NEWNS flag and execs +/bin/bash in the child process. A pty created by the sshd is not visible in +the original mount of /dev/pts. + +User-space changes +------------------ + +In multi-instance mode (i.e '-o newinstance' mount option is specified at least +once), following user-space issues should be noted. + +1. If -o newinstance mount option is never used, /dev/pts/ptmx can be ignored + and no change is needed to system-startup scripts. + +2. To effectively use multi-instance mode (i.e -o newinstance is specified) + administrators or startup scripts should "redirect" open of /dev/ptmx to + /dev/pts/ptmx using either a bind mount or symlink. + + $ mount -t devpts -o newinstance devpts /dev/pts + + followed by either + + $ rm /dev/ptmx + $ ln -s pts/ptmx /dev/ptmx + $ chmod 666 /dev/pts/ptmx + or + $ mount -o bind /dev/pts/ptmx /dev/ptmx + +3. The '/dev/ptmx -> pts/ptmx' symlink is the preferred method since it + enables better error-reporting and treats both single-instance and + multi-instance mounts similarly. + + But this method requires that system-startup scripts set the mode of + /dev/pts/ptmx correctly (default mode is 0000). The scripts can set the + mode by, either + + - adding ptmxmode mount option to devpts entry in /etc/fstab, or + - using 'chmod 0666 /dev/pts/ptmx' + +4. If multi-instance mode mount is needed for containers, but the system + startup scripts have not yet been updated, container-startup scripts + should bind mount /dev/ptmx to /dev/pts/ptmx to avoid breaking single- + instance mounts. + + Or, in general, container-startup scripts should use: + + mount -t devpts -o newinstance -o ptmxmode=0666 devpts /dev/pts + if [ ! -L /dev/ptmx ]; then + mount -o bind /dev/pts/ptmx /dev/ptmx + fi + + When all devpts mounts are multi-instance, /dev/ptmx can permanently be + a symlink to pts/ptmx and the bind mount can be ignored. + +5. A multi-instance mount that is not accompanied by the /dev/ptmx to + /dev/pts/ptmx redirection would result in an unusable/unreachable pty. + + mount -t devpts -o newinstance lxcpts /dev/pts + + immediately followed by: + + open("/dev/ptmx") + + would create a pty, say /dev/pts/7, in the initial kernel mount. + But /dev/pts/7 would be invisible in the new mount. + +6. The permissions for /dev/pts/ptmx node should be specified when mounting + /dev/pts, using the '-o ptmxmode=%o' mount option (default is 0000). + + mount -t devpts -o newinstance -o ptmxmode=0644 devpts /dev/pts + + The permissions can be later be changed as usual with 'chmod'. + + chmod 666 /dev/pts/ptmx + +7. A mount of devpts without the 'newinstance' option results in binding to + initial kernel mount. This behavior while preserving legacy semantics, + does not provide strict isolation in a container environment. i.e by + mounting devpts without the 'newinstance' option, a container could + get visibility into the 'host' or root container's devpts. + + To workaround this and have strict isolation, all mounts of devpts, + including the mount in the root container, should use the newinstance + option. diff --git a/MAINTAINERS b/MAINTAINERS index ceb32ee51f9..d5fc534a108 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2049,6 +2049,12 @@ M: mikulas@artax.karlin.mff.cuni.cz W: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi S: Maintained +HSO 3G Modem Driver (hso.c) +P: Denis Joseph Barrow +M: d.barow@option.com +W: http://www.pharscape.org +S: Maintained + HTCPEN TOUCHSCREEN DRIVER P: Pau Oliva Fora M: pof@eslack.org diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index c602b547cc6..1697043119b 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -190,7 +190,7 @@ config DIGIEPCA config ESPSERIAL tristate "Hayes ESP serial port support" - depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API + depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API && BROKEN help This is a driver which supports Hayes ESP serial ports. Both single port cards and multiport cards are supported. Make sure to read @@ -443,6 +443,17 @@ config UNIX98_PTYS All modern Linux systems use the Unix98 ptys. Say Y unless you're on an embedded system and want to conserve memory. +config DEVPTS_MULTIPLE_INSTANCES + bool "Support multiple instances of devpts" + depends on UNIX98_PTYS + default n + ---help--- + Enable support for multiple instances of devpts filesystem. + If you want to have isolated PTY namespaces (eg: in containers), + say Y here. Otherwise, say N. If enabled, each mount of devpts + filesystem with the '-o newinstance' option will create an + independent PTY namespace. + config LEGACY_PTYS bool "Legacy (BSD) PTY support" default y diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index b97aebd7aeb..4e0cfdeab14 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -170,7 +170,7 @@ static __inline__ void rtsdtr_ctrl(int bits) */ static void rs_stop(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_stop")) @@ -190,7 +190,7 @@ static void rs_stop(struct tty_struct *tty) static void rs_start(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_start")) @@ -861,7 +861,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) static void rs_flush_chars(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) @@ -934,7 +934,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count static int rs_write_room(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; @@ -943,7 +943,7 @@ static int rs_write_room(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) return 0; @@ -952,7 +952,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) @@ -969,7 +969,7 @@ static void rs_flush_buffer(struct tty_struct *tty) */ static void rs_send_xchar(struct tty_struct *tty, char ch) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_send_char")) @@ -1004,7 +1004,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) */ static void rs_throttle(struct tty_struct * tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1029,7 +1029,7 @@ static void rs_throttle(struct tty_struct * tty) static void rs_unthrottle(struct tty_struct * tty) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1194,7 +1194,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value) static int rs_tiocmget(struct tty_struct *tty, struct file *file) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; unsigned char control, status; unsigned long flags; @@ -1217,7 +1217,7 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file) static int rs_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) @@ -1244,7 +1244,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, */ static int rs_break(struct tty_struct *tty, int break_state) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_break")) @@ -1264,7 +1264,7 @@ static int rs_break(struct tty_struct *tty, int break_state) static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct icount; void __user *argp = (void __user *)arg; @@ -1368,7 +1368,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info = tty->driver_data; unsigned long flags; unsigned int cflag = tty->termios->c_cflag; @@ -1428,7 +1428,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) */ static void rs_close(struct tty_struct *tty, struct file * filp) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; struct serial_state *state; unsigned long flags; @@ -1523,7 +1523,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) */ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; unsigned long orig_jiffies, char_time; int lsr; @@ -1587,7 +1587,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) */ static void rs_hangup(struct tty_struct *tty) { - struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_struct * info = tty->driver_data; struct serial_state *state = info->state; if (serial_paranoia_check(info, tty->name, "rs_hangup")) diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 5e5b1dc1a0a..6a59f72a9c2 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -5010,7 +5010,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, if (nchan == 0) { dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " "Serial-Modules\n"); - return -EIO; + goto err_unmap; } } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { struct RUNTIME_9060 __iomem *ctl_addr; diff --git a/drivers/char/epca.c b/drivers/char/epca.c index cf2461d34e5..39ad820b235 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -69,7 +69,9 @@ static int invalid_lilo_config; /* * The ISA boards do window flipping into the same spaces so its only sane with - * a single lock. It's still pretty efficient. + * a single lock. It's still pretty efficient. This lock guards the hardware + * and the tty_port lock guards the kernel side stuff like use counts. Take + * this lock inside the port lock if you must take both. */ static DEFINE_SPINLOCK(epca_lock); @@ -156,14 +158,12 @@ static struct channel *verifyChannel(struct tty_struct *); static void pc_sched_event(struct channel *, int); static void epca_error(int, char *); static void pc_close(struct tty_struct *, struct file *); -static void shutdown(struct channel *); +static void shutdown(struct channel *, struct tty_struct *tty); static void pc_hangup(struct tty_struct *); static int pc_write_room(struct tty_struct *); static int pc_chars_in_buffer(struct tty_struct *); static void pc_flush_buffer(struct tty_struct *); static void pc_flush_chars(struct tty_struct *); -static int block_til_ready(struct tty_struct *, struct file *, - struct channel *); static int pc_open(struct tty_struct *, struct file *); static void post_fep_init(unsigned int crd); static void epcapoll(unsigned long); @@ -173,7 +173,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned); static unsigned termios2digi_i(struct channel *ch, unsigned); static unsigned termios2digi_c(struct channel *ch, unsigned); static void epcaparam(struct tty_struct *, struct channel *); -static void receive_data(struct channel *); +static void receive_data(struct channel *, struct tty_struct *tty); static int pc_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static int info_ioctl(struct tty_struct *, struct file *, @@ -392,7 +392,7 @@ static struct channel *verifyChannel(struct tty_struct *tty) * through tty->driver_data this should catch it. */ if (tty) { - struct channel *ch = (struct channel *)tty->driver_data; + struct channel *ch = tty->driver_data; if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) { if (ch->magic == EPCA_MAGIC) return ch; @@ -419,76 +419,34 @@ static void epca_error(int line, char *msg) static void pc_close(struct tty_struct *tty, struct file *filp) { struct channel *ch; - unsigned long flags; + struct tty_port *port; /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ ch = verifyChannel(tty); - if (ch != NULL) { - spin_lock_irqsave(&epca_lock, flags); - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&epca_lock, flags); - return; - } - if (ch->port.count-- > 1) { - /* Begin channel is open more than once */ - /* - * Return without doing anything. Someone might still - * be using the channel. - */ - spin_unlock_irqrestore(&epca_lock, flags); - return; - } - /* Port open only once go ahead with shutdown & reset */ - BUG_ON(ch->port.count < 0); - - /* - * Let the rest of the driver know the channel is being closed. - * This becomes important if an open is attempted before close - * is finished. - */ - ch->port.flags |= ASYNC_CLOSING; - tty->closing = 1; - - spin_unlock_irqrestore(&epca_lock, flags); - - if (ch->port.flags & ASYNC_INITIALIZED) { - /* Setup an event to indicate when the - transmit buffer empties */ - setup_empty_event(tty, ch); - /* 30 seconds timeout */ - tty_wait_until_sent(tty, 3000); - } - pc_flush_buffer(tty); + if (ch == NULL) + return; + port = &ch->port; - tty_ldisc_flush(tty); - shutdown(ch); + if (tty_port_close_start(port, tty, filp) == 0) + return; - spin_lock_irqsave(&epca_lock, flags); - tty->closing = 0; - ch->event = 0; - ch->port.tty = NULL; - spin_unlock_irqrestore(&epca_lock, flags); + pc_flush_buffer(tty); + shutdown(ch, tty); - if (ch->port.blocked_open) { - if (ch->close_delay) - msleep_interruptible(jiffies_to_msecs(ch->close_delay)); - wake_up_interruptible(&ch->port.open_wait); - } - ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | - ASYNC_CLOSING); - wake_up_interruptible(&ch->port.close_wait); - } + tty_port_close_end(port, tty); + ch->event = 0; /* FIXME: review ch->event locking */ + tty_port_tty_set(port, NULL); } -static void shutdown(struct channel *ch) +static void shutdown(struct channel *ch, struct tty_struct *tty) { unsigned long flags; - struct tty_struct *tty; struct board_chan __iomem *bc; + struct tty_port *port = &ch->port; - if (!(ch->port.flags & ASYNC_INITIALIZED)) + if (!(port->flags & ASYNC_INITIALIZED)) return; spin_lock_irqsave(&epca_lock, flags); @@ -503,7 +461,6 @@ static void shutdown(struct channel *ch) */ if (bc) writeb(0, &bc->idata); - tty = ch->port.tty; /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */ if (tty->termios->c_cflag & HUPCL) { @@ -517,32 +474,26 @@ static void shutdown(struct channel *ch) * will have to reinitialized. Set a flag to indicate this. */ /* Prevent future Digi programmed interrupts from coming active */ - ch->port.flags &= ~ASYNC_INITIALIZED; + port->flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&epca_lock, flags); } static void pc_hangup(struct tty_struct *tty) { struct channel *ch; + /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ ch = verifyChannel(tty); if |