mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
dump+restore: Implement membarrier() registration c/r.
Note: Silently drops MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED as it's not currently detectable. This is still better than silently dropping all membarrier() registrations. Signed-off-by: Michał Mirosław <emmir@google.com>
This commit is contained in:
parent
5b790aa181
commit
e07155e194
@ -122,3 +122,4 @@ pidfd_open 434 434 (pid_t pid, unsigned int flags)
|
||||
openat2 437 437 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
pidfd_getfd 438 438 (int pidfd, int targetfd, unsigned int flags)
|
||||
rseq 293 398 (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
membarrier 283 389 (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -102,6 +102,7 @@ __NR_kcmp 2 sys_kcmp (pid_t pid1, pid_t pid2, int type, unsigned long idx1, u
|
||||
__NR_seccomp 2 sys_seccomp (unsigned int op, unsigned int flags, const char *uargs)
|
||||
__NR_memfd_create 2 sys_memfd_create (const char *name, unsigned int flags)
|
||||
__NR_userfaultfd 2 sys_userfaultfd (int flags)
|
||||
__NR_membarrier 3 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
__NR_rseq 2 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_open_tree 4 sys_open_tree (int dirfd, const char *pathname, unsigned int flags)
|
||||
__NR_move_mount 4 sys_move_mount (int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, int flags)
|
||||
|
@ -119,3 +119,4 @@ __NR_pidfd_open 5434 sys_pidfd_open (pid_t pid, unsigned int flags)
|
||||
__NR_openat2 5437 sys_openat2 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
__NR_pidfd_getfd 5438 sys_pidfd_getfd (int pidfd, int targetfd, unsigned int flags)
|
||||
__NR_rseq 5327 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_membarrier 5318 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -118,3 +118,4 @@ __NR_pidfd_open 434 sys_pidfd_open (pid_t pid, unsigned int flags)
|
||||
__NR_openat2 437 sys_openat2 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
__NR_pidfd_getfd 438 sys_pidfd_getfd (int pidfd, int targetfd, unsigned int flags)
|
||||
__NR_rseq 387 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_membarrier 365 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -118,3 +118,4 @@ __NR_pidfd_open 434 sys_pidfd_open (pid_t pid, unsigned int flags)
|
||||
__NR_openat2 437 sys_openat2 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
__NR_pidfd_getfd 438 sys_pidfd_getfd (int pidfd, int targetfd, unsigned int flags)
|
||||
__NR_rseq 383 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_membarrier 356 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -106,3 +106,4 @@ __NR_pidfd_open 434 sys_pidfd_open (pid_t pid, unsigned int flags)
|
||||
__NR_openat2 437 sys_openat2 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
__NR_pidfd_getfd 438 sys_pidfd_getfd (int pidfd, int targetfd, unsigned int flags)
|
||||
__NR_rseq 386 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_membarrier 375 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -117,3 +117,4 @@ __NR_pidfd_open 434 sys_pidfd_open (pid_t pid, unsigned int flags)
|
||||
__NR_openat2 437 sys_openat2 (int dirfd, char *pathname, struct open_how *how, size_t size)
|
||||
__NR_pidfd_getfd 438 sys_pidfd_getfd (int pidfd, int targetfd, unsigned int flags)
|
||||
__NR_rseq 334 sys_rseq (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
|
||||
__NR_membarrier 324 sys_membarrier (int cmd, unsigned int flags, int cpu_id)
|
||||
|
@ -770,6 +770,11 @@ static int dump_task_core_all(struct parasite_ctl *ctl, struct pstree_item *item
|
||||
core->tc->child_subreaper = misc->child_subreaper;
|
||||
core->tc->has_child_subreaper = true;
|
||||
|
||||
if (misc->membarrier_registration_mask) {
|
||||
core->tc->membarrier_registration_mask = misc->membarrier_registration_mask;
|
||||
core->tc->has_membarrier_registration_mask = true;
|
||||
}
|
||||
|
||||
ret = get_task_personality(pid, &core->tc->personality);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
@ -863,6 +863,9 @@ static int prepare_proc_misc(pid_t pid, TaskCoreEntry *tc, struct task_restore_a
|
||||
if (tc->has_child_subreaper)
|
||||
args->child_subreaper = tc->child_subreaper;
|
||||
|
||||
if (tc->has_membarrier_registration_mask)
|
||||
args->membarrier_registration_mask = tc->membarrier_registration_mask;
|
||||
|
||||
/* loginuid value is critical to restore */
|
||||
if (kdat.luid == LUID_FULL && tc->has_loginuid && tc->loginuid != INVALID_UID) {
|
||||
ret = prepare_loginuid(tc->loginuid);
|
||||
|
@ -128,6 +128,7 @@ struct parasite_dump_misc {
|
||||
int dumpable;
|
||||
int thp_disabled;
|
||||
int child_subreaper;
|
||||
int membarrier_registration_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -229,6 +229,7 @@ struct task_restore_args {
|
||||
#endif
|
||||
int lsm_type;
|
||||
int child_subreaper;
|
||||
int membarrier_registration_mask;
|
||||
bool has_clone3_set_tid;
|
||||
|
||||
/*
|
||||
|
@ -211,6 +211,42 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a membarrier() registration command (it is a bitmask) if the process
|
||||
* was registered for specified (as a bit index) membarrier()-issuing command;
|
||||
* returns zero otherwise.
|
||||
*/
|
||||
static int get_membarrier_registration_mask(int cmd_bit)
|
||||
{
|
||||
unsigned cmd = 1 << cmd_bit;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Issuing a barrier will be successful only if the process was registered
|
||||
* for this type of membarrier. All errors are a sign that the type issued
|
||||
* was not registered (EPERM) or not supported by kernel (EINVAL or ENOSYS).
|
||||
*/
|
||||
ret = sys_membarrier(cmd, 0, 0);
|
||||
if (ret && ret != -EPERM && ret != -EINVAL && ret != -ENOSYS) {
|
||||
pr_err("membarrier(1 << %d) returned %d\n", cmd_bit, ret);
|
||||
return -1;
|
||||
}
|
||||
pr_debug("membarrier(1 << %d) returned %d\n", cmd_bit, ret);
|
||||
/*
|
||||
* For supported registrations, MEMBARRIER_CMD_REGISTER_xxx = MEMBARRIER_CMD_xxx << 1.
|
||||
* See: enum membarrier_cmd in include/uapi/linux/membarrier.h in kernel sources.
|
||||
*/
|
||||
return ret ? 0 : cmd << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* It would be better to check the following with BUILD_BUG_ON, but we might
|
||||
* have an old linux/membarrier.h header without necessary enum values.
|
||||
*/
|
||||
#define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED 3
|
||||
#define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_SYNC_CORE 5
|
||||
#define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_RSEQ 7
|
||||
|
||||
static int dump_misc(struct parasite_dump_misc *args)
|
||||
{
|
||||
int ret;
|
||||
@ -225,6 +261,20 @@ static int dump_misc(struct parasite_dump_misc *args)
|
||||
args->dumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
|
||||
args->thp_disabled = sys_prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0);
|
||||
|
||||
args->membarrier_registration_mask = 0;
|
||||
ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
args->membarrier_registration_mask |= ret;
|
||||
ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_SYNC_CORE);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
args->membarrier_registration_mask |= ret;
|
||||
ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_RSEQ);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
args->membarrier_registration_mask |= ret;
|
||||
|
||||
ret = sys_prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&args->child_subreaper, 0, 0, 0);
|
||||
if (ret)
|
||||
pr_err("PR_GET_CHILD_SUBREAPER failed (%d)\n", ret);
|
||||
|
@ -1537,6 +1537,30 @@ int cleanup_current_inotify_events(struct task_restore_args *task_args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore membarrier() registrations.
|
||||
*/
|
||||
static int restore_membarrier_registrations(int mask)
|
||||
{
|
||||
unsigned long bitmap[1] = { mask };
|
||||
int i, err, ret = 0;
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
|
||||
pr_info("Restoring membarrier() registrations %x\n", mask);
|
||||
|
||||
for_each_bit(i, bitmap) {
|
||||
err = sys_membarrier(1 << i, 0, 0);
|
||||
if (!err)
|
||||
continue;
|
||||
pr_err("Can't restore membarrier(1 << %d) registration: %d\n", i, err);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* The main routine to restore task via sigreturn.
|
||||
* This one is very special, we never return there
|
||||
@ -2023,6 +2047,9 @@ long __export_restore_task(struct task_restore_args *args)
|
||||
goto core_restore_end;
|
||||
}
|
||||
|
||||
if (restore_membarrier_registrations(args->membarrier_registration_mask) < 0)
|
||||
goto core_restore_end;
|
||||
|
||||
pr_info("%ld: Restored\n", sys_getpid());
|
||||
|
||||
restore_finish_stage(task_entries_local, CR_STATE_RESTORE);
|
||||
|
@ -64,6 +64,8 @@ message task_core_entry {
|
||||
optional uint64 blk_sigset_extended = 20[(criu).hex = true];
|
||||
|
||||
optional uint32 stop_signo = 21;
|
||||
|
||||
optional uint32 membarrier_registration_mask = 22 [(criu).hex = true];
|
||||
}
|
||||
|
||||
message task_kobj_ids_entry {
|
||||
|
Loading…
x
Reference in New Issue
Block a user