mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-29 14:00: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);
|
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
|
* 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
|
* 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_pre_dump(struct lxc_container *c, struct migrate_opts *opts);
|
||||||
bool __criu_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_restore(struct lxc_container *c, struct migrate_opts *opts);
|
||||||
|
bool __criu_check_feature(uint64_t *features_to_check);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4474,6 +4474,7 @@ static int do_lxcapi_migrate(struct lxc_container *c, unsigned int cmd,
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct migrate_opts *valid_opts = opts;
|
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
|
/* 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
|
* 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);
|
ret = !__criu_restore(c, valid_opts);
|
||||||
break;
|
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:
|
default:
|
||||||
ERROR("invalid migrate command %u", cmd);
|
ERROR("invalid migrate command %u", cmd);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -904,8 +904,15 @@ enum {
|
|||||||
MIGRATE_PRE_DUMP,
|
MIGRATE_PRE_DUMP,
|
||||||
MIGRATE_DUMP,
|
MIGRATE_DUMP,
|
||||||
MIGRATE_RESTORE,
|
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.
|
* \brief Options for the migrate API call.
|
||||||
*/
|
*/
|
||||||
@ -942,6 +949,13 @@ struct migrate_opts {
|
|||||||
* which at this time is 1MB.
|
* which at this time is 1MB.
|
||||||
*/
|
*/
|
||||||
uint64_t ghost_limit;
|
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 {
|
struct lxc_console_log {
|
||||||
|
Loading…
Reference in New Issue
Block a user