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: Arnd Bergmann <arnd@arndb.de> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
4e60867167
Коммит
be1bc2889a
|
@ -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 (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));
|
||||
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
|
|||
* order of opens and closes may not be preserved across shared
|
||||
* 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));
|
||||
if (signal_pending(current)) {
|
||||
return -ERESTARTSYS;
|
||||
|
@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l
|
|||
set_bit(ST_OPENING, &portp->state);
|
||||
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));
|
||||
if (signal_pending(current))
|
||||
rc = -ERESTARTSYS;
|
||||
|
@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
|
|||
* occurs on this port.
|
||||
*/
|
||||
if (wait) {
|
||||
wait_event_interruptible(portp->raw_wait,
|
||||
wait_event_interruptible_tty(portp->raw_wait,
|
||||
!test_bit(ST_CLOSING, &portp->state));
|
||||
if (signal_pending(current)) {
|
||||
return -ERESTARTSYS;
|
||||
|
@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
|
|||
* to come back.
|
||||
*/
|
||||
rc = 0;
|
||||
wait_event_interruptible(portp->raw_wait,
|
||||
wait_event_interruptible_tty(portp->raw_wait,
|
||||
!test_bit(ST_CLOSING, &portp->state));
|
||||
if (signal_pending(current))
|
||||
rc = -ERESTARTSYS;
|
||||
|
@ -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)
|
||||
{
|
||||
/*
|
||||
* no need for wait_event_tty because clearing ST_CMDING cannot block
|
||||
* on BTM
|
||||
*/
|
||||
wait_event_interruptible(portp->raw_wait,
|
||||
!test_bit(ST_CMDING, &portp->state));
|
||||
if (signal_pending(current))
|
||||
|
|
|
@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
|||
goto unlock;
|
||||
}
|
||||
/* block until there is a message: */
|
||||
wait_event_interruptible(pInfo->read_wait,
|
||||
wait_event_interruptible_tty(pInfo->read_wait,
|
||||
(pMsg = remove_msg(pInfo, pClient)));
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
|
||||
/* block if port is in the process of being closed */
|
||||
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));
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
|
|
|
@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
|
|||
list_add(&vw->list, &vt_events);
|
||||
spin_unlock_irqrestore(&vt_event_lock, flags);
|
||||
/* Wait for it to pass */
|
||||
wait_event_interruptible(vt_event_waitqueue, vw->done);
|
||||
wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
|
||||
/* Dequeue it */
|
||||
spin_lock_irqsave(&vt_event_lock, flags);
|
||||
list_del(&vw->list);
|
||||
|
@ -1761,10 +1761,13 @@ int vt_move_to_console(unsigned int vt, int alloc)
|
|||
return -EIO;
|
||||
}
|
||||
release_console_sem();
|
||||
tty_lock();
|
||||
if (vt_waitactive(vt + 1)) {
|
||||
pr_debug("Suspend: Can't switch VCs.");
|
||||
tty_unlock();
|
||||
return -EINTR;
|
||||
}
|
||||
tty_unlock();
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
|
|
@ -3992,7 +3992,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible(info->close_wait,
|
||||
wait_event_interruptible_tty(info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
|
@ -4150,7 +4150,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible(info->close_wait,
|
||||
wait_event_interruptible_tty(info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->flags & ASYNC_HUP_NOTIFY) ?
|
||||
|
|
|
@ -607,5 +607,47 @@ static inline void tty_unlock(void) __releases(kernel_lock)
|
|||
}
|
||||
#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
|
||||
|
|
Загрузка…
Ссылка в новой задаче