mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 10:51:24 +00:00
criu: add feature check capability
For migration optimization features like pre-copy or post-copy migration the support cannot be determined by simply looking at the CRIU version. Features like that depend on the architecture/kernel/criu combination and CRIU offers a feature checking interface to query if it is supported. This adds a LXC interface to query CRIU for those feature via the migrate() API call. For the recent pre-copy migration support in LXD this can be used to automatically detect if pre-copy migration should be used. In addition to the existing migrate() API commands this adds a new command: 'MIGRATE_FEATURE_CHECK'. The migrate_opts{} structure is extended by the member features_to_check which is a bitmask defining which CRIU features should be queried. Currently only the querying of the features FEATURE_MEM_TRACK and FEATURE_LAZY_PAGES is supported. Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
parent
f449521ce6
commit
b5b12b9e75
@ -652,6 +652,104 @@ err:
|
||||
free(argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to check if the checks activated in 'features_to_check' are
|
||||
* available with the current architecture/kernel/criu combination.
|
||||
*
|
||||
* Parameter features_to_check is a bit mask of all features that should be
|
||||
* checked (see feature check defines in lxc/lxccontainer.h).
|
||||
*
|
||||
* If the return value is true, all requested features are supported. If
|
||||
* the return value is false the features_to_check parameter is updated
|
||||
* to reflect which features are available. '0' means no feature but
|
||||
* also that something went totally wrong.
|
||||
*
|
||||
* Some of the code flow of criu_version_ok() is duplicated and maybe it
|
||||
* is a good candidate for refactoring.
|
||||
*/
|
||||
bool __criu_check_feature(uint64_t *features_to_check)
|
||||
{
|
||||
pid_t pid;
|
||||
uint64_t current_bit = 0;
|
||||
int ret;
|
||||
int features = *features_to_check;
|
||||
/* Feature checking is currently always like
|
||||
* criu check --feature <feature-name>
|
||||
*/
|
||||
char *args[] = { "criu", "check", "--feature", NULL, NULL };
|
||||
|
||||
if ((features & ~FEATURE_MEM_TRACK & ~FEATURE_LAZY_PAGES) != 0) {
|
||||
/* There are feature bits activated we do not understand.
|
||||
* Refusing to answer at all */
|
||||
*features_to_check = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
while (current_bit < sizeof(uint64_t) * 8) {
|
||||
/* only test requested features */
|
||||
if (!(features & (1ULL << current_bit))) {
|
||||
/* skip this */
|
||||
current_bit++;
|
||||
continue;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
SYSERROR("fork() failed");
|
||||
*features_to_check = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
if ((1ULL << current_bit) == FEATURE_MEM_TRACK)
|
||||
/* This is needed for pre-dump support, which
|
||||
* enables pre-copy migration. */
|
||||
args[3] = "mem_dirty_track";
|
||||
else if ((1ULL << current_bit) == FEATURE_LAZY_PAGES)
|
||||
/* CRIU has two checks for userfaultfd support.
|
||||
*
|
||||
* The simpler check is only for 'uffd'. If the
|
||||
* kernel supports userfaultfd without noncoop
|
||||
* then only process can be lazily restored
|
||||
* which do not fork. With 'uffd-noncoop'
|
||||
* it is also possible to lazily restore processes
|
||||
* which do fork. For a container runtime like
|
||||
* LXC checking only for 'uffd' makes not much sense. */
|
||||
args[3] = "uffd-noncoop";
|
||||
else
|
||||
exit(1);
|
||||
|
||||
null_stdfds();
|
||||
|
||||
execvp("criu", args);
|
||||
SYSERROR("Failed to exec \"criu\"");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = wait_for_pid(pid);
|
||||
|
||||
if (ret == -1) {
|
||||
/* It is not known why CRIU failed. Either
|
||||
* CRIU is not available, the feature check
|
||||
* does not exist or the feature is not
|
||||
* supported. */
|
||||
INFO("feature not supported");
|
||||
/* Clear not supported feature bit */
|
||||
features &= ~(1ULL << current_bit);
|
||||
}
|
||||
|
||||
current_bit++;
|
||||
/* no more checks requested; exit check loop */
|
||||
if (!(features & ~((1ULL << current_bit)-1)))
|
||||
break;
|
||||
}
|
||||
if (features != *features_to_check) {
|
||||
*features_to_check = features;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if the criu version is recent enough for all the features we
|
||||
* use. This version allows either CRIU_VERSION or (CRIU_GITID_VERSION and
|
||||
|
@ -30,5 +30,6 @@
|
||||
bool __criu_pre_dump(struct lxc_container *c, struct migrate_opts *opts);
|
||||
bool __criu_dump(struct lxc_container *c, struct migrate_opts *opts);
|
||||
bool __criu_restore(struct lxc_container *c, struct migrate_opts *opts);
|
||||
bool __criu_check_feature(uint64_t *features_to_check);
|
||||
|
||||
#endif
|
||||
|
@ -4474,6 +4474,7 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd,
|
||||
{
|
||||
int ret = -1;
|
||||
struct migrate_opts *valid_opts = opts;
|
||||
uint64_t features_to_check = 0;
|
||||
|
||||
/* If the caller has a bigger (newer) struct migrate_opts, let's make
|
||||
* sure that the stuff on the end is zero, i.e. that they didn't ask us
|
||||
@ -4527,6 +4528,15 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd,
|
||||
}
|
||||
ret = !__criu_restore(c, valid_opts);
|
||||
break;
|
||||
case MIGRATE_FEATURE_CHECK:
|
||||
features_to_check = valid_opts->features_to_check;
|
||||
ret = !__criu_check_feature(&features_to_check);
|
||||
if (ret) {
|
||||
/* Something went wrong. Let's let the caller
|
||||
* know which feature checks failed. */
|
||||
valid_opts->features_to_check = features_to_check;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR("invalid migrate command %u", cmd);
|
||||
ret = -EINVAL;
|
||||
|
@ -904,8 +904,15 @@ enum {
|
||||
MIGRATE_PRE_DUMP,
|
||||
MIGRATE_DUMP,
|
||||
MIGRATE_RESTORE,
|
||||
MIGRATE_FEATURE_CHECK,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Available feature checks.
|
||||
*/
|
||||
#define FEATURE_MEM_TRACK (1ULL << 0)
|
||||
#define FEATURE_LAZY_PAGES (1ULL << 1)
|
||||
|
||||
/*!
|
||||
* \brief Options for the migrate API call.
|
||||
*/
|
||||
@ -942,6 +949,13 @@ struct migrate_opts {
|
||||
* which at this time is 1MB.
|
||||
*/
|
||||
uint64_t ghost_limit;
|
||||
|
||||
/* Some features cannot be checked by comparing the CRIU version.
|
||||
* Features like dirty page tracking or userfaultfd depend on
|
||||
* the architecture/kernel/criu combination. This is a bitmask
|
||||
* in which the desired feature checks can be encoded.
|
||||
*/
|
||||
uint64_t features_to_check;
|
||||
};
|
||||
|
||||
struct lxc_console_log {
|
||||
|
Loading…
Reference in New Issue
Block a user