Commit be1bc288 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Greg Kroah-Hartman

tty: introduce wait_event_interruptible_tty

Calling wait_event_interruptible implicitly
releases the BKL when it sleeps, but we need
to do this explcitly when we have converted
it to a mutex.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 4e608671
...@@ -1607,7 +1607,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) ...@@ -1607,7 +1607,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now * If the port is the middle of closing, bail out now
*/ */
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
wait_event_interruptible(info->port.close_wait, wait_event_interruptible_tty(info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING)); !(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
} }
......
...@@ -954,7 +954,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l ...@@ -954,7 +954,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l
* order of opens and closes may not be preserved across shared * order of opens and closes may not be preserved across shared
* memory, so we must wait until it is complete. * memory, so we must wait until it is complete.
*/ */
wait_event_interruptible(portp->raw_wait, wait_event_interruptible_tty(portp->raw_wait,
!test_bit(ST_CLOSING, &portp->state)); !test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current)) { if (signal_pending(current)) {
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l ...@@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l
set_bit(ST_OPENING, &portp->state); set_bit(ST_OPENING, &portp->state);
spin_unlock_irqrestore(&brd_lock, flags); spin_unlock_irqrestore(&brd_lock, flags);
wait_event_interruptible(portp->raw_wait, wait_event_interruptible_tty(portp->raw_wait,
!test_bit(ST_OPENING, &portp->state)); !test_bit(ST_OPENING, &portp->state));
if (signal_pending(current)) if (signal_pending(current))
rc = -ERESTARTSYS; rc = -ERESTARTSYS;
...@@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned ...@@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
* occurs on this port. * occurs on this port.
*/ */
if (wait) { if (wait) {
wait_event_interruptible(portp->raw_wait, wait_event_interruptible_tty(portp->raw_wait,
!test_bit(ST_CLOSING, &portp->state)); !test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current)) { if (signal_pending(current)) {
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned ...@@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
* to come back. * to come back.
*/ */
rc = 0; rc = 0;
wait_event_interruptible(portp->raw_wait, wait_event_interruptible_tty(portp->raw_wait,
!test_bit(ST_CLOSING, &portp->state)); !test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current)) if (signal_pending(current))
rc = -ERESTARTSYS; rc = -ERESTARTSYS;
...@@ -1073,6 +1073,10 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned ...@@ -1073,6 +1073,10 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback) static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
{ {
/*
* no need for wait_event_tty because clearing ST_CMDING cannot block
* on BTM
*/
wait_event_interruptible(portp->raw_wait, wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CMDING, &portp->state)); !test_bit(ST_CMDING, &portp->state));
if (signal_pending(current)) if (signal_pending(current))
......
...@@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, ...@@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock; goto unlock;
} }
/* block until there is a message: */ /* block until there is a message: */
wait_event_interruptible(pInfo->read_wait, wait_event_interruptible_tty(pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient))); (pMsg = remove_msg(pInfo, pClient)));
} }
......
...@@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_port *port, ...@@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */ /* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
wait_event_interruptible(port->close_wait, wait_event_interruptible_tty(port->close_wait,
!(port->flags & ASYNC_CLOSING)); !(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY) if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN; return -EAGAIN;
......
...@@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_event_wait *vw) ...@@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
list_add(&vw->list, &vt_events); list_add(&vw->list, &vt_events);
spin_unlock_irqrestore(&vt_event_lock, flags); spin_unlock_irqrestore(&vt_event_lock, flags);
/* Wait for it to pass */ /* Wait for it to pass */
wait_event_interruptible(vt_event_waitqueue, vw->done); wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
/* Dequeue it */ /* Dequeue it */
spin_lock_irqsave(&vt_event_lock, flags); spin_lock_irqsave(&vt_event_lock, flags);
list_del(&vw->list); list_del(&vw->list);
...@@ -1761,10 +1761,13 @@ int vt_move_to_console(unsigned int vt, int alloc) ...@@ -1761,10 +1761,13 @@ int vt_move_to_console(unsigned int vt, int alloc)
return -EIO; return -EIO;
} }
release_console_sem(); release_console_sem();
tty_lock();
if (vt_waitactive(vt + 1)) { if (vt_waitactive(vt + 1)) {
pr_debug("Suspend: Can't switch VCs."); pr_debug("Suspend: Can't switch VCs.");
tty_unlock();
return -EINTR; return -EINTR;
} }
tty_unlock();
return prev; return prev;
} }
......
...@@ -3992,7 +3992,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -3992,7 +3992,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/ */
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) { (info->flags & ASYNC_CLOSING)) {
wait_event_interruptible(info->close_wait, wait_event_interruptible_tty(info->close_wait,
!(info->flags & ASYNC_CLOSING)); !(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY) if (info->flags & ASYNC_HUP_NOTIFY)
...@@ -4150,7 +4150,7 @@ rs_open(struct tty_struct *tty, struct file * filp) ...@@ -4150,7 +4150,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
*/ */
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) { (info->flags & ASYNC_CLOSING)) {
wait_event_interruptible(info->close_wait, wait_event_interruptible_tty(info->close_wait,
!(info->flags & ASYNC_CLOSING)); !(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART #ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ? return ((info->flags & ASYNC_HUP_NOTIFY) ?
......
...@@ -607,5 +607,47 @@ static inline void tty_unlock(void) __releases(kernel_lock) ...@@ -607,5 +607,47 @@ static inline void tty_unlock(void) __releases(kernel_lock)
} }
#define tty_locked() (kernel_locked()) #define tty_locked() (kernel_locked())
/*
* wait_event_interruptible_tty -- wait for a condition with the tty lock held
*
* The condition we are waiting for might take a long time to
* become true, or might depend on another thread taking the
* BTM. In either case, we need to drop the BTM to guarantee
* forward progress. This is a leftover from the conversion
* from the BKL and should eventually get removed as the BTM
* falls out of use.
*
* Do not use in new code.
*/
#define wait_event_interruptible_tty(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) { \
__wait_event_interruptible_tty(wq, condition, __ret); \
} \
__ret; \
})
#define __wait_event_interruptible_tty(wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
tty_unlock(); \
schedule(); \
tty_lock(); \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment