From aa8dbad09b5c15ffc04f96084b22a9283cf6feca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Dec 2020 16:22:44 +0100 Subject: [PATCH] UPSTREAM: um: line: Don't free winch (with IRQ) under spinlock Lockdep correctly complains that one shouldn't call um_free_irq() with free_irq() inside under a spinlock since that will attempt to acquire a mutex. Rearrange the code to keep the list manipulations under the lock while moving the actual freeing outside of it, to avoid this. In particular, this removes the lockdep complaint at shutdown that I was seeing with lockdep enabled. Bug: 176213565 Signed-off-by: Johannes Berg Acked-By: anton.ivanov@cambridgegreys.com Signed-off-by: Richard Weinberger (cherry picked from commit f4ab7818ef7add1e10b33d8c3a4fe44858b7f6e9) Signed-off-by: Greg Kroah-Hartman Change-Id: I05c323dd19cf55273fc14adc36841e41207caeb3 --- arch/um/drivers/line.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 14ad9f495fe6..77ce63a57070 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -608,7 +608,6 @@ static void free_winch(struct winch *winch) winch->fd = -1; if (fd != -1) os_close_file(fd); - list_del(&winch->list); __free_winch(&winch->work); } @@ -709,6 +708,8 @@ static void unregister_winch(struct tty_struct *tty) winch = list_entry(ele, struct winch, list); wtty = tty_port_tty_get(winch->port); if (wtty == tty) { + list_del(&winch->list); + spin_unlock(&winch_handler_lock); free_winch(winch); break; } @@ -719,14 +720,17 @@ static void unregister_winch(struct tty_struct *tty) static void winch_cleanup(void) { - struct list_head *ele, *next; struct winch *winch; spin_lock(&winch_handler_lock); + while ((winch = list_first_entry_or_null(&winch_handlers, + struct winch, list))) { + list_del(&winch->list); + spin_unlock(&winch_handler_lock); - list_for_each_safe(ele, next, &winch_handlers) { - winch = list_entry(ele, struct winch, list); free_winch(winch); + + spin_lock(&winch_handler_lock); } spin_unlock(&winch_handler_lock);