--- /dev/null
+From stable-bounces@linux.kernel.org Sun Mar 18 15:57:07 2007
+From: Zach Brown <zach.brown@oracle.com>
+Date: Sun, 18 Mar 2007 18:55:51 -0400
+Subject: dio: invalidate clean pages before dio write
+To: linux-stable <stable@kernel.org>
+Message-ID: <45FDC377.7040309@redhat.com>
+
+From: Zach Brown <zach.brown@oracle.com>
+
+[PATCH] dio: invalidate clean pages before dio write
+
+This patch fixes a user-triggerable oops that was reported by Leonid
+Ananiev as archived at http://lkml.org/lkml/2007/2/8/337.
+
+dio writes invalidate clean pages that intersect the written region so that
+subsequent buffered reads go to disk to read the new data. If this fails
+the interface tries to tell the caller that the cache is inconsistent by
+returning EIO.
+
+Before this patch we had the problem where this invalidation failure would
+clobber -EIOCBQUEUED as it made its way from fs/direct-io.c to fs/aio.c.
+Both fs/aio.c and bio completion call aio_complete() and we reference freed
+memory, usually oopsing.
+
+This patch addresses this problem by invalidating before the write so that
+we can cleanly return -EIO before ->direct_IO() has had a chance to return
+-EIOCBQUEUED.
+
+There is a compromise here. During the dio write we can fault in mmap()ed
+pages which intersect the written range with get_user_pages() if the user
+provided them for the source buffer. This is a crazy thing to do, but we
+can make it mostly work in most cases by trying the invalidation again.
+The compromise is that we won't return an error if this second invalidation
+fails if it's an AIO write and we have -EIOCBQUEUED.
+
+This was tested by having two processes race performing large O_DIRECT and
+buffered ordered writes. Within minutes ext3 would see a race between
+ext3_releasepage() and jbd holding a reference on ordered data buffers and
+would cause invalidation to fail, panicing the box. The test can be found
+in the 'aio_dio_bugs' test group in test.kernel.org/autotest. After this
+patch the test passes.
+
+Signed-off-by: Zach Brown <zach.brown@oracle.com>
+Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Cc: Leonid Ananiev <leonid.i.ananiev@linux.intel.com>
+Cc: Nick Piggin <nickpiggin@yahoo.com.au>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/filemap.c | 46 +++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 35 insertions(+), 11 deletions(-)
+
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -2393,7 +2393,8 @@ generic_file_direct_IO(int rw, struct ki
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ ssize_t retval;
+- size_t write_len = 0;
++ size_t write_len;
++ pgoff_t end = 0; /* silence gcc */
+
+ /*
+ * If it's a write, unmap all mmappings of the file up-front. This
+@@ -2402,23 +2403,46 @@ generic_file_direct_IO(int rw, struct ki
+ */
+ if (rw == WRITE) {
+ write_len = iov_length(iov, nr_segs);
++ end = (offset + write_len - 1) >> PAGE_CACHE_SHIFT;
+ if (mapping_mapped(mapping))
+ unmap_mapping_range(mapping, offset, write_len, 0);
+ }
+
+ retval = filemap_write_and_wait(mapping);
+- if (retval == 0) {
+- retval = mapping->a_ops->direct_IO(rw, iocb, iov,
+- offset, nr_segs);
+- if (rw == WRITE && mapping->nrpages) {
+- pgoff_t end = (offset + write_len - 1)
+- >> PAGE_CACHE_SHIFT;
+- int err = invalidate_inode_pages2_range(mapping,
++ if (retval)
++ goto out;
++
++ /*
++ * After a write we want buffered reads to be sure to go to disk to get
++ * the new data. We invalidate clean cached page from the region we're
++ * about to write. We do this *before* the write so that we can return
++ * -EIO without clobbering -EIOCBQUEUED from ->direct_IO().
++ */
++ if (rw == WRITE && mapping->nrpages) {
++ retval = invalidate_inode_pages2_range(mapping,
+ offset >> PAGE_CACHE_SHIFT, end);
+- if (err)
+- retval = err;
+- }
++ if (retval)
++ goto out;
++ }
++
++ retval = mapping->a_ops->direct_IO(rw, iocb, iov, offset, nr_segs);
++ if (retval)
++ goto out;
++
++ /*
++ * Finally, try again to invalidate clean pages which might have been
++ * faulted in by get_user_pages() if the source of the write was an
++ * mmap()ed region of the file we're writing. That's a pretty crazy
++ * thing to do, so we don't support it 100%. If this invalidation
++ * fails and we have -EIOCBQUEUED we ignore the failure.
++ */
++ if (rw == WRITE && mapping->nrpages) {
++ int err = invalidate_inode_pages2_range(mapping,
++ offset >> PAGE_CACHE_SHIFT, end);
++ if (err && retval >= 0)
++ retval = err;
+ }
++out:
+ return retval;
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Mon Mar 19 08:58:22 2007
+From: Al Viro <viro@ftp.linux.org.uk>
+Date: Mon, 19 Mar 2007 11:55:04 -0400
+Subject: fix deadlock in audit_log_task_context()
+To: linux-stable <stable@kernel.org>
+Message-ID: <45FEB258.7060803@redhat.com>
+
+From: Al Viro <viro@ftp.linux.org.uk>
+
+[PATCH] fix deadlock in audit_log_task_context()
+
+GFP_KERNEL allocations in non-blocking context; fixed by killing
+an idiotic use of security_getprocattr().
+
+Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
+Acked-by: James Morris <jmorris@namei.org>
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ kernel/auditsc.c | 24 +++++++++++-------------
+ 1 file changed, 11 insertions(+), 13 deletions(-)
+
+--- a/kernel/auditsc.c
++++ b/kernel/auditsc.c
+@@ -734,28 +734,26 @@ static inline void audit_free_context(st
+ void audit_log_task_context(struct audit_buffer *ab)
+ {
+ char *ctx = NULL;
+- ssize_t len = 0;
++ unsigned len;
++ int error;
++ u32 sid;
+
+- len = security_getprocattr(current, "current", NULL, 0);
+- if (len < 0) {
+- if (len != -EINVAL)
++ selinux_get_task_sid(current, &sid);
++ if (!sid)
++ return;
++
++ error = selinux_sid_to_string(sid, &ctx, &len);
++ if (error) {
++ if (error != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+- ctx = kmalloc(len, GFP_KERNEL);
+- if (!ctx)
+- goto error_path;
+-
+- len = security_getprocattr(current, "current", ctx, len);
+- if (len < 0 )
+- goto error_path;
+-
+ audit_log_format(ab, " subj=%s", ctx);
++ kfree(ctx);
+ return;
+
+ error_path:
+- kfree(ctx);
+ audit_panic("error in audit_log_task_context");
+ return;
+ }
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Mar 18 15:20:54 2007
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sun, 18 Mar 2007 18:19:29 -0400
+Subject: [ALSA] hda-intel - Fix codec probe with ATI controllers
+To: linux-stable <stable@kernel.org>
+Message-ID: <45FDBAF1.2060408@redhat.com>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ALSA] hda-intel - Fix codec probe with ATI contorllers
+
+ATI controllers may have up to 4 codecs while ICH up to 3.
+Thus the earlier fix to change AZX_MAX_CODECS to 3 cause a regression
+on some devices that have the audio codec at bit#3.
+Now max codecs is defined according to the driver type, either 3 or 4.
+Currently 4 is set only to ATI chips. Other might need the same
+change, too.
+
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Jaroslav Kysela <perex@suse.cz>
+
+---
+ sound/pci/hda/hda_intel.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/sound/pci/hda/hda_intel.c
++++ b/sound/pci/hda/hda_intel.c
+@@ -199,7 +199,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO
+
+ /* STATESTS int mask: SD2,SD1,SD0 */
+ #define STATESTS_INT_MASK 0x07
+-#define AZX_MAX_CODECS 3
+
+ /* SD_CTL bits */
+ #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
+@@ -966,6 +965,16 @@ static int azx_setup_controller(struct a
+ * Codec initialization
+ */
+
++static unsigned int azx_max_codecs[] __devinitdata = {
++ [AZX_DRIVER_ICH] = 3,
++ [AZX_DRIVER_ATI] = 4,
++ [AZX_DRIVER_ATIHDMI] = 4,
++ [AZX_DRIVER_VIA] = 3, /* FIXME: correct? */
++ [AZX_DRIVER_SIS] = 3, /* FIXME: correct? */
++ [AZX_DRIVER_ULI] = 3, /* FIXME: correct? */
++ [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */
++};
++
+ static int __devinit azx_codec_create(struct azx *chip, const char *model)
+ {
+ struct hda_bus_template bus_temp;
+@@ -982,7 +991,7 @@ static int __devinit azx_codec_create(st
+ return err;
+
+ codecs = 0;
+- for (c = 0; c < AZX_MAX_CODECS; c++) {
++ for (c = 0; c < azx_max_codecs[chip->driver_type]; c++) {
+ if ((chip->codec_mask & (1 << c)) & probe_mask) {
+ err = snd_hda_codec_new(chip->bus, c, NULL);
+ if (err < 0)
--- /dev/null
+From cebbert@redhat.com Mon Mar 19 07:18:29 2007
+From: Chuck Ebbert <cebbert@redhat.com>
+Date: Mon, 19 Mar 2007 09:06:25 -0400
+Subject: Input: i8042 - fix AUX IRQ delivery check
+To: Greg KH <greg@kroah.com>
+Message-ID: <45FE8AD1.1040305@redhat.com>
+
+From: Dmitry Torokhov <dtor@insightbb.com>
+
+Input: i8042 - fix AUX IRQ delivery check
+
+On boxes that do not implement AUX LOOP command we can not
+verify AUX IRQ delivery and must assume that it is wired
+properly.
+
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/serio/i8042.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/input/serio/i8042.c
++++ b/drivers/input/serio/i8042.c
+@@ -543,6 +543,7 @@ static int __devinit i8042_check_aux(voi
+ {
+ int retval = -1;
+ int irq_registered = 0;
++ int aux_loop_broken = 0;
+ unsigned long flags;
+ unsigned char param;
+
+@@ -572,6 +573,8 @@ static int __devinit i8042_check_aux(voi
+ if (i8042_command(¶m, I8042_CMD_AUX_TEST) ||
+ (param && param != 0xfa && param != 0xff))
+ return -1;
++
++ aux_loop_broken = 1;
+ }
+
+ /*
+@@ -595,7 +598,7 @@ static int __devinit i8042_check_aux(voi
+ * used it for a PCI card or somethig else.
+ */
+
+- if (i8042_noloop) {
++ if (i8042_noloop || aux_loop_broken) {
+ /*
+ * Without LOOP command we can't test AUX IRQ delivery. Assume the port
+ * is working and hope we are right.
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Mar 18 14:42:51 2007
+From: Dmitry Torokhov <dtor@insightbb.com>
+Date: Sun, 18 Mar 2007 17:41:28 -0400
+Subject: Input: i8042 - really suppress ACK/NAK during panic blink
+To: linux-stable <stable@kernel.org>
+Message-ID: <45FDB208.90502@redhat.com>
+
+From: Dmitry Torokhov <dtor@insightbb.com>
+
+Input: i8042 - really suppress ACK/NAK during panic blink
+
+On some boxes panic blink procedure manages to send both bytes
+to keyboard contoller before getting first ACK so we need to
+make i8042_suppress_kbd_ack a counter instead of boolean.
+
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/input/serio/i8042.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/input/serio/i8042.c
++++ b/drivers/input/serio/i8042.c
+@@ -371,7 +371,7 @@ static irqreturn_t i8042_interrupt(int i
+ if (unlikely(i8042_suppress_kbd_ack))
+ if (port_no == I8042_KBD_PORT_NO &&
+ (data == 0xfa || data == 0xfe)) {
+- i8042_suppress_kbd_ack = 0;
++ i8042_suppress_kbd_ack--;
+ goto out;
+ }
+
+@@ -838,13 +838,14 @@ static long i8042_panic_blink(long count
+ led ^= 0x01 | 0x04;
+ while (i8042_read_status() & I8042_STR_IBF)
+ DELAY;
+- i8042_suppress_kbd_ack = 1;
++ dbg("%02x -> i8042 (panic blink)", 0xed);
++ i8042_suppress_kbd_ack = 2;
+ i8042_write_data(0xed); /* set leds */
+ DELAY;
+ while (i8042_read_status() & I8042_STR_IBF)
+ DELAY;
+ DELAY;
+- i8042_suppress_kbd_ack = 1;
++ dbg("%02x -> i8042 (panic blink)", led);
+ i8042_write_data(led);
+ DELAY;
+ last_blink = count;
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Mar 18 15:55:36 2007
+Date: Sun, 18 Mar 2007 18:54:14 -0400
+From: Ankita Garg <ankita@in.ibm.com>
+Subject: oom fix: prevent oom from killing a process with children/sibling unkillable
+To: linux-stable <stable@kernel.org>
+Message-ID: <45FDC316.60005@redhat.com>
+
+From: Ankita Garg <ankita@in.ibm.com>
+
+[PATCH] oom fix: prevent oom from killing a process with children/sibling unkillable
+
+Looking at oom_kill.c, found that the intention to not kill the selected
+process if any of its children/siblings has OOM_DISABLE set, is not being
+met.
+
+Signed-off-by: Ankita Garg <ankita@in.ibm.com>
+Cc: Chuck Ebbert <cebbert@redhat.com>
+Acked-by: Nick Piggin <npiggin@suse.de>
+Acked-by: William Irwin <wli@holomorphy.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ mm/oom_kill.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/oom_kill.c
++++ b/mm/oom_kill.c
+@@ -320,7 +320,7 @@ static int oom_kill_task(struct task_str
+ * Don't kill the process if any threads are set to OOM_DISABLE
+ */
+ do_each_thread(g, q) {
+- if (q->mm == mm && p->oomkilladj == OOM_DISABLE)
++ if (q->mm == mm && q->oomkilladj == OOM_DISABLE)
+ return 1;
+ } while_each_thread(g, q);
+
fix-sparc64-hugepage-bugs.patch
fix-page-allocation-debugging-on-sparc64.patch
irda-irttp_dup-spin_lock-initialisation.patch
+input-i8042-really-suppress-ack-nak-during-panic-blink.patch
+hda-intel-fix-codec-probe-with-ati-controllers.patch
+oom-fix-prevent-oom-from-killing-a-process-with-children-sibling-unkillable.patch
+dio-invalidate-clean-pages-before-dio-write.patch
+input-i8042-fix-aux-irq-delivery-check.patch
+fix-deadlock-in-audit_log_task_context.patch
+uml-arch_prctl-should-set-thread-fs.patch
--- /dev/null
+From jdike@addtoit.com Mon Mar 19 13:16:13 2007
+From: Jeff Dike <jdike@addtoit.com>
+Date: Mon, 19 Mar 2007 16:12:50 -0400
+Subject: UML - arch_prctl should set thread fs
+To: stable@kernel.org
+Cc: Greg KH <greg@kroah.com>, uml-devel <user-mode-linux-devel@lists.sourceforge.net>
+Message-ID: <20070319201250.GC12179@c2.user-mode-linux.org>
+
+From: Jeff Dike <jdike@addtoit.com>
+
+x86_64 needs some TLS fixes. What was missing was remembering the child
+thread id during clone and stuffing it into the child during each context
+switch.
+
+The %fs value is stored separately in the thread structure since the host
+controls what effect it has on the actual register file. The host also needs
+to store it in its own thread struct, so we need the value kept outside the
+register file.
+
+arch_prctl_skas was fixed to call PTRACE_ARCH_PRCTL appropriately. There is
+some saving and restoring of registers in the ARCH_SET_* cases so that the
+correct set of registers are changed on the host and restored to the process
+when it runs again.
+
+Signed-off-by: Jeff Dike <jdike@addtoit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/um/include/os.h | 2
+ arch/um/os-Linux/sys-x86_64/Makefile | 2
+ arch/um/os-Linux/sys-x86_64/prctl.c | 12 +++++
+ arch/um/sys-x86_64/syscalls.c | 76 ++++++++++++++++++++++++++---------
+ arch/um/sys-x86_64/tls.c | 11 +++--
+ include/asm-um/processor-x86_64.h | 6 +-
+ include/asm-um/ptrace-x86_64.h | 6 --
+ 7 files changed, 86 insertions(+), 29 deletions(-)
+
+--- a/arch/um/include/os.h
++++ b/arch/um/include/os.h
+@@ -341,4 +341,6 @@ extern void maybe_sigio_broken(int fd, i
+ extern void sig_handler_common_skas(int sig, void *sc_ptr);
+ extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
+
++extern int os_arch_prctl(int pid, int code, unsigned long *addr);
++
+ #endif
+--- a/arch/um/os-Linux/sys-x86_64/Makefile
++++ b/arch/um/os-Linux/sys-x86_64/Makefile
+@@ -3,7 +3,7 @@
+ # Licensed under the GPL
+ #
+
+-obj-$(CONFIG_MODE_SKAS) = registers.o signal.o
++obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o
+
+ USER_OBJS := $(obj-y)
+
+--- /dev/null
++++ b/arch/um/os-Linux/sys-x86_64/prctl.c
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com})
++ * Licensed under the GPL
++ */
++
++#include <sys/ptrace.h>
++#include <linux/ptrace.h>
++
++int os_arch_prctl(int pid, int code, unsigned long *addr)
++{
++ return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code);
++}
+--- a/arch/um/sys-x86_64/syscalls.c
++++ b/arch/um/sys-x86_64/syscalls.c
+@@ -16,6 +16,7 @@
+ #include "asm/prctl.h" /* XXX This should get the constants from libc */
+ #include "choose-mode.h"
+ #include "kern.h"
++#include "os.h"
+
+ asmlinkage long sys_uname64(struct new_utsname __user * name)
+ {
+@@ -58,40 +59,70 @@ static long arch_prctl_tt(int code, unsi
+
+ #ifdef CONFIG_MODE_SKAS
+
+-/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */
+-static long arch_prctl_skas(int code, unsigned long addr)
++static long arch_prctl_skas(int code, unsigned long __user *addr)
+ {
+- long ret = 0;
++ unsigned long *ptr = addr, tmp;
++ long ret;
++ int pid = current->mm->context.skas.id.u.pid;
++
++ /*
++ * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
++ * be safe), we need to call arch_prctl on the host because
++ * setting %fs may result in something else happening (like a
++ * GDT being set instead). So, we let the host fiddle the
++ * registers and restore them afterwards.
++ *
++ * So, the saved registers are stored to the process (this
++ * needed because a stub may have been the last thing to run),
++ * arch_prctl is run on the host, then the registers are read
++ * back.
++ */
++ switch(code){
++ case ARCH_SET_FS:
++ case ARCH_SET_GS:
++ restore_registers(pid, ¤t->thread.regs.regs);
++ break;
++ case ARCH_GET_FS:
++ case ARCH_GET_GS:
++ /*
++ * With these two, we read to a local pointer and
++ * put_user it to the userspace pointer that we were
++ * given. If addr isn't valid (because it hasn't been
++ * faulted in or is just bogus), we want put_user to
++ * fault it in (or return -EFAULT) instead of having
++ * the host return -EFAULT.
++ */
++ ptr = &tmp;
++ }
++
++ ret = os_arch_prctl(pid, code, ptr);
++ if(ret)
++ return ret;
+
+ switch(code){
+ case ARCH_SET_FS:
+- current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
++ current->thread.arch.fs = (unsigned long) ptr;
++ save_registers(pid, ¤t->thread.regs.regs);
+ break;
+ case ARCH_SET_GS:
+- current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
++ save_registers(pid, ¤t->thread.regs.regs);
+ break;
+ case ARCH_GET_FS:
+- ret = put_user(current->thread.regs.regs.skas.
+- regs[FS_BASE / sizeof(unsigned long)],
+- (unsigned long __user *)addr);
+- break;
++ ret = put_user(tmp, addr);
++ break;
+ case ARCH_GET_GS:
+- ret = put_user(current->thread.regs.regs.skas.
+- regs[GS_BASE / sizeof(unsigned long)],
+- (unsigned long __user *)addr);
+- break;
+- default:
+- ret = -EINVAL;
++ ret = put_user(tmp, addr);
+ break;
+ }
+
+- return(ret);
++ return ret;
+ }
+ #endif
+
+ long sys_arch_prctl(int code, unsigned long addr)
+ {
+- return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr));
++ return CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code,
++ (unsigned long __user *) addr);
+ }
+
+ long sys_clone(unsigned long clone_flags, unsigned long newsp,
+@@ -105,5 +136,14 @@ long sys_clone(unsigned long clone_flags
+ ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid,
+ child_tid);
+ current->thread.forking = 0;
+- return(ret);
++ return ret;
+ }
++
++void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
++{
++ if((to->thread.arch.fs == 0) || (to->mm == NULL))
++ return;
++
++ arch_prctl_skas(ARCH_SET_FS, (void __user *) to->thread.arch.fs);
++}
++
+--- a/arch/um/sys-x86_64/tls.c
++++ b/arch/um/sys-x86_64/tls.c
+@@ -1,14 +1,17 @@
+ #include "linux/sched.h"
+
+-void debug_arch_force_load_TLS(void)
+-{
+-}
+-
+ void clear_flushed_tls(struct task_struct *task)
+ {
+ }
+
+ int arch_copy_tls(struct task_struct *t)
+ {
++ /*
++ * If CLONE_SETTLS is set, we need to save the thread id
++ * (which is argument 5, child_tid, of clone) so it can be set
++ * during context switches.
++ */
++ t->thread.arch.fs = t->thread.regs.regs.skas.regs[R8 / sizeof(long)];
++
+ return 0;
+ }
+--- a/include/asm-um/processor-x86_64.h
++++ b/include/asm-um/processor-x86_64.h
+@@ -13,6 +13,7 @@
+ struct arch_thread {
+ unsigned long debugregs[8];
+ int debugregs_seq;
++ unsigned long fs;
+ struct faultinfo faultinfo;
+ };
+
+@@ -25,8 +26,9 @@ extern inline void rep_nop(void)
+ #define cpu_relax() rep_nop()
+
+ #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \
+- .debugregs_seq = 0, \
+- .faultinfo = { 0, 0, 0 } }
++ .debugregs_seq = 0, \
++ .fs = 0, \
++ .faultinfo = { 0, 0, 0 } }
+
+ static inline void arch_flush_thread(struct arch_thread *thread)
+ {
+--- a/include/asm-um/ptrace-x86_64.h
++++ b/include/asm-um/ptrace-x86_64.h
+@@ -81,9 +81,7 @@ static inline void arch_switch_to_tt(str
+ {
+ }
+
+-static inline void arch_switch_to_skas(struct task_struct *from,
+- struct task_struct *to)
+-{
+-}
++extern void arch_switch_to_skas(struct task_struct *from,
++ struct task_struct *to);
+
+ #endif