um: fix free_winch() mess
while not doing free_irq() from irq handler is commendable, kfree() on the data passed to said handler before free_irq() is Not Good(tm). Freeing the stack it's being run on is also not nice... Solution: delay actually freeing stuff. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
45cd5e2d4e
commit
7cf3cf21aa
@ -721,43 +721,53 @@ struct winch {
|
|||||||
int pid;
|
int pid;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
unsigned long stack;
|
unsigned long stack;
|
||||||
|
struct work_struct work;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_winch(struct winch *winch, int free_irq_ok)
|
static void __free_winch(struct work_struct *work)
|
||||||
{
|
{
|
||||||
int fd = winch->fd;
|
struct winch *winch = container_of(work, struct winch, work);
|
||||||
winch->fd = -1;
|
free_irq(WINCH_IRQ, winch);
|
||||||
if (free_irq_ok)
|
|
||||||
free_irq(WINCH_IRQ, winch);
|
|
||||||
|
|
||||||
list_del(&winch->list);
|
|
||||||
|
|
||||||
if (winch->pid != -1)
|
if (winch->pid != -1)
|
||||||
os_kill_process(winch->pid, 1);
|
os_kill_process(winch->pid, 1);
|
||||||
if (fd != -1)
|
|
||||||
os_close_file(fd);
|
|
||||||
if (winch->stack != 0)
|
if (winch->stack != 0)
|
||||||
free_stack(winch->stack, 0);
|
free_stack(winch->stack, 0);
|
||||||
kfree(winch);
|
kfree(winch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_winch(struct winch *winch)
|
||||||
|
{
|
||||||
|
int fd = winch->fd;
|
||||||
|
winch->fd = -1;
|
||||||
|
if (fd != -1)
|
||||||
|
os_close_file(fd);
|
||||||
|
list_del(&winch->list);
|
||||||
|
__free_winch(&winch->work);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t winch_interrupt(int irq, void *data)
|
static irqreturn_t winch_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct winch *winch = data;
|
struct winch *winch = data;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
struct line *line;
|
struct line *line;
|
||||||
|
int fd = winch->fd;
|
||||||
int err;
|
int err;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
if (winch->fd != -1) {
|
if (fd != -1) {
|
||||||
err = generic_read(winch->fd, &c, NULL);
|
err = generic_read(fd, &c, NULL);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (err != -EAGAIN) {
|
if (err != -EAGAIN) {
|
||||||
|
winch->fd = -1;
|
||||||
|
list_del(&winch->list);
|
||||||
|
os_close_file(fd);
|
||||||
printk(KERN_ERR "winch_interrupt : "
|
printk(KERN_ERR "winch_interrupt : "
|
||||||
"read failed, errno = %d\n", -err);
|
"read failed, errno = %d\n", -err);
|
||||||
printk(KERN_ERR "fd %d is losing SIGWINCH "
|
printk(KERN_ERR "fd %d is losing SIGWINCH "
|
||||||
"support\n", winch->tty_fd);
|
"support\n", winch->tty_fd);
|
||||||
free_winch(winch, 0);
|
INIT_WORK(&winch->work, __free_winch);
|
||||||
|
schedule_work(&winch->work);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty)
|
|||||||
list_for_each_safe(ele, next, &winch_handlers) {
|
list_for_each_safe(ele, next, &winch_handlers) {
|
||||||
winch = list_entry(ele, struct winch, list);
|
winch = list_entry(ele, struct winch, list);
|
||||||
if (winch->tty == tty) {
|
if (winch->tty == tty) {
|
||||||
free_winch(winch, 1);
|
free_winch(winch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -845,7 +855,7 @@ static void winch_cleanup(void)
|
|||||||
|
|
||||||
list_for_each_safe(ele, next, &winch_handlers) {
|
list_for_each_safe(ele, next, &winch_handlers) {
|
||||||
winch = list_entry(ele, struct winch, list);
|
winch = list_entry(ele, struct winch, list);
|
||||||
free_winch(winch, 1);
|
free_winch(winch);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&winch_handler_lock);
|
spin_unlock(&winch_handler_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user