From: Greg Kroah-Hartman Date: Mon, 19 Mar 2007 21:22:48 +0000 (-0700) Subject: more patches added to the queue X-Git-Tag: v2.6.20.4~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b6d807f3fa7fed979d601c8190c1002fbcd0ea2d;p=thirdparty%2Fkernel%2Fstable-queue.git more patches added to the queue --- 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 index 00000000000..222fe782dfe --- /dev/null +++ b/queue-2.6.20/dio-invalidate-clean-pages-before-dio-write.patch @@ -0,0 +1,124 @@ +From stable-bounces@linux.kernel.org Sun Mar 18 15:57:07 2007 +From: Zach Brown +Date: Sun, 18 Mar 2007 18:55:51 -0400 +Subject: dio: invalidate clean pages before dio write +To: linux-stable +Message-ID: <45FDC377.7040309@redhat.com> + +From: Zach Brown + +[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 +Signed-off-by: Benjamin LaHaise +Cc: Chuck Ebbert +Cc: Leonid Ananiev +Cc: Nick Piggin +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..4cc0756ea5d --- /dev/null +++ b/queue-2.6.20/fix-deadlock-in-audit_log_task_context.patch @@ -0,0 +1,67 @@ +From stable-bounces@linux.kernel.org Mon Mar 19 08:58:22 2007 +From: Al Viro +Date: Mon, 19 Mar 2007 11:55:04 -0400 +Subject: fix deadlock in audit_log_task_context() +To: linux-stable +Message-ID: <45FEB258.7060803@redhat.com> + +From: Al Viro + +[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 +Acked-by: James Morris +Cc: Chuck Ebbert +Signed-off-by: Al Viro +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..8c8038b6bff --- /dev/null +++ b/queue-2.6.20/hda-intel-fix-codec-probe-with-ati-controllers.patch @@ -0,0 +1,62 @@ +From stable-bounces@linux.kernel.org Sun Mar 18 15:20:54 2007 +From: Takashi Iwai +Date: Sun, 18 Mar 2007 18:19:29 -0400 +Subject: [ALSA] hda-intel - Fix codec probe with ATI controllers +To: linux-stable +Message-ID: <45FDBAF1.2060408@redhat.com> + +From: Takashi Iwai + +[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 +Signed-off-by: Takashi Iwai +Signed-off-by: Jaroslav Kysela + +--- + 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 index 00000000000..60738556245 --- /dev/null +++ b/queue-2.6.20/input-i8042-fix-aux-irq-delivery-check.patch @@ -0,0 +1,51 @@ +From cebbert@redhat.com Mon Mar 19 07:18:29 2007 +From: Chuck Ebbert +Date: Mon, 19 Mar 2007 09:06:25 -0400 +Subject: Input: i8042 - fix AUX IRQ delivery check +To: Greg KH +Message-ID: <45FE8AD1.1040305@redhat.com> + +From: Dmitry Torokhov + +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 +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman + +--- + 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. 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 index 00000000000..e7323a5e516 --- /dev/null +++ b/queue-2.6.20/input-i8042-really-suppress-ack-nak-during-panic-blink.patch @@ -0,0 +1,52 @@ +From stable-bounces@linux.kernel.org Sun Mar 18 14:42:51 2007 +From: Dmitry Torokhov +Date: Sun, 18 Mar 2007 17:41:28 -0400 +Subject: Input: i8042 - really suppress ACK/NAK during panic blink +To: linux-stable +Message-ID: <45FDB208.90502@redhat.com> + +From: Dmitry Torokhov + +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 +Signed-off-by: Dmitry Torokhov +Signed-off-by: Greg Kroah-Hartman + + +--- + 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 index 00000000000..d87c5a14693 --- /dev/null +++ b/queue-2.6.20/oom-fix-prevent-oom-from-killing-a-process-with-children-sibling-unkillable.patch @@ -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 +Subject: oom fix: prevent oom from killing a process with children/sibling unkillable +To: linux-stable +Message-ID: <45FDC316.60005@redhat.com> + +From: Ankita Garg + +[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 +Cc: Chuck Ebbert +Acked-by: Nick Piggin +Acked-by: William Irwin +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + diff --git a/queue-2.6.20/series b/queue-2.6.20/series index 7aaf2e80a7b..93854009e0e 100644 --- a/queue-2.6.20/series +++ b/queue-2.6.20/series @@ -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 index 00000000000..6663b2f0a81 --- /dev/null +++ b/queue-2.6.20/uml-arch_prctl-should-set-thread-fs.patch @@ -0,0 +1,246 @@ +From jdike@addtoit.com Mon Mar 19 13:16:13 2007 +From: Jeff Dike +Date: Mon, 19 Mar 2007 16:12:50 -0400 +Subject: UML - arch_prctl should set thread fs +To: stable@kernel.org +Cc: Greg KH , uml-devel +Message-ID: <20070319201250.GC12179@c2.user-mode-linux.org> + +From: Jeff Dike + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 ++#include ++ ++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