2
0
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:
Michał Mirosław 2022-10-06 17:52:46 +02:00 committed by Andrei Vagin
parent 5b790aa181
commit e07155e194
14 changed files with 96 additions and 0 deletions

View File

@ -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) 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) 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) 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)

View File

@ -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_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_memfd_create 2 sys_memfd_create (const char *name, unsigned int flags)
__NR_userfaultfd 2 sys_userfaultfd (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_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_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) __NR_move_mount 4 sys_move_mount (int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, int flags)

View File

@ -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_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_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_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)

View File

@ -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_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_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_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)

View File

@ -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_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_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_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)

View File

@ -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_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_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_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)

View File

@ -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_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_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_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)

View File

@ -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->child_subreaper = misc->child_subreaper;
core->tc->has_child_subreaper = true; 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); ret = get_task_personality(pid, &core->tc->personality);
if (ret < 0) if (ret < 0)
goto err; goto err;

View File

@ -863,6 +863,9 @@ static int prepare_proc_misc(pid_t pid, TaskCoreEntry *tc, struct task_restore_a
if (tc->has_child_subreaper) if (tc->has_child_subreaper)
args->child_subreaper = tc->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 */ /* loginuid value is critical to restore */
if (kdat.luid == LUID_FULL && tc->has_loginuid && tc->loginuid != INVALID_UID) { if (kdat.luid == LUID_FULL && tc->has_loginuid && tc->loginuid != INVALID_UID) {
ret = prepare_loginuid(tc->loginuid); ret = prepare_loginuid(tc->loginuid);

View File

@ -128,6 +128,7 @@ struct parasite_dump_misc {
int dumpable; int dumpable;
int thp_disabled; int thp_disabled;
int child_subreaper; int child_subreaper;
int membarrier_registration_mask;
}; };
/* /*

View File

@ -229,6 +229,7 @@ struct task_restore_args {
#endif #endif
int lsm_type; int lsm_type;
int child_subreaper; int child_subreaper;
int membarrier_registration_mask;
bool has_clone3_set_tid; bool has_clone3_set_tid;
/* /*

View File

@ -211,6 +211,42 @@ out:
return ret; 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) static int dump_misc(struct parasite_dump_misc *args)
{ {
int ret; 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->dumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
args->thp_disabled = sys_prctl(PR_GET_THP_DISABLE, 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); ret = sys_prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&args->child_subreaper, 0, 0, 0);
if (ret) if (ret)
pr_err("PR_GET_CHILD_SUBREAPER failed (%d)\n", ret); pr_err("PR_GET_CHILD_SUBREAPER failed (%d)\n", ret);

View File

@ -1537,6 +1537,30 @@ int cleanup_current_inotify_events(struct task_restore_args *task_args)
return 0; 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. * The main routine to restore task via sigreturn.
* This one is very special, we never return there * 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; goto core_restore_end;
} }
if (restore_membarrier_registrations(args->membarrier_registration_mask) < 0)
goto core_restore_end;
pr_info("%ld: Restored\n", sys_getpid()); pr_info("%ld: Restored\n", sys_getpid());
restore_finish_stage(task_entries_local, CR_STATE_RESTORE); restore_finish_stage(task_entries_local, CR_STATE_RESTORE);

View File

@ -64,6 +64,8 @@ message task_core_entry {
optional uint64 blk_sigset_extended = 20[(criu).hex = true]; optional uint64 blk_sigset_extended = 20[(criu).hex = true];
optional uint32 stop_signo = 21; optional uint32 stop_signo = 21;
optional uint32 membarrier_registration_mask = 22 [(criu).hex = true];
} }
message task_kobj_ids_entry { message task_kobj_ids_entry {