Restartable sequences: clear rseq_cs even if non-nested
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sun, 16 Oct 2016 06:16:25 +0000 (08:16 +0200)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 21 Oct 2016 22:28:17 +0000 (18:28 -0400)
We can speed up the user-space fast path by removing the final
"rseq_cs=NULL" assignment at the end of the critical section, since we
check for both upper and lower bounds anyway in the fixup code.

Take care of setting rseq_cs back to NULL even if we are not nested over
an actual rseq critical section.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
kernel/rseq.c

index a102fcc9994e4680dc812e827d9ffe531f5348e7..a24da12e6b08f6d893677f8c35129136a7970931 100644 (file)
@@ -160,6 +160,17 @@ static bool rseq_get_rseq_cs(struct task_struct *t,
        urseq_cs = (struct rseq_cs __user *)ptr;
        if (copy_from_user(&rseq_cs, urseq_cs, sizeof(rseq_cs)))
                return false;
+       /*
+        * We need to clear rseq_cs upon entry into a signal handler
+        * nested on top of a rseq assembly block, so the signal handler
+        * will not be fixed up if itself interrupted by a nested signal
+        * handler or preempted.  We also need to clear rseq_cs if we
+        * preempt or deliver a signal on top of code outside of the
+        * rseq assembly block, to ensure that a following preemption or
+        * signal delivery will not try to perform a fixup needlessly.
+        */
+       if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs)))
+               return false;
        *start_ip = (void __user *)rseq_cs.start_ip;
        *post_commit_ip = (void __user *)rseq_cs.post_commit_ip;
        *abort_ip = (void __user *)rseq_cs.abort_ip;
@@ -186,15 +197,6 @@ static bool rseq_ip_fixup(struct pt_regs *regs)
                        (void __user *)instruction_pointer(regs) < start_ip)
                return true;
 
-       /*
-        * We need to clear rseq_cs upon entry into a signal
-        * handler nested on top of a rseq assembly block, so
-        * the signal handler will not be fixed up if itself
-        * interrupted by a nested signal handler or preempted.
-        */
-       if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs)))
-               return false;
-
        /*
         * We set this after potentially failing in
         * clear_user so that the signal arrives at the
This page took 0.033143 seconds and 5 git commands to generate.