powerpc: Keep thread.dscr and thread.dscr_inherit in sync
authorAnton Blanchard <anton@samba.org>
Mon, 3 Sep 2012 16:48:46 +0000 (16:48 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Dec 2012 18:49:05 +0000 (10:49 -0800)
commit 00ca0de02f80924dfff6b4f630e1dff3db005e35 upstream.

When we update the DSCR either via emulation of mtspr(DSCR) or via
a change to dscr_default in sysfs we don't update thread.dscr.
We will eventually update it at context switch time but there is
a period where thread.dscr is incorrect.

If we fork at this point we will copy the old value of thread.dscr
into the child. To avoid this, always keep thread.dscr in sync with
reality.

This issue was found with the following testcase:

http://ozlabs.org/~anton/junkcode/dscr_inherit_test.c

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Haren Myneni <haren@us.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c

index d62af950695b6b852f5f1a442c9c55f7da63efb3..cd51a5c713765b4b7a2e18d68f78928467a5d315 100644 (file)
@@ -194,8 +194,10 @@ static ssize_t show_dscr_default(struct sysdev_class *class,
 
 static void update_dscr(void *dummy)
 {
-       if (!current->thread.dscr_inherit)
+       if (!current->thread.dscr_inherit) {
+               current->thread.dscr = dscr_default;
                mtspr(SPRN_DSCR, dscr_default);
+       }
 }
 
 static ssize_t __used store_dscr_default(struct sysdev_class *class,
index 1a0141426cda8ba86bc64840197617f9cc099b89..6889f2676a97bb701337dcce3347883f99f501ec 100644 (file)
@@ -935,8 +935,9 @@ static int emulate_instruction(struct pt_regs *regs)
                        cpu_has_feature(CPU_FTR_DSCR)) {
                PPC_WARN_EMULATED(mtdscr, regs);
                rd = (instword >> 21) & 0x1f;
-               mtspr(SPRN_DSCR, regs->gpr[rd]);
+               current->thread.dscr = regs->gpr[rd];
                current->thread.dscr_inherit = 1;
+               mtspr(SPRN_DSCR, current->thread.dscr);
                return 0;
        }
 #endif