diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h index 0b2f715f383..f5d409acbfb 100644 --- a/criu/include/kerndat.h +++ b/criu/include/kerndat.h @@ -85,6 +85,7 @@ struct kerndat_s { bool has_ptrace_get_rseq_conf; struct __ptrace_rseq_configuration libc_rseq_conf; bool has_ipv6_freebind; + bool has_membarrier_get_registrations; }; extern struct kerndat_s kdat; diff --git a/criu/include/parasite.h b/criu/include/parasite.h index 5209b6da221..b7d0ca6ed68 100644 --- a/criu/include/parasite.h +++ b/criu/include/parasite.h @@ -118,6 +118,8 @@ static inline int posix_timers_dump_size(int timer_n) */ struct parasite_dump_misc { + bool has_membarrier_get_registrations; // this is sent from criu to parasite. + unsigned long brk; u32 pid; diff --git a/criu/kerndat.c b/criu/kerndat.c index 37b265d8def..c77c28ff703 100644 --- a/criu/kerndat.c +++ b/criu/kerndat.c @@ -17,6 +17,7 @@ #include #include #include +#include #if defined(CONFIG_HAS_NFTABLES_LIB_API_0) || defined(CONFIG_HAS_NFTABLES_LIB_API_1) #include @@ -1636,6 +1637,23 @@ static int kerndat_has_ipv6_freebind(void) return ret; } +static int kerndat_has_membarrier_get_registrations(void) +{ + const int cmd_get_registrations = 1 << 9; + int ret = syscall(__NR_membarrier, cmd_get_registrations, 0); + if (ret < 0) { + if (errno != EINVAL) { + return ret; + } + + kdat.has_membarrier_get_registrations = false; + } else { + kdat.has_membarrier_get_registrations = true; + } + + return 0; +} + /* * Some features depend on resource that can be dynamically changed * at the OS runtime. There are cases that we cannot determine the @@ -1879,6 +1897,10 @@ int kerndat_init(void) pr_err("kerndat_has_ipv6_freebind failed when initializing kerndat.\n"); ret = -1; } + if (!ret && kerndat_has_membarrier_get_registrations()) { + pr_err("kerndat_has_membarrier_get_registrations failed when initializing kerndat.\n"); + ret = -1; + } kerndat_lsm(); kerndat_mmap_min_addr(); diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c index c08ed09b189..295e404ec56 100644 --- a/criu/parasite-syscall.c +++ b/criu/parasite-syscall.c @@ -433,6 +433,7 @@ int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_mis struct parasite_dump_misc *ma; ma = compel_parasite_args(ctl, struct parasite_dump_misc); + ma->has_membarrier_get_registrations = kdat.has_membarrier_get_registrations; if (compel_rpc_call_sync(PARASITE_CMD_DUMP_MISC, ctl) < 0) return -1; diff --git a/criu/pie/parasite.c b/criu/pie/parasite.c index c0604903b99..e151ed65634 100644 --- a/criu/pie/parasite.c +++ b/criu/pie/parasite.c @@ -246,6 +246,27 @@ static int get_membarrier_registration_mask(int cmd_bit) #define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED 3 #define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_SYNC_CORE 5 #define MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_RSEQ 7 +#define MEMBARRIER_CMDBIT_GET_REGISTRATIONS 9 + +static int dump_membarrier_compat(int *membarrier_registration_mask) +{ + int ret; + + *membarrier_registration_mask = 0; + ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED); + if (ret < 0) + return -1; + *membarrier_registration_mask |= ret; + ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_SYNC_CORE); + if (ret < 0) + return -1; + *membarrier_registration_mask |= ret; + ret = get_membarrier_registration_mask(MEMBARRIER_CMDBIT_PRIVATE_EXPEDITED_RSEQ); + if (ret < 0) + return -1; + *membarrier_registration_mask |= ret; + return 0; +} static int dump_misc(struct parasite_dump_misc *args) { @@ -261,19 +282,18 @@ 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; + if (args->has_membarrier_get_registrations) { + ret = sys_membarrier(1 << MEMBARRIER_CMDBIT_GET_REGISTRATIONS, 0, 0); + if (ret < 0) { + pr_err("membarrier(1 << %d) returned %d\n", MEMBARRIER_CMDBIT_GET_REGISTRATIONS, ret); + return -1; + } + args->membarrier_registration_mask = ret; + } else { + ret = dump_membarrier_compat(&args->membarrier_registration_mask); + if (ret) + return ret; + } ret = sys_prctl(PR_GET_CHILD_SUBREAPER, (unsigned long)&args->child_subreaper, 0, 0, 0); if (ret)