Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rseq, virt: Retrigger RSEQ after vcpu_run()

Hypervisors invoke resume_user_mode_work() before entering the guest, which
clears TIF_NOTIFY_RESUME. The @regs argument is NULL as there is no user
space context available to them, so the rseq notify handler skips
inspecting the critical section, but updates the CPU/MM CID values
unconditionally so that the eventual pending rseq event is not lost on the
way to user space.

This is a pointless exercise as the task might be rescheduled before
actually returning to user space and it creates unnecessary work in the
vcpu_run() loops.

It's way more efficient to ignore that invocation based on @regs == NULL
and let the hypervisors re-raise TIF_NOTIFY_RESUME after returning from the
vcpu_run() loop before returning from the ioctl().

This ensures that a pending RSEQ update is not lost and the IDs are updated
before returning to user space.

Once the RSEQ handling is decoupled from TIF_NOTIFY_RESUME, this turns into
a NOOP.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Sean Christopherson <seanjc@google.com>
Link: https://patch.msgid.link/20251027084306.399495855@linutronix.de

authored by

Thomas Gleixner and committed by
Ingo Molnar
83409986 d923739e

+68 -37
+3
drivers/hv/mshv_root_main.c
··· 29 29 #include <linux/crash_dump.h> 30 30 #include <linux/panic_notifier.h> 31 31 #include <linux/vmalloc.h> 32 + #include <linux/rseq.h> 32 33 33 34 #include "mshv_eventfd.h" 34 35 #include "mshv.h" ··· 560 559 vp->run.flags.intercept_suspend = 1; 561 560 } 562 561 } while (!vp->run.flags.intercept_suspend); 562 + 563 + rseq_virt_userspace_exit(); 563 564 564 565 return ret; 565 566 }
+17
include/linux/rseq.h
··· 38 38 } 39 39 40 40 /* 41 + * KVM/HYPERV invoke resume_user_mode_work() before entering guest mode, 42 + * which clears TIF_NOTIFY_RESUME. To avoid updating user space RSEQ in 43 + * that case just to do it eventually again before returning to user space, 44 + * the entry resume_user_mode_work() invocation is ignored as the register 45 + * argument is NULL. 46 + * 47 + * After returning from guest mode, they have to invoke this function to 48 + * re-raise TIF_NOTIFY_RESUME if necessary. 49 + */ 50 + static inline void rseq_virt_userspace_exit(void) 51 + { 52 + if (current->rseq_event_pending) 53 + set_tsk_thread_flag(current, TIF_NOTIFY_RESUME); 54 + } 55 + 56 + /* 41 57 * If parent process has a registered restartable sequences area, the 42 58 * child inherits. Unregister rseq for a clone with CLONE_VM set. 43 59 */ ··· 84 68 static inline void rseq_handle_notify_resume(struct pt_regs *regs) { } 85 69 static inline void rseq_signal_deliver(struct ksignal *ksig, struct pt_regs *regs) { } 86 70 static inline void rseq_sched_switch_event(struct task_struct *t) { } 71 + static inline void rseq_virt_userspace_exit(void) { } 87 72 static inline void rseq_fork(struct task_struct *t, u64 clone_flags) { } 88 73 static inline void rseq_execve(struct task_struct *t) { } 89 74 static inline void rseq_exit_to_user_mode(void) { }
+41 -37
kernel/rseq.c
··· 422 422 { 423 423 struct task_struct *t = current; 424 424 int ret, sig; 425 + bool event; 426 + 427 + /* 428 + * If invoked from hypervisors before entering the guest via 429 + * resume_user_mode_work(), then @regs is a NULL pointer. 430 + * 431 + * resume_user_mode_work() clears TIF_NOTIFY_RESUME and re-raises 432 + * it before returning from the ioctl() to user space when 433 + * rseq_event.sched_switch is set. 434 + * 435 + * So it's safe to ignore here instead of pointlessly updating it 436 + * in the vcpu_run() loop. 437 + */ 438 + if (!regs) 439 + return; 425 440 426 441 if (unlikely(t->flags & PF_EXITING)) 427 442 return; 428 443 429 444 /* 430 - * If invoked from hypervisors or IO-URING, then @regs is a NULL 431 - * pointer, so fixup cannot be done. If the syscall which led to 432 - * this invocation was invoked inside a critical section, then it 433 - * will either end up in this code again or a possible violation of 434 - * a syscall inside a critical region can only be detected by the 435 - * debug code in rseq_syscall() in a debug enabled kernel. 445 + * Read and clear the event pending bit first. If the task 446 + * was not preempted or migrated or a signal is on the way, 447 + * there is no point in doing any of the heavy lifting here 448 + * on production kernels. In that case TIF_NOTIFY_RESUME 449 + * was raised by some other functionality. 450 + * 451 + * This is correct because the read/clear operation is 452 + * guarded against scheduler preemption, which makes it CPU 453 + * local atomic. If the task is preempted right after 454 + * re-enabling preemption then TIF_NOTIFY_RESUME is set 455 + * again and this function is invoked another time _before_ 456 + * the task is able to return to user mode. 457 + * 458 + * On a debug kernel, invoke the fixup code unconditionally 459 + * with the result handed in to allow the detection of 460 + * inconsistencies. 436 461 */ 437 - if (regs) { 438 - /* 439 - * Read and clear the event pending bit first. If the task 440 - * was not preempted or migrated or a signal is on the way, 441 - * there is no point in doing any of the heavy lifting here 442 - * on production kernels. In that case TIF_NOTIFY_RESUME 443 - * was raised by some other functionality. 444 - * 445 - * This is correct because the read/clear operation is 446 - * guarded against scheduler preemption, which makes it CPU 447 - * local atomic. If the task is preempted right after 448 - * re-enabling preemption then TIF_NOTIFY_RESUME is set 449 - * again and this function is invoked another time _before_ 450 - * the task is able to return to user mode. 451 - * 452 - * On a debug kernel, invoke the fixup code unconditionally 453 - * with the result handed in to allow the detection of 454 - * inconsistencies. 455 - */ 456 - bool event; 457 - 458 - scoped_guard(RSEQ_EVENT_GUARD) { 459 - event = t->rseq_event_pending; 460 - t->rseq_event_pending = false; 461 - } 462 - 463 - if (IS_ENABLED(CONFIG_DEBUG_RSEQ) || event) { 464 - ret = rseq_ip_fixup(regs, event); 465 - if (unlikely(ret < 0)) 466 - goto error; 467 - } 462 + scoped_guard(RSEQ_EVENT_GUARD) { 463 + event = t->rseq_event_pending; 464 + t->rseq_event_pending = false; 468 465 } 466 + 467 + if (IS_ENABLED(CONFIG_DEBUG_RSEQ) || event) { 468 + ret = rseq_ip_fixup(regs, event); 469 + if (unlikely(ret < 0)) 470 + goto error; 471 + } 472 + 469 473 if (unlikely(rseq_update_cpu_node_id(t))) 470 474 goto error; 471 475 return;
+7
virt/kvm/kvm_main.c
··· 49 49 #include <linux/lockdep.h> 50 50 #include <linux/kthread.h> 51 51 #include <linux/suspend.h> 52 + #include <linux/rseq.h> 52 53 53 54 #include <asm/processor.h> 54 55 #include <asm/ioctl.h> ··· 4476 4475 vcpu->wants_to_run = !READ_ONCE(vcpu->run->immediate_exit__unsafe); 4477 4476 r = kvm_arch_vcpu_ioctl_run(vcpu); 4478 4477 vcpu->wants_to_run = false; 4478 + 4479 + /* 4480 + * FIXME: Remove this hack once all KVM architectures 4481 + * support the generic TIF bits, i.e. a dedicated TIF_RSEQ. 4482 + */ 4483 + rseq_virt_userspace_exit(); 4479 4484 4480 4485 trace_kvm_userspace_exit(vcpu->run->exit_reason, r); 4481 4486 break;