]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more patches added to the queue
authorGreg Kroah-Hartman <gregkh@suse.de>
Mon, 19 Mar 2007 21:22:48 +0000 (14:22 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 19 Mar 2007 21:22:48 +0000 (14:22 -0700)
queue-2.6.20/dio-invalidate-clean-pages-before-dio-write.patch [new file with mode: 0644]
queue-2.6.20/fix-deadlock-in-audit_log_task_context.patch [new file with mode: 0644]
queue-2.6.20/hda-intel-fix-codec-probe-with-ati-controllers.patch [new file with mode: 0644]
queue-2.6.20/input-i8042-fix-aux-irq-delivery-check.patch [new file with mode: 0644]
queue-2.6.20/input-i8042-really-suppress-ack-nak-during-panic-blink.patch [new file with mode: 0644]
queue-2.6.20/oom-fix-prevent-oom-from-killing-a-process-with-children-sibling-unkillable.patch [new file with mode: 0644]
queue-2.6.20/series
queue-2.6.20/uml-arch_prctl-should-set-thread-fs.patch [new file with mode: 0644]

diff --git a/queue-2.6.20/dio-invalidate-clean-pages-before-dio-write.patch b/queue-2.6.20/dio-invalidate-clean-pages-before-dio-write.patch
new file mode 100644 (file)
index 0000000..222fe78
--- /dev/null
@@ -0,0 +1,124 @@
+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;
+ }
diff --git a/queue-2.6.20/fix-deadlock-in-audit_log_task_context.patch b/queue-2.6.20/fix-deadlock-in-audit_log_task_context.patch
new file mode 100644 (file)
index 0000000..4cc0756
--- /dev/null
@@ -0,0 +1,67 @@
+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;
+ }
diff --git a/queue-2.6.20/hda-intel-fix-codec-probe-with-ati-controllers.patch b/queue-2.6.20/hda-intel-fix-codec-probe-with-ati-controllers.patch
new file mode 100644 (file)
index 0000000..8c8038b
--- /dev/null
@@ -0,0 +1,62 @@
+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)
diff --git a/queue-2.6.20/input-i8042-fix-aux-irq-delivery-check.patch b/queue-2.6.20/input-i8042-fix-aux-irq-delivery-check.patch
new file mode 100644 (file)
index 0000000..6073855
--- /dev/null
@@ -0,0 +1,51 @@
+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(&param, 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.
diff --git a/queue-2.6.20/input-i8042-really-suppress-ack-nak-during-panic-blink.patch b/queue-2.6.20/input-i8042-really-suppress-ack-nak-during-panic-blink.patch
new file mode 100644 (file)
index 0000000..e7323a5
--- /dev/null
@@ -0,0 +1,52 @@
+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;
diff --git a/queue-2.6.20/oom-fix-prevent-oom-from-killing-a-process-with-children-sibling-unkillable.patch b/queue-2.6.20/oom-fix-prevent-oom-from-killing-a-process-with-children-sibling-unkillable.patch
new file mode 100644 (file)
index 0000000..d87c5a1
--- /dev/null
@@ -0,0 +1,38 @@
+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);
index 7aaf2e80a7b938c70f5f91906afc6cce77bf7869..93854009e0e68db41838e6a068c919d276084ed3 100644 (file)
@@ -22,3 +22,10 @@ copy-over-mac_len-when-cloning-an-skb.patch
 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
diff --git a/queue-2.6.20/uml-arch_prctl-should-set-thread-fs.patch b/queue-2.6.20/uml-arch_prctl-should-set-thread-fs.patch
new file mode 100644 (file)
index 0000000..6663b2f
--- /dev/null
@@ -0,0 +1,246 @@
+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, &current->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, &current->thread.regs.regs);
+               break;
+       case ARCH_SET_GS:
+-              current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
++              save_registers(pid, &current->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, &current->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