git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
vserver 1.9.3
[linux-2.6.git]
/
drivers
/
char
/
tty_ioctl.c
diff --git
a/drivers/char/tty_ioctl.c
b/drivers/char/tty_ioctl.c
index
ae924c7
..
830c665
100644
(file)
--- a/
drivers/char/tty_ioctl.c
+++ b/
drivers/char/tty_ioctl.c
@@
-98,8
+98,17
@@
static void change_termios(struct tty_struct * tty, struct termios * new_termios
{
int canon_change;
struct termios old_termios = *tty->termios;
{
int canon_change;
struct termios old_termios = *tty->termios;
+ struct tty_ldisc *ld;
+
+ /*
+ * Perform the actual termios internal changes under lock.
+ */
+
+
+ /* FIXME: we need to decide on some locking/ordering semantics
+ for the set_termios notification eventually */
+ down(&tty->termios_sem);
- local_irq_disable(); // FIXME: is this safe?
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@
-109,12
+118,13
@@
static void change_termios(struct tty_struct * tty, struct termios * new_termios
tty->canon_data = 0;
tty->erasing = 0;
}
tty->canon_data = 0;
tty->erasing = 0;
}
- local_irq_enable(); // FIXME: is this safe?
+
+
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->read_wait);
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->read_wait);
- /*
see if packet mode change of state
*/
+ /*
See if packet mode change of state.
*/
if (tty->link && tty->link->packet) {
int old_flow = ((old_termios.c_iflag & IXON) &&
if (tty->link && tty->link->packet) {
int old_flow = ((old_termios.c_iflag & IXON) &&
@@
-132,17
+142,23
@@
static void change_termios(struct tty_struct * tty, struct termios * new_termios
wake_up_interruptible(&tty->link->read_wait);
}
}
wake_up_interruptible(&tty->link->read_wait);
}
}
-
+
if (tty->driver->set_termios)
(*tty->driver->set_termios)(tty, &old_termios);
if (tty->driver->set_termios)
(*tty->driver->set_termios)(tty, &old_termios);
- if (tty->ldisc.set_termios)
- (*tty->ldisc.set_termios)(tty, &old_termios);
+ ld = tty_ldisc_ref(tty);
+ if (ld != NULL) {
+ if (ld->set_termios)
+ (ld->set_termios)(tty, &old_termios);
+ tty_ldisc_deref(ld);
+ }
+ up(&tty->termios_sem);
}
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
{
struct termios tmp_termios;
}
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
{
struct termios tmp_termios;
+ struct tty_ldisc *ld;
int retval = tty_check_change(tty);
if (retval)
int retval = tty_check_change(tty);
if (retval)
@@
-159,9
+175,14
@@
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
return -EFAULT;
}
return -EFAULT;
}
- if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
-
+ ld = tty_ldisc_ref(tty);
+
+ if (ld != NULL) {
+ if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ tty_ldisc_deref(ld);
+ }
+
if (opt & TERMIOS_WAIT) {
tty_wait_until_sent(tty, 0);
if (signal_pending(current))
if (opt & TERMIOS_WAIT) {
tty_wait_until_sent(tty, 0);
if (signal_pending(current))
@@
-226,11
+247,14
@@
static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
{
struct sgttyb tmp;
{
struct sgttyb tmp;
+ down(&tty->termios_sem);
tmp.sg_ispeed = 0;
tmp.sg_ospeed = 0;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
tmp.sg_ispeed = 0;
tmp.sg_ospeed = 0;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
+ up(&tty->termios_sem);
+
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@
-269,12
+293,16
@@
static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
retval = tty_check_change(tty);
if (retval)
return retval;
retval = tty_check_change(tty);
if (retval)
return retval;
- termios = *tty->termios;
+
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
+
+ down(&tty->termios_sem);
+ termios = *tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
+ up(&tty->termios_sem);
change_termios(tty, &termios);
return 0;
}
change_termios(tty, &termios);
return 0;
}
@@
-365,6
+393,7
@@
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
struct tty_struct * real_tty;
void __user *p = (void __user *)arg;
int retval;
struct tty_struct * real_tty;
void __user *p = (void __user *)arg;
int retval;
+ struct tty_ldisc *ld;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@
-443,22
+472,26
@@
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
retval = tty_check_change(tty);
if (retval)
return retval;
retval = tty_check_change(tty);
if (retval)
return retval;
+
+ ld = tty_ldisc_ref(tty);
switch (arg) {
case TCIFLUSH:
switch (arg) {
case TCIFLUSH:
- if (
tty->ldisc.
flush_buffer)
-
tty->ldisc.
flush_buffer(tty);
+ if (
ld->
flush_buffer)
+
ld->
flush_buffer(tty);
break;
case TCIOFLUSH:
break;
case TCIOFLUSH:
- if (
tty->ldisc.
flush_buffer)
-
tty->ldisc.
flush_buffer(tty);
+ if (
ld->
flush_buffer)
+
ld->
flush_buffer(tty);
/* fall through */
case TCOFLUSH:
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
break;
default:
/* fall through */
case TCOFLUSH:
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
break;
default:
+ tty_ldisc_deref(ld);
return -EINVAL;
}
return -EINVAL;
}
+ tty_ldisc_deref(ld);
return 0;
case TIOCOUTQ:
return put_user(tty->driver->chars_in_buffer ?
return 0;
case TIOCOUTQ:
return put_user(tty->driver->chars_in_buffer ?
@@
-504,9
+537,11
@@
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
+ down(&tty->termios_sem);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
+ up(&tty->termios_sem);
return 0;
default:
return -ENOIOCTLCMD;
return 0;
default:
return -ENOIOCTLCMD;