rseq: Introduce restartable sequences system call
[linux-2.6-block.git] / include / linux / sched.h
index 14e4f9c123371e70eb75ce1b3ba1dbfe5ff2c6f8..3aa4fcb74e761dfda361f17d09593ecd9c361646 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/signal_types.h>
 #include <linux/mm_types_task.h>
 #include <linux/task_io_accounting.h>
+#include <linux/rseq.h>
 
 /* task_struct member predeclarations (sorted alphabetically): */
 struct audit_context;
@@ -1047,6 +1048,17 @@ struct task_struct {
        unsigned long                   numa_pages_migrated;
 #endif /* CONFIG_NUMA_BALANCING */
 
+#ifdef CONFIG_RSEQ
+       struct rseq __user *rseq;
+       u32 rseq_len;
+       u32 rseq_sig;
+       /*
+        * RmW on rseq_event_mask must be performed atomically
+        * with respect to preemption.
+        */
+       unsigned long rseq_event_mask;
+#endif
+
        struct tlbflush_unmap_batch     tlb_ubc;
 
        struct rcu_head                 rcu;
@@ -1757,4 +1769,126 @@ extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
 #define TASK_SIZE_OF(tsk)      TASK_SIZE
 #endif
 
+#ifdef CONFIG_RSEQ
+
+/*
+ * Map the event mask on the user-space ABI enum rseq_cs_flags
+ * for direct mask checks.
+ */
+enum rseq_event_mask_bits {
+       RSEQ_EVENT_PREEMPT_BIT  = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT,
+       RSEQ_EVENT_SIGNAL_BIT   = RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT,
+       RSEQ_EVENT_MIGRATE_BIT  = RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT,
+};
+
+enum rseq_event_mask {
+       RSEQ_EVENT_PREEMPT      = (1U << RSEQ_EVENT_PREEMPT_BIT),
+       RSEQ_EVENT_SIGNAL       = (1U << RSEQ_EVENT_SIGNAL_BIT),
+       RSEQ_EVENT_MIGRATE      = (1U << RSEQ_EVENT_MIGRATE_BIT),
+};
+
+static inline void rseq_set_notify_resume(struct task_struct *t)
+{
+       if (t->rseq)
+               set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
+}
+
+void __rseq_handle_notify_resume(struct pt_regs *regs);
+
+static inline void rseq_handle_notify_resume(struct pt_regs *regs)
+{
+       if (current->rseq)
+               __rseq_handle_notify_resume(regs);
+}
+
+static inline void rseq_signal_deliver(struct pt_regs *regs)
+{
+       preempt_disable();
+       __set_bit(RSEQ_EVENT_SIGNAL_BIT, &current->rseq_event_mask);
+       preempt_enable();
+       rseq_handle_notify_resume(regs);
+}
+
+/* rseq_preempt() requires preemption to be disabled. */
+static inline void rseq_preempt(struct task_struct *t)
+{
+       __set_bit(RSEQ_EVENT_PREEMPT_BIT, &t->rseq_event_mask);
+       rseq_set_notify_resume(t);
+}
+
+/* rseq_migrate() requires preemption to be disabled. */
+static inline void rseq_migrate(struct task_struct *t)
+{
+       __set_bit(RSEQ_EVENT_MIGRATE_BIT, &t->rseq_event_mask);
+       rseq_set_notify_resume(t);
+}
+
+/*
+ * If parent process has a registered restartable sequences area, the
+ * child inherits. Only applies when forking a process, not a thread. In
+ * case a parent fork() in the middle of a restartable sequence, set the
+ * resume notifier to force the child to retry.
+ */
+static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags)
+{
+       if (clone_flags & CLONE_THREAD) {
+               t->rseq = NULL;
+               t->rseq_len = 0;
+               t->rseq_sig = 0;
+               t->rseq_event_mask = 0;
+       } else {
+               t->rseq = current->rseq;
+               t->rseq_len = current->rseq_len;
+               t->rseq_sig = current->rseq_sig;
+               t->rseq_event_mask = current->rseq_event_mask;
+               rseq_preempt(t);
+       }
+}
+
+static inline void rseq_execve(struct task_struct *t)
+{
+       t->rseq = NULL;
+       t->rseq_len = 0;
+       t->rseq_sig = 0;
+       t->rseq_event_mask = 0;
+}
+
+#else
+
+static inline void rseq_set_notify_resume(struct task_struct *t)
+{
+}
+static inline void rseq_handle_notify_resume(struct pt_regs *regs)
+{
+}
+static inline void rseq_signal_deliver(struct pt_regs *regs)
+{
+}
+static inline void rseq_preempt(struct task_struct *t)
+{
+}
+static inline void rseq_migrate(struct task_struct *t)
+{
+}
+static inline void rseq_fork(struct task_struct *t, unsigned long clone_flags)
+{
+}
+static inline void rseq_execve(struct task_struct *t)
+{
+}
+
+#endif
+
+#ifdef CONFIG_DEBUG_RSEQ
+
+void rseq_syscall(struct pt_regs *regs);
+
+#else
+
+static inline void rseq_syscall(struct pt_regs *regs)
+{
+}
+
+#endif
+
 #endif