diff mbox

[RFC,2/3] x86, MCE: Avoid potential deadlock in MCE

Message ID f6ee27db104e769822437234b3fee199d51b5177.1405982894.git.tony.luck@intel.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Tony Luck July 21, 2014, 10:44 p.m. UTC
This is how much cleaner things could be with a couple of task_struct
fields instead of the mce_info silliness ... untested.

---
 arch/x86/kernel/cpu/mcheck/mce.c | 58 ++++------------------------------------
 include/linux/sched.h            |  4 +++
 2 files changed, 9 insertions(+), 53 deletions(-)

Comments

Borislav Petkov July 22, 2014, 5:20 p.m. UTC | #1
On Mon, Jul 21, 2014 at 03:44:06PM -0700, Tony Luck wrote:
> 
> This is how much cleaner things could be with a couple of task_struct
> fields instead of the mce_info silliness ... untested.

...

> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index 0376b054a0d0..91db69a4acd7 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1655,6 +1655,10 @@ struct task_struct {
>  	unsigned int	sequential_io;
>  	unsigned int	sequential_io_avg;
>  #endif
> +#ifdef CONFIG_MEMORY_FAILURE
> +	__u64	paddr;
> +	int	restartable;
> +#endif

Right, I don't see anything wrong with this approach especially as
task_struct is full of CONFIG_* ifdeffery for members used with
different features.

Adding 12 more bytes for CONFIG_MEMORY_FAILURE shouldn't hurt anyone. If
we really want to save space, we can use the highest significant byte of
paddr for a bit to say "restartable" or not.

So I think we should make it into a patch and push it upstream.
diff mbox

Patch

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index bb92f38153b2..b08398e69b5c 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -956,51 +956,6 @@  static void mce_clear_state(unsigned long *toclear)
 }
 
 /*
- * Need to save faulting physical address associated with a process
- * in the machine check handler some place where we can grab it back
- * later in mce_notify_process()
- */
-#define	MCE_INFO_MAX	16
-
-struct mce_info {
-	atomic_t		inuse;
-	struct task_struct	*t;
-	__u64			paddr;
-	int			restartable;
-} mce_info[MCE_INFO_MAX];
-
-static void mce_save_info(__u64 addr, int c)
-{
-	struct mce_info *mi;
-
-	for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++) {
-		if (atomic_cmpxchg(&mi->inuse, 0, 1) == 0) {
-			mi->t = current;
-			mi->paddr = addr;
-			mi->restartable = c;
-			return;
-		}
-	}
-
-	mce_panic("Too many concurrent recoverable errors", NULL, NULL);
-}
-
-static struct mce_info *mce_find_info(void)
-{
-	struct mce_info *mi;
-
-	for (mi = mce_info; mi < &mce_info[MCE_INFO_MAX]; mi++)
-		if (atomic_read(&mi->inuse) && mi->t == current)
-			return mi;
-	return NULL;
-}
-
-static void mce_clear_info(struct mce_info *mi)
-{
-	atomic_set(&mi->inuse, 0);
-}
-
-/*
  * The actual machine check handler. This only handles real
  * exceptions when something got corrupted coming in through int 18.
  *
@@ -1156,7 +1111,8 @@  void do_machine_check(struct pt_regs *regs, long error_code)
 			mce_panic("Fatal machine check on current CPU", &m, msg);
 		if (worst == MCE_AR_SEVERITY) {
 			/* schedule action before return to userland */
-			mce_save_info(m.addr, m.mcgstatus & MCG_STATUS_RIPV);
+			current->paddr = m.addr;
+			current->restartable = m.mcgstatus & MCG_STATUS_RIPV;
 			set_thread_flag(TIF_MCE_NOTIFY);
 		} else if (kill_it) {
 			force_sig(SIGBUS, current);
@@ -1195,29 +1151,25 @@  int memory_failure(unsigned long pfn, int vector, int flags)
 void mce_notify_process(void)
 {
 	unsigned long pfn;
-	struct mce_info *mi = mce_find_info();
 	int flags = MF_ACTION_REQUIRED;
 
-	if (!mi)
-		mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL);
-	pfn = mi->paddr >> PAGE_SHIFT;
+	pfn = current->paddr >> PAGE_SHIFT;
 
 	clear_thread_flag(TIF_MCE_NOTIFY);
 
 	pr_err("Uncorrected hardware memory error in user-access at %llx",
-		 mi->paddr);
+		 current->paddr);
 	/*
 	 * We must call memory_failure() here even if the current process is
 	 * doomed. We still need to mark the page as poisoned and alert any
 	 * other users of the page.
 	 */
-	if (!mi->restartable)
+	if (!current->restartable)
 		flags |= MF_MUST_KILL;
 	if (memory_failure(pfn, MCE_VECTOR, flags) < 0) {
 		pr_err("Memory error not recovered");
 		force_sig(SIGBUS, current);
 	}
-	mce_clear_info(mi);
 }
 
 /*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0376b054a0d0..91db69a4acd7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1655,6 +1655,10 @@  struct task_struct {
 	unsigned int	sequential_io;
 	unsigned int	sequential_io_avg;
 #endif
+#ifdef CONFIG_MEMORY_FAILURE
+	__u64	paddr;
+	int	restartable;
+#endif
 };
 
 /* Future-safe accessor for struct task_struct's cpus_allowed. */