On Sun, May 16, 2010 at 16:07, Jan Kiszka <jan.kis...@web.de> wrote:
> Jan Kiszka wrote:
>> Paolo Giarrusso wrote:
>>> On Mon, May 10, 2010 at 19:43, Jan Kiszka <jan.kis...@web.de> wrote:
>>>> Lukas Czerner wrote:

>> Right, there was more broken. Besides the locking fix, this should do
>> the trick by avoiding the recursive free_winch call:

>> diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
>> index d85fcb9..fa66eb4 100644
>> --- a/arch/um/drivers/line.c
>> +++ b/arch/um/drivers/line.c
>> @@ -731,8 +731,10 @@ static void free_winch(struct winch *winch, int 
>> free_irq_ok)
>>
>>       if (winch->pid != -1)
>>               os_kill_process(winch->pid, 1);
>> -     if (winch->fd != -1)
>> +     if (winch->fd != -1) {
>>               os_close_file(winch->fd);
>> +             winch->fd = -1;
>> +     }
>>       if (winch->stack != 0)
>>               free_stack(winch->stack, 0);
>>       if (free_irq_ok)
>>
>> (note: untested)
>
> Well, thought about it again, this is the result:

Given a look, it makes sense. But still, I think that moving the
free_irq call to earlier might make the result more stable.
Moreover, do you really need to avoid the handler calling free_irq?
That should be safe, as long as the IRQ is shutdown by cleanup
routines as the first thing, before the call to
list_del(&winch->list).

> uml: Fix winch cleanup races
>
> Calling free_winch from within the IRQ handler is broken for many
> reasons: It can leave the IRQ line registered and it races with
> parallel cleanup by unregister_winch and winch_cleanup.
>
> Resolve this via a per-winch spinlock that protects pid and fd of the
> winch structure.
>
> Signed-off-by: Jan Kiszka <jan.kis...@web.de>
> ---
>  arch/um/drivers/line.c |   50 ++++++++++++++++++++++++++++++++++++-----------
>  1 files changed, 38 insertions(+), 12 deletions(-)
>
> diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
> index 7f8f649..4b9d177 100644
> --- a/arch/um/drivers/line.c
> +++ b/arch/um/drivers/line.c
> @@ -723,20 +723,30 @@ struct winch {
>        int pid;
>        struct tty_struct *tty;
>        unsigned long stack;
> +       spinlock_t lock;
>  };
>
> -static void free_winch(struct winch *winch, int free_irq_ok)
> +static void free_winch(struct winch *winch)
>  {
> -       list_del(&winch->list);
> +       spin_lock_irq(&winch->lock);
>
> -       if (winch->pid != -1)
> +       if (winch->pid != -1) {
>                os_kill_process(winch->pid, 1);
> -       if (winch->fd != -1)
> +               winch->pid = -1;
> +       }
> +       if (winch->fd != -1) {
>                os_close_file(winch->fd);
> +               winch->fd = -1;
> +       }
> +
> +       spin_unlock_irq(&winch->lock);
> +
>        if (winch->stack != 0)
>                free_stack(winch->stack, 0);
> -       if (free_irq_ok)
> -               um_free_irq(WINCH_IRQ, winch);
> +
> +       um_free_irq(WINCH_IRQ, winch);
> +
> +       list_del(&winch->list);
>        kfree(winch);
>  }
>
> @@ -748,6 +758,8 @@ static irqreturn_t winch_interrupt(int irq, void *data)
>        int err;
>        char c;
>
> +       spin_lock(&winch->lock);
> +
>        if (winch->fd != -1) {
>                err = generic_read(winch->fd, &c, NULL);
>                if (err < 0) {
> @@ -756,10 +768,17 @@ static irqreturn_t winch_interrupt(int irq, void *data)
>                                       "read failed, errno = %d\n", -err);
>                                printk(KERN_ERR "fd %d is losing SIGWINCH "
>                                       "support\n", winch->tty_fd);
> -                               free_winch(winch, 0);
> -                               return IRQ_HANDLED;
> +
> +                               if (winch->pid != -1) {
> +                                       os_kill_process(winch->pid, 1);
> +                                       winch->pid = -1;
> +                               }
> +                               os_close_file(winch->fd);
> +                               winch->fd = -1;
> +
> +                               goto unlock_out;
>                        }
> -                       goto out;
> +                       goto reactivate_out;
>                }
>        }
>        tty = winch->tty;
> @@ -771,9 +790,14 @@ static irqreturn_t winch_interrupt(int irq, void *data)
>                        kill_pgrp(tty->pgrp, SIGWINCH, 1);
>                }
>        }
> - out:
> +
> +reactivate_out:
>        if (winch->fd != -1)
>                reactivate_fd(winch->fd, WINCH_IRQ);
> +
> +unlock_out:
> +       spin_unlock(&winch->lock);
> +
>        return IRQ_HANDLED;
>  }
>
> @@ -795,6 +819,8 @@ void register_winch_irq(int fd, int tty_fd, int pid, 
> struct tty_struct *tty,
>                                   .tty         = tty,
>                                   .stack       = stack });
>
> +       spin_lock_init(&winch->lock);
> +
>        if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
>                           IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
>                           "winch", winch) < 0) {
> @@ -828,7 +854,7 @@ static void unregister_winch(struct tty_struct *tty)
>        list_for_each(ele, &winch_handlers) {
>                winch = list_entry(ele, struct winch, list);
>                if (winch->tty == tty) {
> -                       free_winch(winch, 1);
> +                       free_winch(winch);
>                        break;
>                }
>        }
> @@ -844,7 +870,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);
>
>
>



-- 
Paolo Giarrusso
------------------------------------------------------------------------------

_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel

Reply via email to