From nobody Sat May 4 13:27:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1614398829; cv=none; d=zohomail.com; s=zohoarc; b=cwA5A3Wo6RUomF0rAp1Ak4i9fcPc9++ihjIrm/nER+yin6oZlcMjgVlY3gMdQbwVzEOAMePeTKU9P4mr1JTh/PemQK6vSzvxD4+Xb73E/QK+EkCqk9M1Z/zkw6edmWLE95kO5S/tZgjW3dpOtTZIoIsUhg7G4p5hLAg/y4OvUTw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1614398829; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=2aPsIYgMpEVYevxhIvDj9ubFL8pm9qc39yxSlBJafd0=; b=L4IZ0l3+C6cAusroNo5LAlfRlEg5Owz8BeOa9N7quqe5HkpfQ30HHkuKkoIj4mPDR55KXM468CM/pYxNG4H5Y7zt/7xLQIeA1PlR5KkKfhe4e5DHQNpLBrq+CZeEfamtm+thLJd7oMMMQ//3wJ4Yi8kAO/7ODyLMdXT8beMgQfA= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 1614398829203370.3606364925613; Fri, 26 Feb 2021 20:07:09 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-180-O48kKnnkPJWfA5ce_jwhhw-1; Fri, 26 Feb 2021 23:07:05 -0500 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 9344210066F2; Sat, 27 Feb 2021 04:07:00 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7C1DF100239A; Sat, 27 Feb 2021 04:06:59 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 82BBD18095CC; Sat, 27 Feb 2021 04:06:55 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 11R46sqi031341 for ; Fri, 26 Feb 2021 23:06:54 -0500 Received: by smtp.corp.redhat.com (Postfix) id 44040202A429; Sat, 27 Feb 2021 04:06:54 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast04.extmail.prod.ext.rdu2.redhat.com [10.11.55.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 3EB43202A424 for ; Sat, 27 Feb 2021 04:06:50 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id A13011022F0A for ; Sat, 27 Feb 2021 04:06:50 +0000 (UTC) Received: from mail-qk1-f170.google.com (mail-qk1-f170.google.com [209.85.222.170]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-443-Y-3wseSrMkSY5S_Q4UAMPw-1; Fri, 26 Feb 2021 23:06:48 -0500 Received: by mail-qk1-f170.google.com with SMTP id 136so4998948qkl.10 for ; Fri, 26 Feb 2021 20:06:48 -0800 (PST) Received: from julio.local ([2804:4ec:1239:3000:ce3:2e1a:f934:82bd]) by smtp.gmail.com with ESMTPSA id u7sm495987qkd.116.2021.02.26.20.06.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Feb 2021 20:06:46 -0800 (PST) X-MC-Unique: O48kKnnkPJWfA5ce_jwhhw-1 X-MC-Unique: Y-3wseSrMkSY5S_Q4UAMPw-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2aPsIYgMpEVYevxhIvDj9ubFL8pm9qc39yxSlBJafd0=; b=ozkhhYtlxlgDvmCQbOClb/bR34vPuW0kVSFFI6uYLLGn/js6hVAPlrBoqGf+531hYZ DxQERxXtJgW6EA1FvxFXom0maJQyvcFwYLvU7/CGw5CxtdOvQtwejGP/d04pv0PM0pq7 AWToqDE2AFKkwybfWYj8E4O4dCba6tvAVLztFU1ltH/8yEwDT8UQ7XrNz0T3nP7k9S5k FIAXMaxJwbWfD2zVhPt3xLVrvo4Jj4TCQBztYHVWJ3d6sOPjAn5mFXlla0WLqwVThn/o g6wFZLgMOZfEn3crB7sXOwAypSLnRgfxwsLoaI2UG8iBRYTnNB7SXNgHcomM1WQeEoTo uxRA== X-Gm-Message-State: AOAM533kByZ2a84CMMzaj/9VMShlRZI+5ln8zDyDS4grlH+cf+qjsVAP x4nqDf4N67ENsKxNrTKaeDYeDNNFQyQ= X-Google-Smtp-Source: ABdhPJz2VrQr1LoPQm3BiWiForncDe2kRZ6ib/XaOboJ2556YCln9jZZiovMyLNRPNGCXP85q39Beg== X-Received: by 2002:a37:392:: with SMTP id 140mr4420399qkd.236.1614398807317; Fri, 26 Feb 2021 20:06:47 -0800 (PST) From: Julio Faracco To: libvir-list@redhat.com Subject: [PATCH RFC 1/3] meson: Add support to CRIU binary into meson Date: Sat, 27 Feb 2021 01:06:33 -0300 Message-Id: <20210227040635.73934-2-jcfaracco@gmail.com> In-Reply-To: <20210227040635.73934-1-jcfaracco@gmail.com> References: <20210227040635.73934-1-jcfaracco@gmail.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-loop: libvir-list@redhat.com Cc: Julio Faracco X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch includes CRIU binary checks into meson files to support checkpoint/restore for LXC driver. Signed-off-by: Julio Faracco --- meson.build | 10 ++++++++++ meson_options.txt | 1 + 2 files changed, 11 insertions(+) diff --git a/meson.build b/meson.build index 369548f127..115c903ab2 100644 --- a/meson.build +++ b/meson.build @@ -1639,6 +1639,15 @@ void main(void) { if cc.compiles(lxc_get_free_code) conf.set('WITH_DECL_LOOP_CTL_GET_FREE', 1) endif + + if not get_option('criu').disabled() + criu_prog =3D find_program('criu') + + if criu_prog.found() + conf.set('WITH_CRIU', 1) + conf.set_quoted('CRIU', criu_prog.path()) + endif + endif elif get_option('driver_lxc').enabled() error('linux and remote_driver are required for LXC') endif @@ -2411,6 +2420,7 @@ misc_summary =3D { 'virt-login-shell': conf.has('WITH_LOGIN_SHELL'), 'virt-host-validate': conf.has('WITH_HOST_VALIDATE'), 'TLS priority': conf.get_unquoted('TLS_PRIORITY'), + 'CRIU': conf.has('WITH_CRIU'), } summary(misc_summary, section: 'Miscellaneous', bool_yn: true, list_sep: '= ') =20 diff --git a/meson_options.txt b/meson_options.txt index e5d79c2b6b..de977c8775 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -102,3 +102,4 @@ option('numad', type: 'feature', value: 'auto', descrip= tion: 'use numad to manag option('pm_utils', type: 'feature', value: 'auto', description: 'use pm-ut= ils for power management') option('sysctl_config', type: 'feature', value: 'auto', description: 'Whet= her to install sysctl configs') option('tls_priority', type: 'string', value: 'NORMAL', description: 'set = the default TLS session priority string') +option('criu', type: 'feature', value: 'auto', description: 'use CRIU to c= heckpoint/restore containers') --=20 2.27.0 From nobody Sat May 4 13:27:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1614398829; cv=none; d=zohomail.com; s=zohoarc; b=iqbyGAF8lfKB4JuMfPE5ii5Y7r+zM8OREzeSr0qK0EJJtOqsHY3jF8E/OpKRtCkc7BU2WPX67P2K46W4vx9nROz7lv3JrcaeIXDs/pjPQt95dNqMHqHJwBLnepeRC/WNGUeO70ul5nayp6SIU5bsSeffz1NAECGIaOrel2Mb1sk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1614398829; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=P78a1m/NXRB16G8nBZZLCqHAOsyBVSV7N5Wq+5cVDkc=; b=bfpKSt9RSFhd/kAg02iYlRTJsZF0TGulYPhTj/14PTTYuP8NRTjGyinFsu5MOkpZUVYFam4hhpDX7iTSO6Ri8TtnmvweiHTc8FcWO6RO/pJQSternH12XssT19FYfcAeuHylNMZg5P5wlulz3U/nHxrZaZHFNNsT6S/IoT1iWiU= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 16143988291651007.3421763166277; Fri, 26 Feb 2021 20:07:09 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-340-azEA7bDWMPWthOw6OyMwhA-1; Fri, 26 Feb 2021 23:07:05 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 8CEEAC280; Sat, 27 Feb 2021 04:07:00 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id BF6CB1A7D9; Sat, 27 Feb 2021 04:06:58 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 75BB418095C9; Sat, 27 Feb 2021 04:06:56 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 11R46sIP031342 for ; Fri, 26 Feb 2021 23:06:54 -0500 Received: by smtp.corp.redhat.com (Postfix) id 440C7202A434; Sat, 27 Feb 2021 04:06:54 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast03.extmail.prod.ext.rdu2.redhat.com [10.11.55.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 3DE5F2026D46 for ; Sat, 27 Feb 2021 04:06:53 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8035C9988E1 for ; Sat, 27 Feb 2021 04:06:53 +0000 (UTC) Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-571-MNPbtnz9PVK6lbsoayEl8Q-1; Fri, 26 Feb 2021 23:06:51 -0500 Received: by mail-qk1-f180.google.com with SMTP id x124so11363579qkc.1 for ; Fri, 26 Feb 2021 20:06:51 -0800 (PST) Received: from julio.local ([2804:4ec:1239:3000:ce3:2e1a:f934:82bd]) by smtp.gmail.com with ESMTPSA id u7sm495987qkd.116.2021.02.26.20.06.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Feb 2021 20:06:49 -0800 (PST) X-MC-Unique: azEA7bDWMPWthOw6OyMwhA-1 X-MC-Unique: MNPbtnz9PVK6lbsoayEl8Q-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=P78a1m/NXRB16G8nBZZLCqHAOsyBVSV7N5Wq+5cVDkc=; b=KDVLFbJrNsqFkNS0Y9rx8dXV2B8B1bmQXxPISoBEXUKEiLP7xJDvdYf7OZm0rqSIi0 V4iBcWPRtxoIZJuSFdj2jmsyCpgm+NMRaLKC79co/dm8g+ympuMhUPbQXYM4KnQwfEad Mqvyo6aWyMp44TjKzdxntDgUTdGYW8hhPQkiGwH2eby+zKg4AWEZL4yo15of/08CY+4i 2oBtGgywysvmFCFHgzPgbB14oT6U0y07Cmlu8Cb98MiRHtpLdVN3zU8eaIV4IRxwLNAT AI26NUlx8kXQqXzEeP9qqkZP+q7wlwpNwq8Ks88m5n+H1Xw3Puv2g/XZkD2bwtsGbpjn gbjg== X-Gm-Message-State: AOAM5316fzdYbjmriwmO7fj/WHQY1w6hNhx0HCFeAisdo6G0B70iXnyM FSi122HnBV21Atxv1f28qh6nsL9EmmI= X-Google-Smtp-Source: ABdhPJwgFPUSkAltg4K+dO0dqwU136qvmePStMse4imaD55Mczev1rtq1RNuKS7JUYCoZLA2tV2Gfw== X-Received: by 2002:a37:4c09:: with SMTP id z9mr5819712qka.9.1614398810060; Fri, 26 Feb 2021 20:06:50 -0800 (PST) From: Julio Faracco To: libvir-list@redhat.com Subject: [PATCH RFC 2/3] lxc: Including CRIU functions and functions to support C/R. Date: Sat, 27 Feb 2021 01:06:34 -0300 Message-Id: <20210227040635.73934-3-jcfaracco@gmail.com> In-Reply-To: <20210227040635.73934-1-jcfaracco@gmail.com> References: <20210227040635.73934-1-jcfaracco@gmail.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-loop: libvir-list@redhat.com Cc: Julio Faracco X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch adds the source code of helper functions into files lxc_criu.{h,c} to support LXC checkpoint/restore using CRIU binary. To save container state, LXC follows the same pattern of QEMU and libxl using a file with a header with metadata, but as CRIU saves multiple files, it needs to inserted in a unique file using a type of compression. Using TAR for instance. Signed-off-by: Julio Faracco --- src/lxc/lxc_criu.c | 405 ++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_criu.h | 50 ++++++ src/lxc/meson.build | 2 + 3 files changed, 457 insertions(+) create mode 100644 src/lxc/lxc_criu.c create mode 100644 src/lxc/lxc_criu.h diff --git a/src/lxc/lxc_criu.c b/src/lxc/lxc_criu.c new file mode 100644 index 0000000000..a82bd5ffde --- /dev/null +++ b/src/lxc/lxc_criu.c @@ -0,0 +1,405 @@ +/* + * lxc_criu.c: wrapper functions for CRIU C API to be used for lxc migrati= on + * + * Copyright (c) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include +#include +#include + +#include "virobject.h" +#include "virerror.h" +#include "virlog.h" +#include "virfile.h" +#include "vircommand.h" +#include "virstring.h" +#include "viralloc.h" +#include "virutil.h" + +#include "lxc_domain.h" +#include "lxc_driver.h" +#include "lxc_criu.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +VIR_LOG_INIT("lxc.lxc_criu"); + +#if WITH_CRIU +typedef enum { + LXC_SAVE_FORMAT_RAW =3D 0, + LXC_SAVE_FORMAT_GZIP =3D 1, + LXC_SAVE_FORMAT_BZIP2 =3D 2, + LXC_SAVE_FORMAT_XZ =3D 3, + LXC_SAVE_FORMAT_LZOP =3D 4, + + LXC_SAVE_FORMAT_LAST +} virLXCSaveFormat; + +VIR_ENUM_DECL(lxcSaveCompression); +VIR_ENUM_IMPL(lxcSaveCompression, + LXC_SAVE_FORMAT_LAST, + "raw", + "gzip", + "bzip2", + "xz", + "lzop", +); + + +/* lxcSaveImageGetCompressionProgram: + * @imageFormat: String representation from lxc.conf for the compression + * image format being used (dump, save, or snapshot). + * @compresspath: Pointer to a character string to store the fully qualifi= ed + * path from virFindFileInPath. + * @styleFormat: String representing the style of format (dump, save, snap= shot) + * + * Returns: + * virQEMUSaveFormat - Integer representation of the compression + * program to be used for particular style + * (e.g. dump, save, or snapshot). + * LXC_SAVE_FORMAT_RAW - If there is no lxc.conf imageFormat value or + * no there was an error, then just return RAW + * indicating none. + */ +static int +lxcSaveImageGetCompressionProgram(const char *imageFormat, + virCommandPtr *compressor, + const char *styleFormat) +{ + const char *prog; + int ret; + + *compressor =3D NULL; + + /* Use tar to compress all .img files */ + if (!(prog =3D virFindFileInPath("tar"))) + return -1; + + *compressor =3D virCommandNew(prog); + + if (STREQ(styleFormat, "save")) { + /* Remove files after added into tar */ + virCommandAddArgList(*compressor, "--create", + "--remove-files", NULL); + } else if (STREQ(styleFormat, "dump")) { + virCommandAddArg(*compressor, "--extract"); + } else { + return -1; + } + + if (!imageFormat) + return 0; + + if ((ret =3D lxcSaveCompressionTypeFromString(imageFormat)) < 0) + return -1; + + switch (ret) { + case LXC_SAVE_FORMAT_GZIP: + virCommandAddArg(*compressor, "--gzip"); + break; + case LXC_SAVE_FORMAT_BZIP2: + virCommandAddArg(*compressor, "--bzip2"); + break; + case LXC_SAVE_FORMAT_XZ: + virCommandAddArg(*compressor, "--xz"); + break; + case LXC_SAVE_FORMAT_LZOP: + virCommandAddArg(*compressor, "--lzop"); + break; + case LXC_SAVE_FORMAT_RAW: + default: + break; + } + + return ret; +} + + +int lxcCriuCompress(const char *checkpointdir, + char *compressionType) +{ + virCommandPtr cmd; + g_autofree char *tarfile =3D NULL; + int ret =3D -1; + + if ((ret =3D lxcSaveImageGetCompressionProgram(compressionType, + &cmd, + "save")) < 0) + return -1; + + tarfile =3D g_strdup_printf("%s/criu.save", checkpointdir); + + virCommandAddArgFormat(cmd, "--file=3D%s", tarfile); + virCommandAddArgFormat(cmd, "--directory=3D%s/save/", checkpointdir); + virCommandAddArg(cmd, "."); + + if (virCommandRun(cmd, NULL) < 0) + return -1; + + return ret; +} + + +int lxcCriuDecompress(const char *checkpointdir, + char *compressionType) +{ + virCommandPtr cmd; + g_autofree char *tarfile =3D NULL; + g_autofree char *savedir =3D NULL; + int ret =3D -1; + + if ((ret =3D lxcSaveImageGetCompressionProgram(compressionType, + &cmd, + "dump")) < 0) + return -1; + + savedir =3D g_strdup_printf("%s/save/", checkpointdir); + if (virFileMakePath(savedir) < 0) { + virReportSystemError(errno, + _("Failed to mkdir %s"), savedir); + return -1; + } + + tarfile =3D g_strdup_printf("%s/criu.save", checkpointdir); + + virCommandAddArgFormat(cmd, "--file=3D%s", tarfile); + virCommandAddArgFormat(cmd, "--directory=3D%s", savedir); + + if (virCommandRun(cmd, NULL) < 0) + return -1; + + return ret; +} + + +int lxcCriuDump(virDomainObjPtr vm, + const char *checkpointdir) +{ + int ret =3D -1; + virLXCDomainObjPrivatePtr priv =3D vm->privateData; + virCommandPtr cmd; + struct stat sb; + g_autofree char *path =3D NULL; + g_autofree char *tty_info_path =3D NULL; + g_autofree char *ttyinfo =3D NULL; + g_autofree char *pidfile =3D NULL; + g_autofree char *pidbuf =3D NULL; + g_autofree char *savedir =3D NULL; + int pidlen; + int pidfd; + int status; + + savedir =3D g_strdup_printf("%s/save/", checkpointdir); + if (virFileMakePath(savedir) < 0) { + virReportSystemError(errno, + _("Failed to mkdir %s"), savedir); + return -1; + } + + pidfile =3D g_strdup_printf("%s/save/dump.pid", checkpointdir); + pidbuf =3D g_strdup_printf("%d", priv->initpid); + pidlen =3D strlen(pidbuf); + + pidfd =3D open(pidfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (safewrite(pidfd, pidbuf, pidlen) !=3D pidlen) { + virReportSystemError(errno, "%s", _("criu pid file write failed")); + return -1; + } + + cmd =3D virCommandNew(CRIU); + virCommandAddArg(cmd, "dump"); + + virCommandAddArgList(cmd, "--images-dir", savedir, NULL); + + virCommandAddArgList(cmd, "--log-file", "dump.log", NULL); + + virCommandAddArgList(cmd, "-vvvv", NULL); + + virCommandAddArg(cmd, "--tree"); + virCommandAddArgFormat(cmd, "%d", priv->initpid); + + virCommandAddArgList(cmd, "--tcp-established", "--file-locks", + "--link-remap", "--force-irmap", NULL); + + virCommandAddArgList(cmd, "--manage-cgroup", NULL); + + virCommandAddArgList(cmd, "--enable-external-sharing", + "--enable-external-masters", NULL); + + virCommandAddArgList(cmd, "--enable-fs", "hugetlbfs", + "--enable-fs", "tracefs", NULL); + + /* Add support for FUSE */ + virCommandAddArgList(cmd, "--ext-mount-map", "/proc/meminfo:fuse", NUL= L); + virCommandAddArgList(cmd, "--ghost-limit", "10000000", NULL); + + virCommandAddArgList(cmd, "--ext-mount-map", "/dev/console:console", N= ULL); + virCommandAddArgList(cmd, "--ext-mount-map", "/dev/tty1:tty1", NULL); + virCommandAddArgList(cmd, "--ext-mount-map", "auto", NULL); + + /* The master pair of the /dev/pts device lives outside from what is d= umped + * inside the libvirt-lxc process. Add the slave pair as an external t= ty + * otherwise criu will fail. + */ + path =3D g_strdup_printf("/proc/%d/root/dev/pts/0", priv->initpid); + + if (stat(path, &sb) < 0) { + virReportSystemError(errno, + _("Unable to stat %s"), path); + goto cleanup; + } + + tty_info_path =3D g_strdup_printf("%s/tty.info", savedir); + ttyinfo =3D g_strdup_printf("tty[%x:%x]", (unsigned int)sb.st_rdev, + (unsigned int)sb.st_dev); + + if (virFileWriteStr(tty_info_path, ttyinfo, 0666) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to write tty info to %s"), tty_info_path); + goto cleanup; + } + + VIR_DEBUG("tty.info: tty[%x:%x]", + (unsigned int)sb.st_dev, (unsigned int)sb.st_rdev); + virCommandAddArg(cmd, "--external"); + virCommandAddArgFormat(cmd, "tty[%x:%x]", + (unsigned int)sb.st_rdev, (unsigned int)sb.st_de= v); + + VIR_DEBUG("About to checkpoint domain %s (pid =3D %d)", + vm->def->name, priv->initpid); + virCommandRawStatus(cmd); + if (virCommandRun(cmd, &status) < 0) + goto cleanup; + + ret =3D 0; + + cleanup: + if (ret < 0) + return ret; + return status; +} + +int lxcCriuRestore(virDomainDefPtr def, + int restorefd, int ttyfd) +{ + virCommandPtr cmd; + g_autofree char *ttyinfo =3D NULL; + g_autofree char *inheritfd =3D NULL; + g_autofree char *tty_info_path =3D NULL; + g_autofree char *checkpointfd =3D NULL; + g_autofree char *checkpointdir =3D NULL; + g_autofree char *rootfs_mount =3D NULL; + g_autofree gid_t *groups =3D NULL; + int ret =3D -1; + int ngroups; + + cmd =3D virCommandNew(CRIU); + virCommandAddArg(cmd, "restore"); + + checkpointfd =3D g_strdup_printf("/proc/self/fd/%d", restorefd); + + if (virFileResolveLink(checkpointfd, &checkpointdir) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to readlink checkpoint dir path")); + return -1; + } + + /* CRIU needs the container's root bind mounted so that it is the root= of + * some mount. + */ + rootfs_mount =3D g_strdup_printf("%s/save/%s", LXC_STATE_DIR, def->nam= e); + + virCommandAddArgList(cmd, "--images-dir", checkpointdir, NULL); + + virCommandAddArgList(cmd, "--log-file", "restore.log", NULL); + + virCommandAddArgList(cmd, "--pidfile", "restore.pid", NULL); + + virCommandAddArgList(cmd, "-vvvv", NULL); + virCommandAddArgList(cmd, "--tcp-established", "--file-locks", + "--link-remap", "--force-irmap", NULL); + + virCommandAddArgList(cmd, "--enable-external-sharing", + "--enable-external-masters", NULL); + + virCommandAddArgList(cmd, "--ext-mount-map", "auto", NULL); + + virCommandAddArgList(cmd, "--enable-fs", "hugetlbfs", + "--enable-fs", "tracefs", NULL); + + virCommandAddArgList(cmd, "--ext-mount-map", "fuse:/proc/meminfo", NUL= L); + + virCommandAddArgList(cmd, "--ext-mount-map", "console:/dev/console", N= ULL); + virCommandAddArgList(cmd, "--ext-mount-map", "tty1:/dev/tty1", NULL); + + virCommandAddArgList(cmd, "--restore-detached", "--restore-sibling", N= ULL); + + /* Restore external tty that was saved in tty.info file + */ + tty_info_path =3D g_strdup_printf("%s/tty.info", checkpointdir); + + if (virFileReadAll(tty_info_path, 1024, &ttyinfo) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read tty info from %s"), tty_info_path= ); + return -1; + } + + inheritfd =3D g_strdup_printf("fd[%d]:%s", ttyfd, ttyinfo); + + virCommandAddArgList(cmd, "--inherit-fd", inheritfd, NULL); + + /* Change the root filesystem because we run in mount namespace. + */ + virCommandAddArgList(cmd, "--root", rootfs_mount, NULL); + + if ((ngroups =3D virGetGroupList(virCommandGetUID(cmd), virCommandGetG= ID(cmd), + &groups)) < 0) + return -1; + + + VIR_DEBUG("Executing init binary"); + /* this function will only return if an error occurred */ + ret =3D virCommandExec(cmd, groups, ngroups); + + if (ret !=3D 0) { + VIR_DEBUG("Tearing down container"); + fprintf(stderr, + _("Failure in libvirt_lxc startup: %s\n"), + virGetLastErrorMessage()); + } + + return ret; +} +#else +int lxcCriuDump(virDomainObjPtr vm ATTRIBUTE_UNUSED, + const char *checkpointdir ATTRIBUTE_UNUSED) +{ + virReportUnsupportedError(); + return -1; +} + +int lxcCriuRestore(virDomainDefPtr def ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED, + int ttyfd ATTRIBUTE_UNUSED) +{ + virReportUnsupportedError(); + return -1; +} +#endif diff --git a/src/lxc/lxc_criu.h b/src/lxc/lxc_criu.h new file mode 100644 index 0000000000..7dfd78aa24 --- /dev/null +++ b/src/lxc/lxc_criu.h @@ -0,0 +1,50 @@ +/* + * lxc_criu.h: CRIU C API methods wrapper + * + * Copyright (c) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#ifndef LXC_CRIU_H +# define LXC_CRIU_H + +# include "virobject.h" + +#define LXC_SAVE_MAGIC "LXCCriuSaveMagic" +#define LXC_SAVE_VERSION 2 + +typedef struct _virLXCSaveHeader virLXCSaveHeader; +typedef virLXCSaveHeader *virLXCSaveHeaderPtr; +struct _virLXCSaveHeader { + char magic[sizeof(LXC_SAVE_MAGIC)-1]; + uint32_t version; + uint32_t xmlLen; + uint32_t compressed; + uint32_t unused[9]; +}; + +int lxcCriuCompress(const char *checkpointdir, + char *compressionType); + +int lxcCriuDecompress(const char *checkpointdir, + char *compressionType); + +int lxcCriuDump(virDomainObjPtr vm, + const char *checkpointdir); + +int lxcCriuRestore(virDomainDefPtr def, + int fd, int ttyfd); +#endif /* LXC_CRIU_H */ diff --git a/src/lxc/meson.build b/src/lxc/meson.build index ad5c659dba..1a8524aab3 100644 --- a/src/lxc/meson.build +++ b/src/lxc/meson.build @@ -9,6 +9,7 @@ lxc_driver_sources =3D [ 'lxc_monitor.c', 'lxc_native.c', 'lxc_process.c', + 'lxc_criu.c', ] =20 lxc_monitor_protocol =3D files('lxc_monitor_protocol.x') @@ -61,6 +62,7 @@ lxc_controller_sources =3D files( 'lxc_domain.c', 'lxc_fuse.c', 'lxc_controller.c', + 'lxc_criu.c', ) =20 lxc_controller_generated =3D custom_target( --=20 2.27.0 From nobody Sat May 4 13:27:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) client-ip=63.128.21.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1614398848; cv=none; d=zohomail.com; s=zohoarc; b=DUcMW1gaCvzrCzVyBvJBNC+CvGl4vqLeHFJXgmzWmxN3pKbi404IJ57gG+nrAWl2ecxGl9YNl/WPEknTDokV41gu8WCoYnFi6x2UV4SyPgmq9TppkwuBY2So0UsoZGG+d0MIOZO2Q6aC6d5NhN7tMOkY+1WLcBlPjVc6Xn9eS3c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1614398848; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=OX/bffCbmYRSyx5PH2/6QyQxL07oMd1XnBx7vWSU0GY=; b=e3HyEIfFoQN+P5pLtcmCtext0VYXkiVIMUmo/Or2cvZxLgzpz3t1J+p3c8e8/DwhSdG23UMXNH9pjHu9ouTzKIMZvz5VD+PuAOQQnMInV250QBqrx4omPIdTJ1SF7YjSy31hA03edwTrJFIgqy0zGhdUpQmVJPcheGFzYt9VwnE= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 63.128.21.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [63.128.21.124]) by mx.zohomail.com with SMTPS id 1614398848709983.1250449708704; Fri, 26 Feb 2021 20:07:28 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-506-WTGpxjHSNWScv4f_U3dJ1Q-1; Fri, 26 Feb 2021 23:07:24 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id A4EE68030C1; Sat, 27 Feb 2021 04:07:16 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 81B045C257; Sat, 27 Feb 2021 04:07:16 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 15DC34E58E; Sat, 27 Feb 2021 04:07:16 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 11R46vv1031362 for ; Fri, 26 Feb 2021 23:06:57 -0500 Received: by smtp.corp.redhat.com (Postfix) id EEEC7163D15; Sat, 27 Feb 2021 04:06:56 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast01.extmail.prod.ext.rdu2.redhat.com [10.11.55.17]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E81041649D1 for ; Sat, 27 Feb 2021 04:06:56 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C62DB85A59D for ; Sat, 27 Feb 2021 04:06:56 +0000 (UTC) Received: from mail-qt1-f172.google.com (mail-qt1-f172.google.com [209.85.160.172]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-164-7qjyxUPcNtuINdrUiwnQBQ-1; Fri, 26 Feb 2021 23:06:53 -0500 Received: by mail-qt1-f172.google.com with SMTP id d11so7468745qtx.9 for ; Fri, 26 Feb 2021 20:06:53 -0800 (PST) Received: from julio.local ([2804:4ec:1239:3000:ce3:2e1a:f934:82bd]) by smtp.gmail.com with ESMTPSA id u7sm495987qkd.116.2021.02.26.20.06.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Feb 2021 20:06:52 -0800 (PST) X-MC-Unique: WTGpxjHSNWScv4f_U3dJ1Q-1 X-MC-Unique: 7qjyxUPcNtuINdrUiwnQBQ-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OX/bffCbmYRSyx5PH2/6QyQxL07oMd1XnBx7vWSU0GY=; b=HzwD4Tp2oz2zPVvxdI29iNctyOxwNj7RRMSEyI5wjzkWnvMa2O5YAf3CR6+BYJNxqf Hvqrrv3gJgNEZZks3lYYWBjdLw6o9DWkfnCk/XK/4pTS9Um9/lBIbAle4Gcp6AbDsUGm asYZxnMEZ+JU2FVOD+BKgfylm+N7eIk1s7PaJu5w7dyysi7UKWsCWEkfwNma+396m7v7 pSK7jRGlfv04FQ+CC8IKRNSYMPSQU+6iuYF/CfbpVT46M3V0ETf1I0QUpL7wdTlKrfqJ FqIsRrC1e8YAX02JvH53HFia/hKSbRCOvKtHoznZhGyEPmAJxST9bv5yujkmCyIoCIL+ 9J+g== X-Gm-Message-State: AOAM531jLfmvL3j0dDYUtIRfBFDmbR9NMj6N2JoU55m0ojVI6VfrCIZ7 X6/YwMdplGYnJonoWfAWkhbgeK6nYqE= X-Google-Smtp-Source: ABdhPJzziijz1YDaYvRsmbrJ+qDNvqOZl3BoN2OMIF1kF+zJ5rGUlXpTxagJLFB5tjEtxWQn9cabKg== X-Received: by 2002:ac8:73c4:: with SMTP id v4mr2066970qtp.275.1614398812562; Fri, 26 Feb 2021 20:06:52 -0800 (PST) From: Julio Faracco To: libvir-list@redhat.com Subject: [PATCH RFC 3/3] lxc: Adding support to LXC driver to restore a container Date: Sat, 27 Feb 2021 01:06:35 -0300 Message-Id: <20210227040635.73934-4-jcfaracco@gmail.com> In-Reply-To: <20210227040635.73934-1-jcfaracco@gmail.com> References: <20210227040635.73934-1-jcfaracco@gmail.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-loop: libvir-list@redhat.com Cc: Julio Faracco X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch introduces the hability to restore a saved container using CRIU. It should be possible to start it using traditional methods: a simple conta= iner start; or from a saved state. Signed-off-by: Julio Faracco --- src/lxc/lxc_conf.c | 3 + src/lxc/lxc_conf.h | 2 + src/lxc/lxc_container.c | 188 ++++++++++++++++++++- src/lxc/lxc_container.h | 3 +- src/lxc/lxc_controller.c | 93 ++++++++++- src/lxc/lxc_driver.c | 341 ++++++++++++++++++++++++++++++++++++++- src/lxc/lxc_process.c | 26 ++- src/lxc/lxc_process.h | 1 + 8 files changed, 638 insertions(+), 19 deletions(-) diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index e6ad91205e..690cef7d39 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -240,6 +240,8 @@ virLXCDriverConfigNew(void) cfg->logDir =3D g_strdup(LXC_LOG_DIR); cfg->autostartDir =3D g_strdup(LXC_AUTOSTART_DIR); =20 + cfg->saveImageFormat =3D NULL; + return cfg; } =20 @@ -291,4 +293,5 @@ virLXCDriverConfigDispose(void *obj) g_free(cfg->stateDir); g_free(cfg->logDir); g_free(cfg->securityDriverName); + g_free(cfg->saveImageFormat); } diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index 664bafc7b9..08bea11c02 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -61,6 +61,8 @@ struct _virLXCDriverConfig { char *securityDriverName; bool securityDefaultConfined; bool securityRequireConfined; + + char *saveImageFormat; }; =20 struct _virLXCDriver { diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 2a5f8711c4..03c086d029 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -51,6 +51,7 @@ #include "virerror.h" #include "virlog.h" #include "lxc_container.h" +#include "lxc_criu.h" #include "viralloc.h" #include "virnetdevveth.h" #include "viruuid.h" @@ -84,6 +85,7 @@ struct __lxc_child_argv { char **ttyPaths; int handshakefd; int *nsInheritFDs; + int restorefd; }; =20 static int lxcContainerMountFSBlock(virDomainFSDefPtr fs, @@ -235,8 +237,8 @@ static virCommandPtr lxcContainerBuildInitCmd(virDomain= DefPtr vmDef, * * Returns 0 on success or -1 in case of error */ -static int lxcContainerSetupFDs(int *ttyfd, - size_t npassFDs, int *passFDs) +static int lxcContainerSetupFDs(int *ttyfd, size_t npassFDs, + int *passFDs, int restorefd) { int rc =3D -1; int open_max; @@ -335,6 +337,10 @@ static int lxcContainerSetupFDs(int *ttyfd, =20 for (fd =3D last_fd + 1; fd < open_max; fd++) { int tmpfd =3D fd; + + if (tmpfd =3D=3D restorefd) + continue; + VIR_MASS_CLOSE(tmpfd); } =20 @@ -1017,6 +1023,30 @@ static int lxcContainerMountFSDevPTS(virDomainDefPtr= def, return 0; } =20 + +static int lxcContainerMountFSDevPTSRestore(virDomainDefPtr def, + const char *stateDir) +{ + int flags =3D MS_MOVE; + g_autofree char *path =3D NULL; + + VIR_DEBUG("Mount /dev/pts stateDir=3D%s", stateDir); + + path =3D g_strdup_printf("%s/%s.devpts", stateDir, def->name); + + VIR_DEBUG("Trying to move %s to /dev/pts", path); + + if (mount(path, "/dev/pts", NULL, flags, NULL) < 0) { + virReportSystemError(errno, + _("Failed to mount %s on /dev/pts"), + path); + return -1; + } + + return 0; +} + + static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths) { size_t i; @@ -1843,6 +1873,139 @@ static int lxcAttachNS(int *ns_fd) return 0; } =20 + +/* + * lxcContainerChildRestore: + * @data: pointer to container arguments + */ +static int lxcContainerChildRestore(void *data) +{ + lxc_child_argv_t *argv =3D data; + virDomainDefPtr vmDef =3D argv->config; + int ttyfd =3D -1; + int ret =3D -1; + virDomainFSDefPtr root; + g_autofree char *ttyPath =3D NULL; + g_autofree char *sec_mount_options =3D NULL; + g_autofree char *stateDir =3D NULL; + g_autofree char *rootfs_mount =3D NULL; + + if (NULL =3D=3D vmDef) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("lxcChild() passed invalid vm definition")); + goto cleanup; + } + + if (lxcContainerWaitForContinue(argv->monitor) < 0) { + virReportSystemError(errno, "%s", + _("Failed to read the container continue mess= age")); + goto cleanup; + } + VIR_DEBUG("Received container continue message"); + + if (lxcContainerSetID(vmDef) < 0) + goto cleanup; + + root =3D virDomainGetFilesystemForTarget(vmDef, "/"); + + if (argv->nttyPaths) { + const char *tty =3D argv->ttyPaths[0]; + + if (STRPREFIX(tty, "/dev/pts/")) + tty +=3D strlen("/dev/pts/"); + + ttyPath =3D g_strdup_printf("%s/%s.devpts/%s", + LXC_STATE_DIR, vmDef->name, tty); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("At least one tty is required")); + goto cleanup; + } + + VIR_DEBUG("Container TTY path: %s", ttyPath); + + ttyfd =3D open(ttyPath, O_RDWR); + if (ttyfd < 0) { + virReportSystemError(errno, + _("Failed to open tty %s"), + ttyPath); + goto cleanup; + } + VIR_DEBUG("Container TTY fd: %d", ttyfd); + + if (!(sec_mount_options =3D virSecurityManagerGetMountOptions( + argv->securityDriver, + vmDef))) + goto cleanup; + + if (lxcContainerPrepareRoot(vmDef, root, sec_mount_options) < 0) + goto cleanup; + + if (lxcContainerSendContinue(argv->handshakefd) < 0) { + virReportSystemError(errno, "%s", + _("Failed to send continue signal to controlle= r")); + goto cleanup; + } + + VIR_DEBUG("Setting up container's std streams"); + + if (lxcContainerSetupFDs(&ttyfd, + argv->npassFDs, argv->passFDs, argv->restoref= d) < 0) + goto cleanup; + + /* CRIU needs the container's root bind mounted so that it is the root= of + * some mount. + */ + rootfs_mount =3D g_strdup_printf("%s/save/%s", LXC_STATE_DIR, vmDef->n= ame); + + if (virFileMakePath(rootfs_mount) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to mkdir rootfs mount path")); + goto cleanup; + } + + if (mount(root->src->path, rootfs_mount, NULL, MS_BIND, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to create rootfs mountpoint")); + goto cleanup; + } + + if (virFileResolveAllLinks(LXC_STATE_DIR, &stateDir) < 0) + goto cleanup; + + /* Mounts /dev/pts */ + if (lxcContainerMountFSDevPTSRestore(vmDef, stateDir) < 0) { + virReportSystemError(errno, "%s", + _("Failed to mount dev/pts")); + goto cleanup; + } + + if (setsid() < 0) { + virReportSystemError(errno, "%s", + _("Unable to become session leader")); + } + + ret =3D 0; + + cleanup: + VIR_FORCE_CLOSE(argv->monitor); + VIR_FORCE_CLOSE(argv->handshakefd); + VIR_FORCE_CLOSE(ttyfd); + + if (ret =3D=3D 0) { + VIR_DEBUG("Executing container restore criu function"); + ret =3D lxcCriuRestore(vmDef, argv->restorefd, 0); + } else { + VIR_DEBUG("Tearing down container"); + fprintf(stderr, + _("Failure in libvirt_lxc startup: %s\n"), + virGetLastErrorMessage()); + } + + return ret; +} + + /** * lxcContainerSetUserGroup: * @cmd: command to update @@ -2049,7 +2212,7 @@ static int lxcContainerChild(void *data) VIR_FORCE_CLOSE(argv->handshakefd); VIR_FORCE_CLOSE(argv->monitor); if (lxcContainerSetupFDs(&ttyfd, - argv->npassFDs, argv->passFDs) < 0) + argv->npassFDs, argv->passFDs, -1) < 0) goto cleanup; =20 /* Make init process of the container the leader of the new session. @@ -2143,7 +2306,8 @@ int lxcContainerStart(virDomainDefPtr def, int handshakefd, int *nsInheritFDs, size_t nttyPaths, - char **ttyPaths) + char **ttyPaths, + int restorefd) { pid_t pid; int cflags; @@ -2162,6 +2326,7 @@ int lxcContainerStart(virDomainDefPtr def, .ttyPaths =3D ttyPaths, .handshakefd =3D handshakefd, .nsInheritFDs =3D nsInheritFDs, + .restorefd =3D restorefd, }; =20 /* allocate a stack for the container */ @@ -2207,9 +2372,18 @@ int lxcContainerStart(virDomainDefPtr def, VIR_DEBUG("Inheriting a UTS namespace"); } =20 - VIR_DEBUG("Cloning container init process"); - pid =3D clone(lxcContainerChild, stacktop, cflags, &args); - VIR_DEBUG("clone() completed, new container PID is %d", pid); + if (restorefd =3D=3D -1) + VIR_DEBUG("Cloning container init process"); + else + VIR_DEBUG("Cloning container process that will spawn criu restore"= ); + + if (restorefd !=3D -1) + pid =3D clone(lxcContainerChildRestore, stacktop, SIGCHLD, &args); + else + pid =3D clone(lxcContainerChild, stacktop, cflags, &args); + + if (restorefd =3D=3D -1) + VIR_DEBUG("clone() completed, new container PID is %d", pid); =20 if (pid < 0) { virReportSystemError(errno, "%s", diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index 94a6c5309c..cf61a033fc 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -54,7 +54,8 @@ int lxcContainerStart(virDomainDefPtr def, int handshakefd, int *nsInheritFDs, size_t nttyPaths, - char **ttyPaths); + char **ttyPaths, + int restorefd); =20 int lxcContainerSetupHostdevCapsMakePath(const char *dev); =20 diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 8f166a436a..5bd0712ba9 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -139,6 +139,8 @@ struct _virLXCController { virCgroupPtr cgroup; =20 virLXCFusePtr fuse; + + int restore; }; =20 #include "lxc_controller_dispatch.h" @@ -1006,6 +1008,54 @@ static int lxcControllerClearCapabilities(void) return 0; } =20 + +static int lxcControllerFindRestoredPid(int fd) +{ + int initpid =3D 0; + int ret =3D -1; + g_autofree char *checkpointdir =3D NULL; + g_autofree char *pidfile =3D NULL; + g_autofree char *checkpointfd =3D NULL; + int pidfilefd; + char c; + + if (fd < 0) + goto cleanup; + + checkpointfd =3D g_strdup_printf("/proc/self/fd/%d", fd); + + if (virFileResolveLink(checkpointfd, &checkpointdir) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to readlink checkpoint dir path")); + goto cleanup; + } + + pidfile =3D g_strdup_printf("%s/restore.pid", checkpointdir); + + if ((pidfilefd =3D virFileOpenAs(pidfile, O_RDONLY, 0, -1, -1, 0)) < 0= ) { + virReportSystemError(pidfilefd, + _("Failed to open domain's pidfile '%s'"), + pidfile); + goto cleanup; + } + + while ((saferead(pidfilefd, &c, 1) =3D=3D 1) && c !=3D EOF) + initpid =3D initpid*10 + c - '0'; + + ret =3D initpid; + + if (virFileRemove(pidfile, -1, -1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to delete pidfile path")); + } + + cleanup: + VIR_FORCE_CLOSE(fd); + VIR_FORCE_CLOSE(pidfilefd); + return ret; +} + + static bool wantReboot; static virMutex lock =3D VIR_MUTEX_INITIALIZER; =20 @@ -2310,6 +2360,7 @@ virLXCControllerRun(virLXCControllerPtr ctrl) int rc =3D -1; int control[2] =3D { -1, -1}; int containerhandshake[2] =3D { -1, -1 }; + bool restore_mode =3D (ctrl->restore !=3D -1); char **containerTTYPaths =3D g_new0(char *, ctrl->nconsoles); size_t i; =20 @@ -2368,7 +2419,8 @@ virLXCControllerRun(virLXCControllerPtr ctrl) containerhandshake[1], ctrl->nsFDs, ctrl->nconsoles, - containerTTYPaths)) < 0) + containerTTYPaths, + ctrl->restore)) < 0) goto cleanup; VIR_FORCE_CLOSE(control[1]); VIR_FORCE_CLOSE(containerhandshake[1]); @@ -2380,10 +2432,10 @@ virLXCControllerRun(virLXCControllerPtr ctrl) for (i =3D 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) VIR_FORCE_CLOSE(ctrl->nsFDs[i]); =20 - if (virLXCControllerSetupCgroupLimits(ctrl) < 0) + if (!restore_mode && virLXCControllerSetupCgroupLimits(ctrl) < 0) goto cleanup; =20 - if (virLXCControllerSetupUserns(ctrl) < 0) + if (!restore_mode && virLXCControllerSetupUserns(ctrl) < 0) goto cleanup; =20 if (virLXCControllerMoveInterfaces(ctrl) < 0) @@ -2408,6 +2460,26 @@ virLXCControllerRun(virLXCControllerPtr ctrl) if (lxcControllerClearCapabilities() < 0) goto cleanup; =20 + if (restore_mode) { + int status; + int ret =3D waitpid(-1, &status, 0); + int initpid; + + VIR_DEBUG("Got sig child %d", ret); + + /* We have two basic cases here. + * - CRIU died bacause of restore error and we do not have a runni= ng container + * - CRIU detached itself from the running container + */ + if ((initpid =3D lxcControllerFindRestoredPid(ctrl->restore)) < 0)= { + virReportSystemError(errno, "%s", + _("Unable to get restored task pid")); + virNetDaemonQuit(ctrl->daemon); + goto cleanup; + } + ctrl->initpid =3D initpid; + } + for (i =3D 0; i < ctrl->nconsoles; i++) if (virLXCControllerConsoleSetNonblocking(&(ctrl->consoles[i])) < = 0) goto cleanup; @@ -2450,6 +2522,7 @@ int main(int argc, char *argv[]) char **veths =3D NULL; int ns_fd[VIR_LXC_DOMAIN_NAMESPACE_LAST]; int handshakeFd =3D -1; + int restore =3D -1; bool bg =3D false; const struct option options[] =3D { { "background", 0, NULL, 'b' }, @@ -2462,6 +2535,7 @@ int main(int argc, char *argv[]) { "share-net", 1, NULL, 'N' }, { "share-ipc", 1, NULL, 'I' }, { "share-uts", 1, NULL, 'U' }, + { "restore", 1, NULL, 'r' }, { "help", 0, NULL, 'h' }, { 0, 0, 0, 0 }, }; @@ -2488,7 +2562,7 @@ int main(int argc, char *argv[]) while (1) { int c; =20 - c =3D getopt_long(argc, argv, "dn:v:p:m:c:s:h:S:N:I:U:", + c =3D getopt_long(argc, argv, "dn:v:p:m:c:s:h:S:N:I:U:r:", options, NULL); =20 if (c =3D=3D -1) @@ -2560,6 +2634,14 @@ int main(int argc, char *argv[]) securityDriver =3D optarg; break; =20 + case 'r': + if (virStrToLong_i(optarg, NULL, 10, &restore) < 0) { + fprintf(stderr, "malformed --restore argument '%s'", + optarg); + goto cleanup; + } + break; + case 'h': case '?': fprintf(stderr, "\n"); @@ -2576,6 +2658,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " -N FD, --share-net FD\n"); fprintf(stderr, " -I FD, --share-ipc FD\n"); fprintf(stderr, " -U FD, --share-uts FD\n"); + fprintf(stderr, " -r FD, --restore FD\n"); fprintf(stderr, " -h, --help\n"); fprintf(stderr, "\n"); rc =3D 0; @@ -2628,6 +2711,8 @@ int main(int argc, char *argv[]) ctrl->passFDs =3D passFDs; ctrl->npassFDs =3D npassFDs; =20 + ctrl->restore =3D restore; + for (i =3D 0; i < VIR_LXC_DOMAIN_NAMESPACE_LAST; i++) { if (ns_fd[i] !=3D -1) { if (!ctrl->nsFDs) {/*allocate only once */ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 4416acf923..44306685f5 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -44,6 +44,7 @@ #include "lxc_driver.h" #include "lxc_native.h" #include "lxc_process.h" +#include "lxc_criu.h" #include "virnetdevbridge.h" #include "virnetdevveth.h" #include "virnetdevopenvswitch.h" @@ -1012,7 +1013,7 @@ static int lxcDomainCreateWithFiles(virDomainPtr dom, ret =3D virLXCProcessStart(dom->conn, driver, vm, nfiles, files, (flags & VIR_DOMAIN_START_AUTODESTROY), - VIR_DOMAIN_RUNNING_BOOTED); + -1, VIR_DOMAIN_RUNNING_BOOTED); =20 if (ret =3D=3D 0) { event =3D virDomainEventLifecycleNewFromObj(vm, @@ -1135,7 +1136,7 @@ lxcDomainCreateXMLWithFiles(virConnectPtr conn, if (virLXCProcessStart(conn, driver, vm, nfiles, files, (flags & VIR_DOMAIN_START_AUTODESTROY), - VIR_DOMAIN_RUNNING_BOOTED) < 0) { + -1, VIR_DOMAIN_RUNNING_BOOTED) < 0) { virDomainAuditStart(vm, "booted", false); virLXCDomainObjEndJob(driver, vm); if (!vm->persistent) @@ -2731,6 +2732,338 @@ static int lxcDomainResume(virDomainPtr dom) return ret; } =20 + +static int +lxcDoDomainSave(virLXCDriverPtr driver, virDomainObjPtr vm, + const char *to) +{ + virCapsPtr caps =3D NULL; + virLXCSaveHeader hdr; + virLXCDriverConfigPtr cfg =3D virLXCDriverGetConfig(driver); + g_autofree char *checkpointdir =3D NULL; + g_autofree char *criufile =3D NULL; + g_autofree char *xml =3D NULL; + uint32_t xml_len; + int compressed =3D 0; + int fd =3D -1; + int criufd =3D -1; + int ret =3D -1; + ssize_t r; + + if (!(caps =3D virLXCDriverGetCapabilities(driver, false))) + return -1; + + checkpointdir =3D g_path_get_dirname(to); + + if (lxcCriuDump(vm, checkpointdir) !=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to checkpoint domain with CRIU")); + goto cleanup; + } + + if ((compressed =3D lxcCriuCompress(checkpointdir, + cfg->saveImageFormat)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to compress criu files")); + goto cleanup; + } + + hdr.compressed =3D compressed; + + if ((fd =3D virFileOpenAs(to, O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR, -1, -1, 0)) < 0) { + virReportSystemError(-fd, + _("Failed to create domain save file '%s'"), = to); + goto cleanup; + } + + if ((xml =3D virDomainDefFormat(vm->def, driver->xmlopt, 0)) =3D=3D NU= LL) + goto cleanup; + + xml_len =3D strlen(xml) + 1; + + memset(&hdr, 0, sizeof(hdr)); + memcpy(hdr.magic, LXC_SAVE_MAGIC, sizeof(hdr.magic)); + hdr.version =3D LXC_SAVE_VERSION; + hdr.xmlLen =3D xml_len; + + if (safewrite(fd, &hdr, sizeof(hdr)) !=3D sizeof(hdr)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write save file header")); + goto cleanup; + } + + if (safewrite(fd, xml, xml_len) !=3D xml_len) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to write xml description")); + goto cleanup; + } + + criufile =3D g_strdup_printf("%s/criu.save", checkpointdir); + if ((criufd =3D virFileOpenAs(criufile, O_RDONLY, + 0, -1, -1, 0)) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to read criu file")); + goto cleanup; + } + + do { + char buf[1024]; + + if ((r =3D saferead(criufd, buf, sizeof(buf))) < 0) { + virReportSystemError(errno, + _("Unable to read from file '%s'"), + criufile); + goto cleanup; + } + + if (safewrite(fd, buf, r) < 0) { + virReportSystemError(errno, + _("Unable to write to file '%s'"), + to); + goto cleanup; + } + } while (r); + + if (virFileRemove(criufile, -1, -1) < 0) + VIR_WARN("failed to remove scratch file '%s'", + criufile); + + virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, + VIR_DOMAIN_SHUTOFF_SAVED); + + ret =3D 0; + cleanup: + VIR_FORCE_CLOSE(fd); + VIR_FORCE_CLOSE(criufd); + virObjectUnref(caps); + virObjectUnref(cfg); + return ret; +} + +static int +lxcDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml, + unsigned int flags) +{ + int ret =3D -1; + virLXCDriverPtr driver =3D dom->conn->privateData; + virDomainObjPtr vm; + bool remove_dom =3D false; + + virCheckFlags(0, -1); + if (dxml) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("xml modification unsupported")); + return -1; + } + + if (!(vm =3D lxcDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Domain is not running")); + goto endjob; + } + + if (lxcDoDomainSave(driver, vm, to) < 0) + goto endjob; + + if (!vm->persistent) + remove_dom =3D true; + + ret =3D 0; + + endjob: + virLXCDomainObjEndJob(driver, vm); + + cleanup: + if (remove_dom && vm) + virDomainObjListRemove(driver->domains, vm); + virDomainObjEndAPI(&vm); + return ret; +} + +static int +lxcDomainSave(virDomainPtr dom, const char *to) +{ + return lxcDomainSaveFlags(dom, to, NULL, 0); +} + +static int +lxcDomainRestoreFlags(virConnectPtr conn, const char *from, + const char* dxml, unsigned int flags) +{ + virLXCDriverPtr driver =3D conn->privateData; + virLXCDriverConfigPtr cfg =3D NULL; + virLXCSaveHeader hdr; + virDomainObjPtr vm =3D NULL; + virDomainDefPtr def =3D NULL; + virCapsPtr caps =3D NULL; + int ret =3D -1; + int restorefd; + g_autofree char *xml =3D NULL; + g_autofree char *xml_image_path =3D NULL; + g_autofree char *criufile =3D NULL; + g_autofree char *savedir =3D NULL; + g_autofree char *checkpointdir =3D NULL; + ssize_t r; + int criufd; + int fd; + + virCheckFlags(0, -1); + if (dxml) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("xml modification unsupported")); + goto out; + } + + if ((fd =3D virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) { + virReportSystemError(-fd, + _("Failed to open domain image file '%s'"), + xml_image_path); + goto out; + } + + if (saferead(fd, &hdr, sizeof(hdr)) !=3D sizeof(hdr)) { + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("failed to read lxc header")); + return -1; + } + + if (memcmp(hdr.magic, LXC_SAVE_MAGIC, sizeof(hdr.magic)) !=3D 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("image magic is incorrect")); + return -1; + } + + if (hdr.version > LXC_SAVE_VERSION) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("image version is not supported (%d > %d)"), + hdr.version, LXC_SAVE_VERSION); + return -1; + } + + cfg =3D virLXCDriverGetConfig(driver); + + xml =3D g_new0(char, hdr.xmlLen); + + if (saferead(fd, xml, hdr.xmlLen) !=3D hdr.xmlLen) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read X= ML")); + goto cleanup; + } + + checkpointdir =3D g_path_get_dirname(from); + + criufile =3D g_strdup_printf("%s/criu.save", checkpointdir); + if ((criufd =3D virFileOpenAs(criufile, O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR, -1, -1, 0)) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("Failed to read criu file")); + goto cleanup; + } + + do { + char buf[1024]; + + if ((r =3D saferead(fd, buf, sizeof(buf))) < 0) { + virReportSystemError(errno, + _("Unable to read from file '%s'"), + criufile); + goto cleanup; + } + + if (safewrite(criufd, buf, r) < 0) { + virReportSystemError(errno, + _("Unable to write to file '%s'"), + from); + goto cleanup; + } + } while (r); + + if (lxcCriuDecompress(checkpointdir, + cfg->saveImageFormat) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to decompress criu files")); + goto cleanup; + } + + if (!xml) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("no domain XML parsed")); + goto cleanup; + } + + if (!(caps =3D virLXCDriverGetCapabilities(driver, false))) + goto cleanup; + + if (!(def =3D virDomainDefParseString(xml, driver->xmlopt, caps, + VIR_DOMAIN_DEF_PARSE_INACTIVE))) + goto cleanup; + + if (virDomainRestoreFlagsEnsureACL(conn, def) < 0) + goto cleanup; + + if (!(vm =3D virDomainObjListAdd(driver->domains, def, + driver->xmlopt, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, + NULL))) + goto cleanup; + def =3D NULL; + + if (virLXCDomainObjBeginJob(driver, vm, LXC_JOB_MODIFY) < 0) { + if (!vm->persistent) + virDomainObjListRemove(driver->domains, vm); + goto cleanup; + } + + savedir =3D g_strdup_printf("%s/save/", checkpointdir); + + restorefd =3D open(savedir, O_DIRECTORY); + if (restorefd < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Can't open images dir")); + if (!vm->persistent) + virDomainObjListRemove(driver->domains, vm); + virLXCDomainObjEndJob(driver, vm); + goto cleanup; + } + + ret =3D virLXCProcessStart(conn, driver, vm, + 0, NULL, + 0, restorefd, + VIR_DOMAIN_RUNNING_RESTORED); + + VIR_FORCE_CLOSE(restorefd); + + if (ret < 0 && !vm->persistent) + virDomainObjListRemove(driver->domains, vm); + + virLXCDomainObjEndJob(driver, vm); + cleanup: + VIR_FORCE_CLOSE(fd); + VIR_FORCE_CLOSE(criufd); + out: + virDomainDefFree(def); + virDomainObjEndAPI(&vm); + virObjectUnref(cfg); + return ret; +} + +static int +lxcDomainRestore(virConnectPtr conn, const char *from) +{ + return lxcDomainRestoreFlags(conn, from, NULL, 0); +} + + static int lxcDomainOpenConsole(virDomainPtr dom, const char *dev_name, @@ -5088,6 +5421,10 @@ static virHypervisorDriver lxcHypervisorDriver =3D { .domainLookupByName =3D lxcDomainLookupByName, /* 0.4.2 */ .domainSuspend =3D lxcDomainSuspend, /* 0.7.2 */ .domainResume =3D lxcDomainResume, /* 0.7.2 */ + .domainSave =3D lxcDomainSave, /* x.x.x */ + .domainSaveFlags =3D lxcDomainSaveFlags, /* x.x.x */ + .domainRestore =3D lxcDomainRestore, /* x.x.x */ + .domainRestoreFlags =3D lxcDomainRestoreFlags, /* x.x.x */ .domainDestroy =3D lxcDomainDestroy, /* 0.4.4 */ .domainDestroyFlags =3D lxcDomainDestroyFlags, /* 0.9.4 */ .domainGetOSType =3D lxcDomainGetOSType, /* 0.4.2 */ diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index cbc04a3dcd..8dc8c42558 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -117,8 +117,8 @@ virLXCProcessReboot(virLXCDriverPtr driver, vm->newDef =3D NULL; virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN); vm->newDef =3D savedDef; - if (virLXCProcessStart(conn, driver, vm, - 0, NULL, autodestroy, reason) < 0) { + if (virLXCProcessStart(conn, driver, vm, 0, + NULL, autodestroy, -1, reason) < 0) { VIR_WARN("Unable to handle reboot of vm %s", vm->def->name); goto cleanup; @@ -942,7 +942,8 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driver, size_t nfiles, int handshakefd, int * const logfd, - const char *pidfile) + const char *pidfile, + int restorefd) { size_t i; g_autofree char *filterstr =3D NULL; @@ -1016,6 +1017,12 @@ virLXCProcessBuildControllerCmd(virLXCDriverPtr driv= er, for (i =3D 0; veths && veths[i]; i++) virCommandAddArgList(cmd, "--veth", veths[i], NULL); =20 + if (restorefd !=3D -1) { + virCommandAddArg(cmd, "--restore"); + virCommandAddArgFormat(cmd, "%d", restorefd); + virCommandPassFD(cmd, restorefd, 0); + } + virCommandPassFD(cmd, handshakefd, 0); virCommandDaemonize(cmd); virCommandSetPidFile(cmd, pidfile); @@ -1186,6 +1193,8 @@ virLXCProcessEnsureRootFS(virDomainObjPtr vm) * @driver: pointer to driver structure * @vm: pointer to virtual machine structure * @autoDestroy: mark the domain for auto destruction + * @restorefd: file descriptor pointing to the restore directory (-1 if not + * restoring) * @reason: reason for switching vm to running state * * Starts a vm @@ -1197,6 +1206,7 @@ int virLXCProcessStart(virConnectPtr conn, virDomainObjPtr vm, unsigned int nfiles, int *files, bool autoDestroy, + int restorefd, virDomainRunningReason reason) { int rc =3D -1, r; @@ -1388,7 +1398,8 @@ int virLXCProcessStart(virConnectPtr conn, files, nfiles, handshakefds[1], &logfd, - pidfile))) + pidfile, + restorefd))) goto cleanup; =20 /* now that we know it is about to start call the hook if present */ @@ -1491,6 +1502,9 @@ int virLXCProcessStart(virConnectPtr conn, if (!priv->machineName) goto cleanup; =20 + if (restorefd !=3D -1) + goto skip_cgroup_checks; + /* We know the cgroup must exist by this synchronization * point so lets detect that first, since it gives us a * more reliable way to kill everything off if something @@ -1507,6 +1521,8 @@ int virLXCProcessStart(virConnectPtr conn, goto cleanup; } =20 + skip_cgroup_checks: + /* And we can get the first monitor connection now too */ if (!(priv->monitor =3D virLXCProcessConnectMonitor(driver, vm))) { /* Intentionally overwrite the real monitor error message, @@ -1587,7 +1603,7 @@ virLXCProcessAutostartDomain(virDomainObjPtr vm, if (vm->autostart && !virDomainObjIsActive(vm)) { ret =3D virLXCProcessStart(data->conn, data->driver, vm, - 0, NULL, false, + 0, NULL, false, -1, VIR_DOMAIN_RUNNING_BOOTED); virDomainAuditStart(vm, "booted", ret >=3D 0); if (ret < 0) { diff --git a/src/lxc/lxc_process.h b/src/lxc/lxc_process.h index 383f6f714d..dab300784f 100644 --- a/src/lxc/lxc_process.h +++ b/src/lxc/lxc_process.h @@ -28,6 +28,7 @@ int virLXCProcessStart(virConnectPtr conn, virDomainObjPtr vm, unsigned int nfiles, int *files, bool autoDestroy, + int restorefd, virDomainRunningReason reason); int virLXCProcessStop(virLXCDriverPtr driver, virDomainObjPtr vm, --=20 2.27.0