/* Insert the contents of the selection buffer into the * queue of the tty associated with the current console. * Invoked by ioctl(). */ int paste_selection(struct tty_struct *tty) { struct vt_struct *vt = (struct vt_struct *) tty->driver_data; int pasted = 0, count; struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); acquire_console_sem(); poke_blanked_console(); release_console_sem(); ld = tty_ldisc_ref_wait(tty); add_wait_queue(&vt->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); if (test_bit(TTY_THROTTLED, &tty->flags)) { schedule(); continue; } count = sel_buffer_lth - pasted; count = min(count, tty->ldisc.receive_room(tty)); tty->ldisc.receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } remove_wait_queue(&vt->paste_wait, &wait); current->state = TASK_RUNNING; tty_ldisc_deref(ld); return 0; }
int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval; struct tty_ldisc o_ldisc, new_ldisc; int work; unsigned long flags; struct tty_struct *o_tty; restart: /* This is a bit ugly for now but means we can break the 'ldisc is part of the tty struct' assumption later */ retval = tty_ldisc_get(ldisc, &new_ldisc); if (retval) return retval; /* * Problem: What do we do if this blocks ? */ tty_wait_until_sent(tty, 0); if (tty->ldisc.ops->num == ldisc) { tty_ldisc_put(new_ldisc.ops); return 0; } /* * No more input please, we are switching. The new ldisc * will update this value in the ldisc open function */ tty->receive_room = 0; o_ldisc = tty->ldisc; o_tty = tty->link; /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. * * We must clear the TTY_LDISC bit here to avoid a livelock * with a userspace app continually trying to use the tty in * parallel to the change and re-referencing the tty. */ clear_bit(TTY_LDISC, &tty->flags); if (o_tty) clear_bit(TTY_LDISC, &o_tty->flags); spin_lock_irqsave(&tty_ldisc_lock, flags); if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { if (tty->ldisc.refcount) { /* Free the new ldisc we grabbed. Must drop the lock first. */ spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(new_ldisc.ops); /* * There are several reasons we may be busy, including * random momentary I/O traffic. We must therefore * retry. We could distinguish between blocking ops * and retries if we made tty_ldisc_wait() smarter. * That is up for discussion. */ if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; } if (o_tty && o_tty->ldisc.refcount) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(o_tty->ldisc.ops); if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; } } /* * If the TTY_LDISC bit is set, then we are racing against * another ldisc change */ if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { struct tty_ldisc *ld; spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(new_ldisc.ops); ld = tty_ldisc_ref_wait(tty); tty_ldisc_deref(ld); goto restart; } /* * This flag is used to avoid two parallel ldisc changes. Once * open and close are fine grained locked this may work better * as a mutex shared with the open/close/hup paths */ set_bit(TTY_LDISC_CHANGING, &tty->flags); if (o_tty) set_bit(TTY_LDISC_CHANGING, &o_tty->flags); spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* * From this point on we know nobody has an ldisc * usage reference, nor can they obtain one until * we say so later on. */ work = cancel_delayed_work(&tty->buf.work); /* * Wait for ->hangup_work and ->buf.work handlers to terminate * MUST NOT hold locks here. */ flush_scheduled_work(); /* Shutdown the current discipline. */ if (o_ldisc.ops->close) (o_ldisc.ops->close)(tty); /* Now set up the new line discipline. */ tty_ldisc_assign(tty, &new_ldisc); tty_set_termios_ldisc(tty, ldisc); if (new_ldisc.ops->open) retval = (new_ldisc.ops->open)(tty); if (retval < 0) { tty_ldisc_put(new_ldisc.ops); tty_ldisc_restore(tty, &o_ldisc); } /* At this point we hold a reference to the new ldisc and a a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc) tty->ops->set_ldisc(tty); tty_ldisc_put(o_ldisc.ops); /* * Allow ldisc referencing to occur as soon as the driver * ldisc callback completes. */ tty_ldisc_enable(tty); if (o_tty) tty_ldisc_enable(o_tty); /* Restart it in case no characters kick it off. Safe if already running */ if (work) schedule_delayed_work(&tty->buf.work, 1); return retval; }