lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 15 Jun 2012 14:29:37 +0800
From:	Ning Jiang <ning.n.jiang@...il.com>
To:	Thomas Gleixner <tglx@...utronix.de>
Cc:	linux-kernel@...r.kernel.org
Subject: Re: [PATCH 2/2] genirq: Resend nested irq's ancestor irq

2012/6/14 Thomas Gleixner <tglx@...utronix.de>:
> On Thu, 14 Jun 2012, Ning Jiang wrote:
>> We'll set IRQS_PENDING for handle_nested_irq if it's disabled. When
>> it's re-enabled later on, check_irq_resend() will detect this flag
>> and trigger the software resend mechanism. resend_irqs() will call
>> desc->handle_irq() directly to process this interrupt, hence the
>> irq_nested_primary_handler() will be called for the nested irq which
>> gives us a warning.
>>
>> If we need to resend a nested interrupt, we have to trace all the
>> way back to its ancestor and trigger ancestor's irq flow handler.
>
> And what makes you believe that the ancestors demux handler will find
> the irq bit of the nested interrupt still pending? There is NO
> guarantee for that.

You are right.

> The correct solution for this is to replace the tasklet with a kernel
> thread and check whether the interrupt is marked nested or not and
> then invoke the correct function.
>

Do you want something like this? This just gives a rough idea. Please
help to review.

>From 1ce5f392446a06631d190468b314b7060f5c34ae Mon Sep 17 00:00:00 2001
From: Ning Jiang <ning.n.jiang@...il.com>
Date: Fri, 15 Jun 2012 09:13:24 +0800
Subject: [PATCH] genirq: Create temporary kernel thread when resending
nested irq

---
 kernel/irq/chip.c      |    1 +
 kernel/irq/handle.c    |    2 +-
 kernel/irq/internals.h |    4 ++++
 kernel/irq/manage.c    |    8 +++++++-
 kernel/irq/resend.c    |   20 +++++++++++++++++---
 5 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 6cec1a2..ec48d4e 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -272,6 +272,7 @@ void handle_nested_irq(unsigned int irq)

 	raw_spin_lock_irq(&desc->lock);

+	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
 	kstat_incr_irqs_this_cpu(irq, desc);

 	action = desc->action;
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index bdb1803..556b469 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -51,7 +51,7 @@ static void warn_no_thread(unsigned int irq, struct
irqaction *action)
 	       "but no thread function available.", irq, action->name);
 }

-static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
+void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
 {
 	/*
 	 * In case the thread crashed and was killed we just pretend that
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 001fa5b..fd9dabe 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -104,6 +104,10 @@ extern void irq_set_thread_affinity(struct irq_desc *desc);
 extern int irq_do_set_affinity(struct irq_data *data,
 			       const struct cpumask *dest, bool force);

+extern int irq_thread(void *data);
+
+extern void irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
+
 /* Inline functions for support of irq chips on slow busses */
 static inline void chip_bus_lock(struct irq_desc *desc)
 {
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8c54823..2bd4a39 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -811,7 +811,7 @@ static void irq_thread_dtor(struct task_work *unused)
 /*
  * Interrupt handler thread
  */
-static int irq_thread(void *data)
+int irq_thread(void *data)
 {
 	struct task_work on_exit_work;
 	static const struct sched_param param = {
@@ -843,6 +843,12 @@ static int irq_thread(void *data)
 			note_interrupt(action->irq, desc, action_ret);

 		wake_threads_waitq(desc);
+
+		if (irq_settings_is_nested_thread(desc) && desc->action->thread) {
+			put_task_struct(desc->action->thread);
+			desc->action->thread = NULL;
+			do_exit(0);
+		}
 	}

 	/*
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
index 6454db7..5bb9227 100644
--- a/kernel/irq/resend.c
+++ b/kernel/irq/resend.c
@@ -14,6 +14,7 @@
  */

 #include <linux/irq.h>
+#include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/interrupt.h>
@@ -74,9 +75,22 @@ void check_irq_resend(struct irq_desc *desc,
unsigned int irq)
 		if (!desc->irq_data.chip->irq_retrigger ||
 		    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
 #ifdef CONFIG_HARDIRQS_SW_RESEND
-			/* Set it pending and activate the softirq: */
-			set_bit(irq, irqs_resend);
-			tasklet_schedule(&resend_tasklet);
+			struct task_struct *t;
+			if (irq_settings_is_nested_thread(desc)) {
+				raw_spin_unlock(&desc->lock);
+				t = kthread_create(irq_thread, desc->action,
+					"irq/%d-%s", irq, desc->action->name);
+				raw_spin_lock(&desc->lock);
+				if (IS_ERR(t))
+					return;
+				get_task_struct(t);
+				desc->action->thread = t;
+				irq_wake_thread(desc, desc->action);
+			} else {
+				/* Set it pending and activate the softirq: */
+				set_bit(irq, irqs_resend);
+				tasklet_schedule(&resend_tasklet);
+			}
 #endif
 		}
 	}
-- 
1.7.1


> That requires a check for irq in progress in the nested handler as
> well, but that's trivial to add.

Will check it later.

> Thanks,
>
>        tglx
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ