Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7cf3cf21 authored by Al Viro's avatar Al Viro Committed by Linus Torvalds
Browse files

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 45cd5e2d
Loading
Loading
Loading
Loading
+24 −14
Original line number Diff line number Diff line
@@ -721,43 +721,53 @@ struct winch {
	int pid;
	struct tty_struct *tty;
	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;
	winch->fd = -1;
	if (free_irq_ok)
	struct winch *winch = container_of(work, struct winch, work);
	free_irq(WINCH_IRQ, winch);

	list_del(&winch->list);

	if (winch->pid != -1)
		os_kill_process(winch->pid, 1);
	if (fd != -1)
		os_close_file(fd);
	if (winch->stack != 0)
		free_stack(winch->stack, 0);
	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)
{
	struct winch *winch = data;
	struct tty_struct *tty;
	struct line *line;
	int fd = winch->fd;
	int err;
	char c;

	if (winch->fd != -1) {
		err = generic_read(winch->fd, &c, NULL);
	if (fd != -1) {
		err = generic_read(fd, &c, NULL);
		if (err < 0) {
			if (err != -EAGAIN) {
				winch->fd = -1;
				list_del(&winch->list);
				os_close_file(fd);
				printk(KERN_ERR "winch_interrupt : "
				       "read failed, errno = %d\n", -err);
				printk(KERN_ERR "fd %d is losing SIGWINCH "
				       "support\n", winch->tty_fd);
				free_winch(winch, 0);
				INIT_WORK(&winch->work, __free_winch);
				schedule_work(&winch->work);
				return IRQ_HANDLED;
			}
			goto out;
@@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty)
	list_for_each_safe(ele, next, &winch_handlers) {
		winch = list_entry(ele, struct winch, list);
		if (winch->tty == tty) {
			free_winch(winch, 1);
			free_winch(winch);
			break;
		}
	}
@@ -845,7 +855,7 @@ static void winch_cleanup(void)

	list_for_each_safe(ele, next, &winch_handlers) {
		winch = list_entry(ele, struct winch, list);
		free_winch(winch, 1);
		free_winch(winch);
	}

	spin_unlock(&winch_handler_lock);