diff options
author | Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> | 2005-07-07 20:56:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-07 21:23:44 -0400 |
commit | 605a69ac81249cca531cdc6b3e695f15dda63102 (patch) | |
tree | f42d781478ddf14288d3952263363efde1bc45a2 | |
parent | 3f580470baa3afc423e38fdc6e19667446b5aac0 (diff) |
[PATCH] uml: remove winch sem
Replace a semaphore (winch_handler_sem) used in atomic code with a
spinlock, and reduces as needed the amount of protected code to the bare
minimum (for instance no kmalloc calls are needed).
This fixes the last problems with spinlocking (in UP mode with DEBUG
options); the semaphore, taken inside spinlocks, caused a "spin_lock was
already locked" warning, without this patch.
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/um/drivers/line.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 2bb4c4f5dec4..e0fdffa2d542 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set, | |||
663 | return driver; | 663 | return driver; |
664 | } | 664 | } |
665 | 665 | ||
666 | static spinlock_t winch_handler_lock; | ||
667 | LIST_HEAD(winch_handlers); | ||
668 | |||
666 | void lines_init(struct line *lines, int nlines) | 669 | void lines_init(struct line *lines, int nlines) |
667 | { | 670 | { |
668 | struct line *line; | 671 | struct line *line; |
669 | int i; | 672 | int i; |
670 | 673 | ||
674 | spin_lock_init(&winch_handler_lock); | ||
671 | for(i = 0; i < nlines; i++){ | 675 | for(i = 0; i < nlines; i++){ |
672 | line = &lines[i]; | 676 | line = &lines[i]; |
673 | INIT_LIST_HEAD(&line->chan_list); | 677 | INIT_LIST_HEAD(&line->chan_list); |
@@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) | |||
724 | return IRQ_HANDLED; | 728 | return IRQ_HANDLED; |
725 | } | 729 | } |
726 | 730 | ||
727 | DECLARE_MUTEX(winch_handler_sem); | ||
728 | LIST_HEAD(winch_handlers); | ||
729 | |||
730 | void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) | 731 | void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) |
731 | { | 732 | { |
732 | struct winch *winch; | 733 | struct winch *winch; |
733 | 734 | ||
734 | down(&winch_handler_sem); | ||
735 | winch = kmalloc(sizeof(*winch), GFP_KERNEL); | 735 | winch = kmalloc(sizeof(*winch), GFP_KERNEL); |
736 | if (winch == NULL) { | 736 | if (winch == NULL) { |
737 | printk("register_winch_irq - kmalloc failed\n"); | 737 | printk("register_winch_irq - kmalloc failed\n"); |
738 | goto out; | 738 | return; |
739 | } | 739 | } |
740 | |||
740 | *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), | 741 | *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), |
741 | .fd = fd, | 742 | .fd = fd, |
742 | .tty_fd = tty_fd, | 743 | .tty_fd = tty_fd, |
743 | .pid = pid, | 744 | .pid = pid, |
744 | .tty = tty }); | 745 | .tty = tty }); |
746 | |||
747 | spin_lock(&winch_handler_lock); | ||
745 | list_add(&winch->list, &winch_handlers); | 748 | list_add(&winch->list, &winch_handlers); |
749 | spin_unlock(&winch_handler_lock); | ||
750 | |||
746 | if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, | 751 | if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, |
747 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, | 752 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, |
748 | "winch", winch) < 0) | 753 | "winch", winch) < 0) |
749 | printk("register_winch_irq - failed to register IRQ\n"); | 754 | printk("register_winch_irq - failed to register IRQ\n"); |
750 | out: | ||
751 | up(&winch_handler_sem); | ||
752 | } | 755 | } |
753 | 756 | ||
754 | static void unregister_winch(struct tty_struct *tty) | 757 | static void unregister_winch(struct tty_struct *tty) |
@@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty) | |||
756 | struct list_head *ele; | 759 | struct list_head *ele; |
757 | struct winch *winch, *found = NULL; | 760 | struct winch *winch, *found = NULL; |
758 | 761 | ||
759 | down(&winch_handler_sem); | 762 | spin_lock(&winch_handler_lock); |
760 | list_for_each(ele, &winch_handlers){ | 763 | list_for_each(ele, &winch_handlers){ |
761 | winch = list_entry(ele, struct winch, list); | 764 | winch = list_entry(ele, struct winch, list); |
762 | if(winch->tty == tty){ | 765 | if(winch->tty == tty){ |
@@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty) | |||
764 | break; | 767 | break; |
765 | } | 768 | } |
766 | } | 769 | } |
767 | |||
768 | if(found == NULL) | 770 | if(found == NULL) |
769 | goto out; | 771 | goto err; |
772 | |||
773 | list_del(&winch->list); | ||
774 | spin_unlock(&winch_handler_lock); | ||
770 | 775 | ||
771 | if(winch->pid != -1) | 776 | if(winch->pid != -1) |
772 | os_kill_process(winch->pid, 1); | 777 | os_kill_process(winch->pid, 1); |
773 | 778 | ||
774 | free_irq(WINCH_IRQ, winch); | 779 | free_irq(WINCH_IRQ, winch); |
775 | list_del(&winch->list); | ||
776 | kfree(winch); | 780 | kfree(winch); |
777 | out: | 781 | |
778 | up(&winch_handler_sem); | 782 | return; |
783 | err: | ||
784 | spin_unlock(&winch_handler_lock); | ||
779 | } | 785 | } |
780 | 786 | ||
787 | /* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup | ||
788 | * order... are we sure that nothing else is done on the list? */ | ||
781 | static void winch_cleanup(void) | 789 | static void winch_cleanup(void) |
782 | { | 790 | { |
783 | struct list_head *ele; | 791 | struct list_head *ele; |
@@ -786,6 +794,9 @@ static void winch_cleanup(void) | |||
786 | list_for_each(ele, &winch_handlers){ | 794 | list_for_each(ele, &winch_handlers){ |
787 | winch = list_entry(ele, struct winch, list); | 795 | winch = list_entry(ele, struct winch, list); |
788 | if(winch->fd != -1){ | 796 | if(winch->fd != -1){ |
797 | /* Why is this different from the above free_irq(), | ||
798 | * which deactivates SIGIO? This searches the FD | ||
799 | * somewhere else and removes it from the list... */ | ||
789 | deactivate_fd(winch->fd, WINCH_IRQ); | 800 | deactivate_fd(winch->fd, WINCH_IRQ); |
790 | os_close_file(winch->fd); | 801 | os_close_file(winch->fd); |
791 | } | 802 | } |