]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
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>
Fri, 14 Sep 2012 17:00:22 +0000 (10:00 -0700)
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/traps.c

index d4cbbd1fa75f98c2835e4d2f51a6048787e729c2..8302af6492195b77ac8a5b7f5dfbc69dfc7d43b8 100644 (file)
@@ -196,8 +196,10 @@ static ssize_t show_dscr_default(struct device *dev,
 
 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 device *dev,
index 158972341a2d7a66da48c32878fdc0842b2a4feb..ae0843fa7a61f64540214b2fbf658265d24879df 100644 (file)
@@ -972,8 +972,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