[libvirt] [PATCH] lxc: suspend/resume support

Chris Lalancette clalance at redhat.com
Wed Sep 16 11:15:24 UTC 2009


It looks relatively good, but one suggestion and two missing pieces:

Ryota Ozaki wrote:

<snip>

> diff --git a/src/lxc_driver.c b/src/lxc_driver.c
> index 0ec1e92..2399d98 100644
> --- a/src/lxc_driver.c
> +++ b/src/lxc_driver.c
> @@ -1862,6 +1862,188 @@ static char *lxcGetHostname (virConnectPtr conn)
>      return result;
>  }
> 
> +static int lxcFreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm)
> +{
> +    int timeout = 3; /* In seconds */
> +    int check_interval = 500; /* In milliseconds */
> +    int n_try = (timeout * (1000 / check_interval));
> +    int i = 0;
> +    int ret = -1;
> +    char *state = NULL;
> +    virCgroupPtr cgroup = NULL;
> +
> +    if (!(driver->cgroup &&
> +        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
> +        return -1;
> +
> +    while (++i <= n_try) {
> +        int r;
> +        /*
> +         * Writing "FROZEN" to the "freezer.state" freezes the group,
> +         * i.e., the container, temporarily transiting "FREEZING" state.
> +         * Once the freezing is completed, the state of the group transits
> +         * to "FROZEN".
> +         * (see linux-2.6/Documentation/cgroups/freezer-subsystem.txt)
> +         */
> +        r = virCgroupSetFreezerState(cgroup, "FROZEN");
> +
> +        /*
> +         * Returning EBUSY explicitly indicates that the group is
> +         * being freezed but incomplete and other errors are true
> +         * errors.
> +         */
> +        if (r < 0 && r != -EBUSY) {
> +            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
> +            goto error;
> +        }
> +
> +        /*
> +         * Unfortunately, returning 0 (success) is likely to happen
> +         * even when the freezing has not been completed. Sometimes
> +         * the state of the group remains "FREEZING" like when
> +         * returning -EBUSY and even worse may never transit to
> +         * "FROZEN" even if writing "FROZEN" again.
> +         *
> +         * So we don't trust the return value anyway and always
> +         * decide that the freezing has been complete only with
> +         * the state actually transit to "FROZEN".
> +         */
> +        usleep(check_interval * 1000);

Suggestion: it might be better to sleep for shorter periods of time here in a
loop.  That is, sleep for say 1 ms, check if it's changed, sleep for 1 ms, etc.
 If it doesn't appear after 500 ms, then fail.  That way you'll know about the
change faster.

<snip>

> +static int lxcDomainSuspend(virDomainPtr dom)
> +{
> +    lxc_driver_t *driver = dom->conn->privateData;
> +    virDomainObjPtr vm;
> +    int ret = -1;
> +
> +    lxcDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> +
> +    if (!vm) {
> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
> +        virUUIDFormat(dom->uuid, uuidstr);
> +        lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
> +                 _("no domain with matching uuid '%s'"), uuidstr);
> +        goto cleanup;
> +    }
> +
> +    if (!virDomainIsActive(vm)) {
> +        lxcError(dom->conn, dom, VIR_ERR_OPERATION_INVALID,
> +                         "%s", _("domain is not running"));
> +        goto cleanup;
> +    }
> +
> +    if (vm->state != VIR_DOMAIN_PAUSED) {
> +        if (lxcFreezeContainer(driver, vm) < 0) {
> +            lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
> +                             "%s", _("suspend operation failed"));
> +            goto cleanup;
> +        }
> +        vm->state = VIR_DOMAIN_PAUSED;
> +    }
> +
> +    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
> +        goto cleanup;
> +    ret = 0;

Here, you'll want to generate an event (virDomainEventNewFromObj) for the
change.  You can look at lxcDomainCreateAndStart() for an example of what kind
of event you would want to generate.

<snip>

> +static int lxcDomainResume(virDomainPtr dom)
> +{
> +    lxc_driver_t *driver = dom->conn->privateData;
> +    virDomainObjPtr vm;
> +    int ret = -1;
> +
> +    lxcDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> +
> +    if (!vm) {
> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
> +        virUUIDFormat(dom->uuid, uuidstr);
> +        lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
> +                 _("no domain with matching uuid '%s'"), uuidstr);
> +        goto cleanup;
> +    }
> +
> +    if (!virDomainIsActive(vm)) {
> +        lxcError(dom->conn, dom, VIR_ERR_OPERATION_INVALID,
> +                         "%s", _("domain is not running"));
> +        goto cleanup;
> +    }
> +
> +    if (vm->state == VIR_DOMAIN_PAUSED) {
> +        if (lxcUnfreezeContainer(driver, vm) < 0) {
> +            lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
> +                             "%s", _("resume operation failed"));
> +            goto cleanup;
> +        }
> +        vm->state = VIR_DOMAIN_RUNNING;
> +    }
> +
> +    if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
> +        goto cleanup;
> +    ret = 0;

Same thing here.

-- 
Chris Lalancette




More information about the libvir-list mailing list