]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Jun 2012 01:47:30 +0000 (18:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 1 Jun 2012 01:47:30 +0000 (18:47 -0700)
Pull second pile of signal handling patches from Al Viro:
 "This one is just task_work_add() series + remaining prereqs for it.

  There probably will be another pull request from that tree this
  cycle - at least for helpers, to get them out of the way for per-arch
  fixes remaining in the tree."

Fix trivial conflict in kernel/irq/manage.c: the merge of Andrew's pile
had brought in commit 97fd75b7b8e0 ("kernel/irq/manage.c: use the
pr_foo() infrastructure to prefix printks") which changed one of the
pr_err() calls that this merge moves around.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal:
  keys: kill task_struct->replacement_session_keyring
  keys: kill the dummy key_replace_session_keyring()
  keys: change keyctl_session_to_parent() to use task_work_add()
  genirq: reimplement exit_irq_thread() hook via task_work_add()
  task_work_add: generic process-context callbacks
  avr32: missed _TIF_NOTIFY_RESUME on one of do_notify_resume callers
  parisc: need to check NOTIFY_RESUME when exiting from syscall
  move key_repace_session_keyring() into tracehook_notify_resume()
  TIF_NOTIFY_RESUME is defined on all targets now

1  2 
arch/arm/kernel/signal.c
arch/parisc/kernel/entry.S
arch/tile/kernel/process.c
arch/x86/kernel/signal.c
include/linux/sched.h
kernel/Makefile
kernel/exit.c
kernel/fork.c
kernel/irq/manage.c
security/keys/keyctl.c

diff --combined arch/arm/kernel/signal.c
index 17fc36c41cff6c155802fab60e3b04a3b5efd135,ec640412aed05fb488a907e79bbfe5e22e9bceab..63f327dd519814b28a5c092b203e089ec4d732ea
@@@ -29,6 -29,7 +29,6 @@@
   */
  #define SWI_SYS_SIGRETURN     (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
  #define SWI_SYS_RT_SIGRETURN  (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
 -#define SWI_SYS_RESTART               (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)
  
  /*
   * With EABI, the syscall number has to be loaded into r7.
@@@ -48,6 -49,18 +48,6 @@@ const unsigned long sigreturn_codes[7] 
        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
  };
  
 -/*
 - * Either we support OABI only, or we have EABI with the OABI
 - * compat layer enabled.  In the later case we don't know if
 - * user space is EABI or not, and if not we must not clobber r7.
 - * Always using the OABI syscall solves that issue and works for
 - * all those cases.
 - */
 -const unsigned long syscall_restart_code[2] = {
 -      SWI_SYS_RESTART,        /* swi  __NR_restart_syscall */
 -      0xe49df004,             /* ldr  pc, [sp], #4 */
 -};
 -
  /*
   * atomically swap in the new signal mask, and wait for a signal.
   */
@@@ -69,10 -82,10 +69,10 @@@ sys_sigaction(int sig, const struct old
                old_sigset_t mask;
                if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
                    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 -                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
 +                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
 +                  __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
 +                  __get_user(mask, &act->sa_mask))
                        return -EFAULT;
 -              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 -              __get_user(mask, &act->sa_mask);
                siginitset(&new_ka.sa.sa_mask, mask);
        }
  
        if (!ret && oact) {
                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
                    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
 -                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
 +                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
 +                  __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
 +                  __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
                        return -EFAULT;
 -              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 -              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
        }
  
        return ret;
@@@ -588,6 -601,15 +588,6 @@@ static void do_signal(struct pt_regs *r
        siginfo_t info;
        int signr;
  
 -      /*
 -       * We want the common case to go fast, which
 -       * is why we may in certain cases get here from
 -       * kernel mode. Just return without doing anything
 -       * if so.
 -       */
 -      if (!user_mode(regs))
 -              return;
 -
        /*
         * If we were from a system call, check for system call restarting...
         */
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
 +              case -ERESTART_RESTARTBLOCK:
                        regs->ARM_r0 = regs->ARM_ORIG_r0;
                        regs->ARM_pc = restart_addr;
                        break;
 -              case -ERESTART_RESTARTBLOCK:
 -                      regs->ARM_r0 = -EINTR;
 -                      break;
                }
        }
  
 -      if (try_to_freeze())
 -              goto no_signal;
 -
        /*
         * Get the signal to deliver.  When running under ptrace, at this
         * point the debugger may change all our registers ...
                 * debugger has chosen to restart at a different PC.
                 */
                if (regs->ARM_pc == restart_addr) {
 -                      if (retval == -ERESTARTNOHAND
 +                      if (retval == -ERESTARTNOHAND ||
 +                          retval == -ERESTART_RESTARTBLOCK
                            || (retval == -ERESTARTSYS
                                && !(ka.sa.sa_flags & SA_RESTART))) {
                                regs->ARM_r0 = -EINTR;
                                regs->ARM_pc = continue_addr;
                        }
 +                      clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
                }
  
                if (test_thread_flag(TIF_RESTORE_SIGMASK))
                return;
        }
  
 - no_signal:
        if (syscall) {
                /*
                 * Handle restarting a different system call.  As above,
                 * ignore the restart.
                 */
                if (retval == -ERESTART_RESTARTBLOCK
 -                  && regs->ARM_pc == continue_addr) {
 -                      if (thumb_mode(regs)) {
 -                              regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
 -                              regs->ARM_pc -= 2;
 -                      } else {
 -#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
 -                              regs->ARM_r7 = __NR_restart_syscall;
 -                              regs->ARM_pc -= 4;
 -#else
 -                              u32 __user *usp;
 -
 -                              regs->ARM_sp -= 4;
 -                              usp = (u32 __user *)regs->ARM_sp;
 -
 -                              if (put_user(regs->ARM_pc, usp) == 0) {
 -                                      regs->ARM_pc = KERN_RESTART_CODE;
 -                              } else {
 -                                      regs->ARM_sp += 4;
 -                                      force_sigsegv(0, current);
 -                              }
 -#endif
 -                      }
 -              }
 -
 -              /* If there's no signal to deliver, we just put the saved sigmask
 -               * back.
 -               */
 -              if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
 -                      clear_thread_flag(TIF_RESTORE_SIGMASK);
 -                      sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 -              }
 +                  && regs->ARM_pc == restart_addr)
 +                      set_thread_flag(TIF_SYSCALL_RESTARTSYS);
        }
 +
 +      /* If there's no signal to deliver, we just put the saved sigmask
 +       * back.
 +       */
 +      if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
 +              set_current_blocked(&current->saved_sigmask);
  }
  
  asmlinkage void
@@@ -679,7 -728,5 +679,5 @@@ do_notify_resume(struct pt_regs *regs, 
        if (thread_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
-               if (current->replacement_session_keyring)
-                       key_replace_session_keyring();
        }
  }
index 07ef351edd57da0b4fe576a6eed02026b148e890,4f283eaf490741baabf021482d2848ccae5fa963..c7fbc96472f3f9e8ae8013fb72528d9f81d584d8
         * entry (identifying the physical page) and %r23 up with
         * the from tlb entry (or nothing if only a to entry---for
         * clear_user_page_asm) */
 -      .macro          do_alias        spc,tmp,tmp1,va,pte,prot,fault
 +      .macro          do_alias        spc,tmp,tmp1,va,pte,prot,fault,patype
        cmpib,COND(<>),n 0,\spc,\fault
        ldil            L%(TMPALIAS_MAP_START),\tmp
  #if defined(CONFIG_64BIT) && (TMPALIAS_MAP_START >= 0x80000000)
         */
        cmpiclr,=       0x01,\tmp,%r0
        ldi             (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
 -#ifdef CONFIG_64BIT
 +.ifc \patype,20
        depd,z          \prot,8,7,\prot
 -#else
 +.else
 +.ifc \patype,11
        depw,z          \prot,8,7,\prot
 -#endif
 +.else
 +      .error "undefined PA type to do_alias"
 +.endif
 +.endif
        /*
         * OK, it is in the temp alias region, check whether "from" or "to".
         * Check "subtle" note in pacache.S re: r23/r26.
@@@ -1193,7 -1189,7 +1193,7 @@@ dtlb_miss_20w
        nop
  
  dtlb_check_alias_20w:
 -      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault,20
  
        idtlbt          pte,prot
  
@@@ -1217,7 -1213,7 +1217,7 @@@ nadtlb_miss_20w
        nop
  
  nadtlb_check_alias_20w:
 -      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 +      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate,20
  
        idtlbt          pte,prot
  
@@@ -1249,7 -1245,7 +1249,7 @@@ dtlb_miss_11
        nop
  
  dtlb_check_alias_11:
 -      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault,11
  
        idtlba          pte,(va)
        idtlbp          prot,(va)
@@@ -1281,7 -1277,7 +1281,7 @@@ nadtlb_miss_11
        nop
  
  nadtlb_check_alias_11:
 -      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 +      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate,11
  
        idtlba          pte,(va)
        idtlbp          prot,(va)
@@@ -1308,7 -1304,7 +1308,7 @@@ dtlb_miss_20
        nop
  
  dtlb_check_alias_20:
 -      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,dtlb_fault,20
        
        idtlbt          pte,prot
  
@@@ -1334,7 -1330,7 +1334,7 @@@ nadtlb_miss_20
        nop
  
  nadtlb_check_alias_20:
 -      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate
 +      do_alias        spc,t0,t1,va,pte,prot,nadtlb_emulate,20
  
        idtlbt          pte,prot
  
@@@ -1461,7 -1457,7 +1461,7 @@@ naitlb_miss_20w
        nop
  
  naitlb_check_alias_20w:
 -      do_alias        spc,t0,t1,va,pte,prot,naitlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,naitlb_fault,20
  
        iitlbt          pte,prot
  
@@@ -1515,7 -1511,7 +1515,7 @@@ naitlb_miss_11
        nop
  
  naitlb_check_alias_11:
 -      do_alias        spc,t0,t1,va,pte,prot,itlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,itlb_fault,11
  
        iitlba          pte,(%sr0, va)
        iitlbp          prot,(%sr0, va)
@@@ -1561,7 -1557,7 +1561,7 @@@ naitlb_miss_20
        nop
  
  naitlb_check_alias_20:
 -      do_alias        spc,t0,t1,va,pte,prot,naitlb_fault
 +      do_alias        spc,t0,t1,va,pte,prot,naitlb_fault,20
  
        iitlbt          pte,prot
  
@@@ -2032,7 -2028,7 +2032,7 @@@ syscall_check_resched
        .import do_signal,code
  syscall_check_sig:
        LDREG   TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19
-       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26
+       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r26
        and,COND(<>)    %r19, %r26, %r0
        b,n     syscall_restore /* skip past if we've nothing to do */
  
index ba1023d8a0218ca3a33918cf3a256a592a77fb5f,32817ab6062a9d90d41d5fc6a6c47ebbc3e94097..6be7991505019a30ce3ff6268c275a931a088644
@@@ -128,10 -128,10 +128,10 @@@ void arch_release_thread_info(struct th
         * Calling deactivate here just frees up the data structures.
         * If the task we're freeing held the last reference to a
         * hardwall fd, it would have been released prior to this point
 -       * anyway via exit_files(), and "hardwall" would be NULL by now.
 +       * anyway via exit_files(), and the hardwall_task.info pointers
 +       * would be NULL by now.
         */
 -      if (info->task->thread.hardwall)
 -              hardwall_deactivate(info->task);
 +      hardwall_deactivate_all(info->task);
  #endif
  
        if (step_state) {
@@@ -245,8 -245,7 +245,8 @@@ int copy_thread(unsigned long clone_fla
  
  #ifdef CONFIG_HARDWALL
        /* New thread does not own any networks. */
 -      p->thread.hardwall = NULL;
 +      memset(&p->thread.hardwall[0], 0,
 +             sizeof(struct hardwall_task) * HARDWALL_TYPES);
  #endif
  
  
@@@ -516,7 -515,12 +516,7 @@@ struct task_struct *__sched _switch_to(
  
  #ifdef CONFIG_HARDWALL
        /* Enable or disable access to the network registers appropriately. */
 -      if (prev->thread.hardwall != NULL) {
 -              if (next->thread.hardwall == NULL)
 -                      restrict_network_mpls();
 -      } else if (next->thread.hardwall != NULL) {
 -              grant_network_mpls();
 -      }
 +      hardwall_switch_tasks(prev, next);
  #endif
  
        /*
@@@ -565,8 -569,6 +565,6 @@@ int do_work_pending(struct pt_regs *reg
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
-               if (current->replacement_session_keyring)
-                       key_replace_session_keyring();
                return 1;
        }
        if (thread_info_flags & _TIF_SINGLESTEP) {
diff --combined arch/x86/kernel/signal.c
index 965dfda0fd5e442fa88a13e5aeff0a9b98e73029,9363b58b967cf4fb0cdf17deabbef6b5f9c1c1e7..2e937a5ad53154b4ff3a047e181894ec1a44633e
@@@ -18,7 -18,6 +18,7 @@@
  #include <linux/personality.h>
  #include <linux/uaccess.h>
  #include <linux/user-return-notifier.h>
 +#include <linux/uprobes.h>
  
  #include <asm/processor.h>
  #include <asm/ucontext.h>
@@@ -815,11 -814,6 +815,11 @@@ do_notify_resume(struct pt_regs *regs, 
                mce_notify_process();
  #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
  
 +      if (thread_info_flags & _TIF_UPROBE) {
 +              clear_thread_flag(TIF_UPROBE);
 +              uprobe_notify_resume(regs);
 +      }
 +
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
-               if (current->replacement_session_keyring)
-                       key_replace_session_keyring();
        }
        if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)
                fire_user_return_notifiers();
diff --combined include/linux/sched.h
index f45c0b280b5d39873aaca3a3d67b1a01362adba8,17c6c929ee9421084484d31f17a19dafad142944..660c8ae93471cfb1a150936fda19e8f5a0945ef8
@@@ -1301,11 -1301,6 +1301,6 @@@ struct task_struct 
        unsigned sched_reset_on_fork:1;
        unsigned sched_contributes_to_load:1;
  
- #ifdef CONFIG_GENERIC_HARDIRQS
-       /* IRQ handler threads */
-       unsigned irq_thread:1;
- #endif
        pid_t pid;
        pid_t tgid;
  
        /* Canary value for the -fstack-protector gcc feature */
        unsigned long stack_canary;
  #endif
-       /* 
+       /*
         * pointers to (original) parent process, youngest child, younger sibling,
-        * older sibling, respectively.  (p->father can be replaced with 
+        * older sibling, respectively.  (p->father can be replaced with
         * p->real_parent->pid)
         */
        struct task_struct __rcu *real_parent; /* real parent process */
                                         * credentials (COW) */
        const struct cred __rcu *cred;  /* effective (overridable) subjective task
                                         * credentials (COW) */
-       struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */
        char comm[TASK_COMM_LEN]; /* executable name excluding path
                                     - access with [gs]et_task_comm (which lock
                                       it with task_lock())
        int (*notifier)(void *priv);
        void *notifier_data;
        sigset_t *notifier_mask;
+       struct hlist_head task_works;
        struct audit_context *audit_context;
  #ifdef CONFIG_AUDITSYSCALL
        uid_t loginuid;
  #ifdef CONFIG_HAVE_HW_BREAKPOINT
        atomic_t ptrace_bp_refcnt;
  #endif
 +#ifdef CONFIG_UPROBES
 +      struct uprobe_task *utask;
 +      int uprobe_srcu_id;
 +#endif
  };
  
  /* Future-safe accessor for struct task_struct's cpus_allowed. */
diff --combined kernel/Makefile
index 80be6ca0cc753c3bd8ff4c8b6dba71dca8f07657,bf1034008acae4a7a8881366c34ca652bb571186..6f3d0ae044b24769c1caa61346174bc44a3684bc
@@@ -5,7 -5,7 +5,7 @@@
  obj-y     = fork.o exec_domain.o panic.o printk.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
            sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
-           signal.o sys.o kmod.o workqueue.o pid.o \
+           signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
            rcupdate.o extable.o params.o posix-timers.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
@@@ -25,9 -25,6 +25,9 @@@ endi
  obj-y += sched/
  obj-y += power/
  
 +ifeq ($(CONFIG_CHECKPOINT_RESTORE),y)
 +obj-$(CONFIG_X86) += kcmp.o
 +endif
  obj-$(CONFIG_FREEZER) += freezer.o
  obj-$(CONFIG_PROFILING) += profile.o
  obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --combined kernel/exit.c
index 6d85655353e919fd56e0d2cc65cb36862e328a8c,3ecd096e5d4d728a6bfe79d4d39e9776a101ad4e..34867cc5b42a77f325c204bb2fd09e1fabe38955
@@@ -884,9 -884,9 +884,9 @@@ static void check_stack_usage(void
  
        spin_lock(&low_water_lock);
        if (free < lowest_to_date) {
 -              printk(KERN_WARNING "%s used greatest stack depth: %lu bytes "
 -                              "left\n",
 -                              current->comm, free);
 +              printk(KERN_WARNING "%s (%d) used greatest stack depth: "
 +                              "%lu bytes left\n",
 +                              current->comm, task_pid_nr(current), free);
                lowest_to_date = free;
        }
        spin_unlock(&low_water_lock);
@@@ -946,12 -946,13 +946,13 @@@ void do_exit(long code
        exit_signals(tsk);  /* sets PF_EXITING */
        /*
         * tsk->flags are checked in the futex code to protect against
-        * an exiting task cleaning up the robust pi futexes.
+        * an exiting task cleaning up the robust pi futexes, and in
+        * task_work_add() to avoid the race with exit_task_work().
         */
        smp_mb();
        raw_spin_unlock_wait(&tsk->pi_lock);
  
-       exit_irq_thread();
+       exit_task_work(tsk);
  
        if (unlikely(in_atomic()))
                printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
@@@ -1214,7 -1215,7 +1215,7 @@@ static int wait_task_zombie(struct wait
        unsigned long state;
        int retval, status, traced;
        pid_t pid = task_pid_vnr(p);
 -      uid_t uid = from_kuid_munged(current_user_ns(), __task_cred(p)->uid);
 +      uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
        struct siginfo __user *infop;
  
        if (!likely(wo->wo_flags & WEXITED))
diff --combined kernel/fork.c
index c55b61ab6d646c0dbbd3d9042bdc4da8405e1f38,a46db217a589add818e4b136fbffe80ca8841b13..ab5211b9e622cf94d07b7bfb4ccfd9bac85e7b79
@@@ -69,7 -69,6 +69,7 @@@
  #include <linux/oom.h>
  #include <linux/khugepaged.h>
  #include <linux/signalfd.h>
 +#include <linux/uprobes.h>
  
  #include <asm/pgtable.h>
  #include <asm/pgalloc.h>
@@@ -386,8 -385,7 +386,8 @@@ static int dup_mmap(struct mm_struct *m
                }
                charge = 0;
                if (mpnt->vm_flags & VM_ACCOUNT) {
 -                      unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 +                      unsigned long len;
 +                      len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
                        if (security_vm_enough_memory_mm(oldmm, len)) /* sic */
                                goto fail_nomem;
                        charge = len;
  
                if (retval)
                        goto out;
 +
 +              if (file && uprobe_mmap(tmp))
 +                      goto out;
        }
        /* a new mm has just been created */
        arch_dup_mmap(oldmm, mm);
@@@ -604,7 -599,6 +604,7 @@@ void mmput(struct mm_struct *mm
        might_sleep();
  
        if (atomic_dec_and_test(&mm->mm_users)) {
 +              uprobe_clear_state(mm);
                exit_aio(mm);
                ksm_exit(mm);
                khugepaged_exit(mm); /* must run before exit_mmap */
                        list_del(&mm->mmlist);
                        spin_unlock(&mmlist_lock);
                }
 -              put_swap_token(mm);
                if (mm->binfmt)
                        module_put(mm->binfmt->module);
                mmdrop(mm);
@@@ -782,11 -777,12 +782,11 @@@ void mm_release(struct task_struct *tsk
                exit_pi_state_list(tsk);
  #endif
  
 +      uprobe_free_utask(tsk);
 +
        /* Get rid of any cached register state */
        deactivate_mm(tsk, mm);
  
 -      if (tsk->vfork_done)
 -              complete_vfork_done(tsk);
 -
        /*
         * If we're exiting normally, clear a user-space tid field if
         * requested.  We leave this alone when dying by signal, to leave
                }
                tsk->clear_child_tid = NULL;
        }
 +
 +      /*
 +       * All done, finally we can wake up parent and return this mm to him.
 +       * Also kthread_stop() uses this completion for synchronization.
 +       */
 +      if (tsk->vfork_done)
 +              complete_vfork_done(tsk);
  }
  
  /*
@@@ -835,10 -824,13 +835,10 @@@ struct mm_struct *dup_mm(struct task_st
        memcpy(mm, oldmm, sizeof(*mm));
        mm_init_cpumask(mm);
  
 -      /* Initializing for Swap token stuff */
 -      mm->token_priority = 0;
 -      mm->last_interval = 0;
 -
  #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        mm->pmd_huge_pte = NULL;
  #endif
 +      uprobe_reset_state(mm);
  
        if (!mm_init(mm, tsk))
                goto fail_nomem;
@@@ -913,6 -905,10 +913,6 @@@ static int copy_mm(unsigned long clone_
                goto fail_nomem;
  
  good_mm:
 -      /* Initializing for Swap token stuff */
 -      mm->token_priority = 0;
 -      mm->last_interval = 0;
 -
        tsk->mm = mm;
        tsk->active_mm = mm;
        return 0;
@@@ -980,8 -976,9 +980,8 @@@ static int copy_io(unsigned long clone_
         * Share io context with parent, if CLONE_IO is set
         */
        if (clone_flags & CLONE_IO) {
 -              tsk->io_context = ioc_task_link(ioc);
 -              if (unlikely(!tsk->io_context))
 -                      return -ENOMEM;
 +              ioc_task_link(ioc);
 +              tsk->io_context = ioc;
        } else if (ioprio_valid(ioc->ioprio)) {
                new_ioc = get_task_io_context(tsk, GFP_KERNEL, NUMA_NO_NODE);
                if (unlikely(!new_ioc))
@@@ -1376,7 -1373,6 +1376,7 @@@ static struct task_struct *copy_process
        INIT_LIST_HEAD(&p->pi_state_list);
        p->pi_state_cache = NULL;
  #endif
 +      uprobe_copy_process(p);
        /*
         * sigaltstack should be cleared when sharing the same VM
         */
         */
        p->group_leader = p;
        INIT_LIST_HEAD(&p->thread_group);
+       INIT_HLIST_HEAD(&p->task_works);
  
        /* Now that the task is set up, run cgroup callbacks if
         * necessary. We need to run them before the task is visible
diff --combined kernel/irq/manage.c
index 7c475cd3f6e69800126548aa46c78d4e59d92e03,4d1f8f897414e64bc5abaff664138956a5bbcf47..ea0c6c2ae6f747d0bd8dff198e5e1f6b6934f050
@@@ -7,8 -7,6 +7,8 @@@
   * This file contains driver APIs to the irq subsystem.
   */
  
 +#define pr_fmt(fmt) "genirq: " fmt
 +
  #include <linux/irq.h>
  #include <linux/kthread.h>
  #include <linux/module.h>
@@@ -16,6 -14,7 +16,7 @@@
  #include <linux/interrupt.h>
  #include <linux/slab.h>
  #include <linux/sched.h>
+ #include <linux/task_work.h>
  
  #include "internals.h"
  
@@@ -567,7 -566,7 +568,7 @@@ int __irq_set_trigger(struct irq_desc *
                 * IRQF_TRIGGER_* but the PIC does not support multiple
                 * flow-types?
                 */
 -              pr_debug("genirq: No set_type function for IRQ %d (%s)\n", irq,
 +              pr_debug("No set_type function for IRQ %d (%s)\n", irq,
                         chip ? (chip->name ? : "unknown") : "unknown");
                return 0;
        }
                ret = 0;
                break;
        default:
 -              pr_err("genirq: Setting trigger mode %lu for irq %u failed (%pF)\n",
 +              pr_err("Setting trigger mode %lu for irq %u failed (%pF)\n",
                       flags, irq, chip->irq_set_type);
        }
        if (unmask)
@@@ -775,11 -774,39 +776,39 @@@ static void wake_threads_waitq(struct i
                wake_up(&desc->wait_for_threads);
  }
  
 -      pr_err("genirq: exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
+ static void irq_thread_dtor(struct task_work *unused)
+ {
+       struct task_struct *tsk = current;
+       struct irq_desc *desc;
+       struct irqaction *action;
+       if (WARN_ON_ONCE(!(current->flags & PF_EXITING)))
+               return;
+       action = kthread_data(tsk);
++      pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
+              tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
+       desc = irq_to_desc(action->irq);
+       /*
+        * If IRQTF_RUNTHREAD is set, we need to decrement
+        * desc->threads_active and wake possible waiters.
+        */
+       if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
+               wake_threads_waitq(desc);
+       /* Prevent a stale desc->threads_oneshot */
+       irq_finalize_oneshot(desc, action);
+ }
  /*
   * Interrupt handler thread
   */
  static int irq_thread(void *data)
  {
+       struct task_work on_exit_work;
        static const struct sched_param param = {
                .sched_priority = MAX_USER_RT_PRIO/2,
        };
                handler_fn = irq_thread_fn;
  
        sched_setscheduler(current, SCHED_FIFO, &param);
-       current->irq_thread = 1;
+       init_task_work(&on_exit_work, irq_thread_dtor, NULL);
+       task_work_add(current, &on_exit_work, false);
  
        while (!irq_wait_for_interrupt(action)) {
                irqreturn_t action_ret;
         * cannot touch the oneshot mask at this point anymore as
         * __setup_irq() might have given out currents thread_mask
         * again.
-        *
-        * Clear irq_thread. Otherwise exit_irq_thread() would make
-        * fuzz about an active irq thread going into nirvana.
         */
-       current->irq_thread = 0;
+       task_work_cancel(current, irq_thread_dtor);
        return 0;
  }
  
- /*
-  * Called from do_exit()
-  */
- void exit_irq_thread(void)
- {
-       struct task_struct *tsk = current;
-       struct irq_desc *desc;
-       struct irqaction *action;
-       if (!tsk->irq_thread)
-               return;
-       action = kthread_data(tsk);
-       pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
-              tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
-       desc = irq_to_desc(action->irq);
-       /*
-        * If IRQTF_RUNTHREAD is set, we need to decrement
-        * desc->threads_active and wake possible waiters.
-        */
-       if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags))
-               wake_threads_waitq(desc);
-       /* Prevent a stale desc->threads_oneshot */
-       irq_finalize_oneshot(desc, action);
- }
  static void irq_setup_forced_threading(struct irqaction *new)
  {
        if (!force_irqthreads)
@@@ -1046,7 -1042,7 +1044,7 @@@ __setup_irq(unsigned int irq, struct ir
                 * has. The type flags are unreliable as the
                 * underlying chip implementation can override them.
                 */
 -              pr_err("genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
 +              pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n",
                       irq);
                ret = -EINVAL;
                goto out_mask;
  
                if (nmsk != omsk)
                        /* hope the handler works with current  trigger mode */
 -                      pr_warning("genirq: irq %d uses trigger mode %u; requested %u\n",
 +                      pr_warning("irq %d uses trigger mode %u; requested %u\n",
                                   irq, nmsk, omsk);
        }
  
  
  mismatch:
        if (!(new->flags & IRQF_PROBE_SHARED)) {
 -              pr_err("genirq: Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
 +              pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n",
                       irq, new->flags, new->name, old->flags, old->name);
  #ifdef CONFIG_DEBUG_SHIRQ
                dump_stack();
diff --combined security/keys/keyctl.c
index 21907ea35b15c118515eb03dea87efab7f8ad9f8,2f28126215a224ce6dc1ecb56b4cb337f39c30f5..0f5b3f0272995dc7057f1306c346468174d3e464
@@@ -84,7 -84,7 +84,7 @@@ SYSCALL_DEFINE5(add_key, const char __u
        vm = false;
        if (_payload) {
                ret = -ENOMEM;
 -              payload = kmalloc(plen, GFP_KERNEL);
 +              payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
                if (!payload) {
                        if (plen <= PAGE_SIZE)
                                goto error2;
@@@ -1110,7 -1110,7 +1110,7 @@@ long keyctl_instantiate_key_iov(key_ser
                goto no_payload;
  
        ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
 -                                  ARRAY_SIZE(iovstack), iovstack, &iov, 1);
 +                                  ARRAY_SIZE(iovstack), iovstack, &iov);
        if (ret < 0)
                return ret;
        if (ret == 0)
@@@ -1454,50 -1454,57 +1454,57 @@@ long keyctl_get_security(key_serial_t k
   */
  long keyctl_session_to_parent(void)
  {
- #ifdef TIF_NOTIFY_RESUME
        struct task_struct *me, *parent;
        const struct cred *mycred, *pcred;
-       struct cred *cred, *oldcred;
+       struct task_work *newwork, *oldwork;
        key_ref_t keyring_r;
+       struct cred *cred;
        int ret;
  
        keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
        if (IS_ERR(keyring_r))
                return PTR_ERR(keyring_r);
  
+       ret = -ENOMEM;
+       newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
+       if (!newwork)
+               goto error_keyring;
        /* our parent is going to need a new cred struct, a new tgcred struct
         * and new security data, so we allocate them here to prevent ENOMEM in
         * our parent */
-       ret = -ENOMEM;
        cred = cred_alloc_blank();
        if (!cred)
-               goto error_keyring;
+               goto error_newwork;
  
        cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
-       keyring_r = NULL;
+       init_task_work(newwork, key_change_session_keyring, cred);
  
        me = current;
        rcu_read_lock();
        write_lock_irq(&tasklist_lock);
  
-       parent = me->real_parent;
        ret = -EPERM;
+       oldwork = NULL;
+       parent = me->real_parent;
  
        /* the parent mustn't be init and mustn't be a kernel thread */
        if (parent->pid <= 1 || !parent->mm)
-               goto not_permitted;
+               goto unlock;
  
        /* the parent must be single threaded */
        if (!thread_group_empty(parent))
-               goto not_permitted;
+               goto unlock;
  
        /* the parent and the child must have different session keyrings or
         * there's no point */
        mycred = current_cred();
        pcred = __task_cred(parent);
        if (mycred == pcred ||
-           mycred->tgcred->session_keyring == pcred->tgcred->session_keyring)
-               goto already_same;
+           mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) {
+               ret = 0;
+               goto unlock;
+       }
  
        /* the parent must have the same effective ownership and mustn't be
         * SUID/SGID */
            pcred->gid  != mycred->egid ||
            pcred->egid != mycred->egid ||
            pcred->sgid != mycred->egid)
-               goto not_permitted;
+               goto unlock;
  
        /* the keyrings must have the same UID */
        if ((pcred->tgcred->session_keyring &&
             pcred->tgcred->session_keyring->uid != mycred->euid) ||
            mycred->tgcred->session_keyring->uid != mycred->euid)
-               goto not_permitted;
+               goto unlock;
  
-       /* if there's an already pending keyring replacement, then we replace
-        * that */
-       oldcred = parent->replacement_session_keyring;
+       /* cancel an already pending keyring replacement */
+       oldwork = task_work_cancel(parent, key_change_session_keyring);
  
        /* the replacement session keyring is applied just prior to userspace
         * restarting */
-       parent->replacement_session_keyring = cred;
-       cred = NULL;
-       set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME);
+       ret = task_work_add(parent, newwork, true);
+       if (!ret)
+               newwork = NULL;
+ unlock:
        write_unlock_irq(&tasklist_lock);
        rcu_read_unlock();
-       if (oldcred)
-               put_cred(oldcred);
-       return 0;
- already_same:
-       ret = 0;
- not_permitted:
-       write_unlock_irq(&tasklist_lock);
-       rcu_read_unlock();
-       put_cred(cred);
+       if (oldwork) {
+               put_cred(oldwork->data);
+               kfree(oldwork);
+       }
+       if (newwork) {
+               put_cred(newwork->data);
+               kfree(newwork);
+       }
        return ret;
  
+ error_newwork:
+       kfree(newwork);
  error_keyring:
        key_ref_put(keyring_r);
        return ret;
- #else /* !TIF_NOTIFY_RESUME */
-       /*
-        * To be removed when TIF_NOTIFY_RESUME has been implemented on
-        * m68k/xtensa
-        */
- #warning TIF_NOTIFY_RESUME not implemented
-       return -EOPNOTSUPP;
- #endif /* !TIF_NOTIFY_RESUME */
  }
  
  /*