From b258d645463205dfec79a8fcc10bc77a77bd53f3 Mon Sep 17 00:00:00 2001 From: Ahmed Elaidy Date: Tue, 3 Mar 2026 00:18:14 +0200 Subject: [PATCH] criu: restore timer_slack_ns per thread During restore, set the per-thread timer_slack_ns value via PR_SET_TIMERSLACK if the image contains it. This completes the checkpoint/restore cycle for the timer slack property. The restore is skipped for images that do not contain the field, maintaining backward compatibility with older image formats. Signed-off-by: Ahmed Elaidy --- criu/cr-restore.c | 5 +++++ criu/include/restorer.h | 2 ++ criu/pie/restorer.c | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/criu/cr-restore.c b/criu/cr-restore.c index 957478ce2..4e7bd5e79 100644 --- a/criu/cr-restore.c +++ b/criu/cr-restore.c @@ -3466,6 +3466,11 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns goto err; } + if (tcore->thread_core->has_timerslack_ns) { + thread_args[i].has_timerslack_ns = true; + thread_args[i].timerslack_ns = tcore->thread_core->timerslack_ns; + } + ret = prep_sched_info(&thread_args[i].sp, tcore->thread_core); if (ret) goto err; diff --git a/criu/include/restorer.h b/criu/include/restorer.h index 78da19182..5a141664c 100644 --- a/criu/include/restorer.h +++ b/criu/include/restorer.h @@ -114,6 +114,8 @@ struct thread_restore_args { unsigned int siginfo_n; int pdeath_sig; + bool has_timerslack_ns; + unsigned long timerslack_ns; struct thread_creds_args *creds_args; diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c index 694a5e874..ee7b2c994 100644 --- a/criu/pie/restorer.c +++ b/criu/pie/restorer.c @@ -66,6 +66,10 @@ #define PR_SET_PDEATHSIG 1 #endif +#ifndef PR_SET_TIMERSLACK +#define PR_SET_TIMERSLACK 29 +#endif + #ifndef PR_SET_CHILD_SUBREAPER #define PR_SET_CHILD_SUBREAPER 36 #endif @@ -417,6 +421,22 @@ static inline int restore_pdeath_sig(struct thread_restore_args *ta) return 0; } +static inline int restore_timerslack(struct thread_restore_args *ta) +{ + int ret; + + if (!ta->has_timerslack_ns) + return 0; + + ret = sys_prctl(PR_SET_TIMERSLACK, ta->timerslack_ns, 0, 0, 0); + if (ret) { + pr_err("Unable to set PR_SET_TIMERSLACK(%lu): %d\n", ta->timerslack_ns, ret); + return -1; + } + + return 0; +} + static int restore_dumpable_flag(MmEntry *mme) { int current_dumpable; @@ -830,6 +850,7 @@ __visible long __export_restore_thread(struct thread_restore_args *args) ret = restore_creds(args->creds_args, args->ta->proc_fd, args->ta->lsm_type, args->ta->uid); ret = ret || restore_dumpable_flag(&args->ta->mm); ret = ret || restore_pdeath_sig(args); + ret = ret || restore_timerslack(args); if (ret) BUG(); @@ -2303,6 +2324,7 @@ __visible long __export_restore_task(struct task_restore_args *args) ret = restore_creds(args->t->creds_args, args->proc_fd, args->lsm_type, args->uid); ret = ret || restore_dumpable_flag(&args->mm); ret = ret || restore_pdeath_sig(args->t); + ret = ret || restore_timerslack(args->t); ret = ret || restore_child_subreaper(args->child_subreaper); atomic_set(&thread_inprogress, args->nr_threads);