aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:47:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-31 21:47:30 -0400
commitfb21affa49204acd409328415b49bfe90136653c (patch)
tree3535dbe0c0aad049a38cadfcffe78409397a1b32 /kernel/irq
parenta00b6151a2ae4c52576c35d3998e144a993d50b8 (diff)
parentf23ca335462e3c84f13270b9e65f83936068ec2c (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull second pile of signal handling patches from Al Viro: "This one is just task_work_add() series + remaining prereqs for it. There probably will be another pull request from that tree this cycle - at least for helpers, to get them out of the way for per-arch fixes remaining in the tree." Fix trivial conflict in kernel/irq/manage.c: the merge of Andrew's pile had brought in commit 97fd75b7b8e0 ("kernel/irq/manage.c: use the pr_foo() infrastructure to prefix printks") which changed one of the pr_err() calls that this merge moves around. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: keys: kill task_struct->replacement_session_keyring keys: kill the dummy key_replace_session_keyring() keys: change keyctl_session_to_parent() to use task_work_add() genirq: reimplement exit_irq_thread() hook via task_work_add() task_work_add: generic process-context callbacks avr32: missed _TIF_NOTIFY_RESUME on one of do_notify_resume callers parisc: need to check NOTIFY_RESUME when exiting from syscall move key_repace_session_keyring() into tracehook_notify_resume() TIF_NOTIFY_RESUME is defined on all targets now
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/manage.c68
1 files changed, 33 insertions, 35 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 7c475cd3f6e6..ea0c6c2ae6f7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -16,6 +16,7 @@
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/task_work.h>
19 20
20#include "internals.h" 21#include "internals.h"
21 22
@@ -775,11 +776,39 @@ static void wake_threads_waitq(struct irq_desc *desc)
775 wake_up(&desc->wait_for_threads); 776 wake_up(&desc->wait_for_threads);
776} 777}
777 778
779static void irq_thread_dtor(struct task_work *unused)
780{
781 struct task_struct *tsk = current;
782 struct irq_desc *desc;
783 struct irqaction *action;
784
785 if (WARN_ON_ONCE(!(current->flags & PF_EXITING)))
786 return;
787
788 action = kthread_data(tsk);
789
790 pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
791 tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
792
793
794 desc = irq_to_desc(action->irq);
795 /*
796 * If IRQTF_RUNTHREAD is set, we need to decrement
797 * desc->threads_active and wake possible waiters.
798 */
799 if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
800 wake_threads_waitq(desc);
801
802 /* Prevent a stale desc->threads_oneshot */
803 irq_finalize_oneshot(desc, action);
804}
805
778/* 806/*
779 * Interrupt handler thread 807 * Interrupt handler thread
780 */ 808 */
781static int irq_thread(void *data) 809static int irq_thread(void *data)
782{ 810{
811 struct task_work on_exit_work;
783 static const struct sched_param param = { 812 static const struct sched_param param = {
784 .sched_priority = MAX_USER_RT_PRIO/2, 813 .sched_priority = MAX_USER_RT_PRIO/2,
785 }; 814 };
@@ -795,7 +824,9 @@ static int irq_thread(void *data)
795 handler_fn = irq_thread_fn; 824 handler_fn = irq_thread_fn;
796 825
797 sched_setscheduler(current, SCHED_FIFO, &param); 826 sched_setscheduler(current, SCHED_FIFO, &param);
798 current->irq_thread = 1; 827
828 init_task_work(&on_exit_work, irq_thread_dtor, NULL);
829 task_work_add(current, &on_exit_work, false);
799 830
800 while (!irq_wait_for_interrupt(action)) { 831 while (!irq_wait_for_interrupt(action)) {
801 irqreturn_t action_ret; 832 irqreturn_t action_ret;
@@ -817,44 +848,11 @@ static int irq_thread(void *data)
817 * cannot touch the oneshot mask at this point anymore as 848 * cannot touch the oneshot mask at this point anymore as
818 * __setup_irq() might have given out currents thread_mask 849 * __setup_irq() might have given out currents thread_mask
819 * again. 850 * again.
820 *
821 * Clear irq_thread. Otherwise exit_irq_thread() would make
822 * fuzz about an active irq thread going into nirvana.
823 */ 851 */
824 current->irq_thread = 0; 852 task_work_cancel(current, irq_thread_dtor);
825 return 0; 853 return 0;
826} 854}
827 855
828/*
829 * Called from do_exit()
830 */
831void exit_irq_thread(void)
832{
833 struct task_struct *tsk = current;
834 struct irq_desc *desc;
835 struct irqaction *action;
836
837 if (!tsk->irq_thread)
838 return;
839
840 action = kthread_data(tsk);
841
842 pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
843 tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
844
845 desc = irq_to_desc(action->irq);
846
847 /*
848 * If IRQTF_RUNTHREAD is set, we need to decrement
849 * desc->threads_active and wake possible waiters.
850 */
851 if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
852 wake_threads_waitq(desc);
853
854 /* Prevent a stale desc->threads_oneshot */
855 irq_finalize_oneshot(desc, action);
856}
857
858static void irq_setup_forced_threading(struct irqaction *new) 856static void irq_setup_forced_threading(struct irqaction *new)
859{ 857{
860 if (!force_irqthreads) 858 if (!force_irqthreads)