From patchwork Wed Mar 17 16:32:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Gruzdev X-Patchwork-Id: 12146491 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BBD9CC433DB for ; Wed, 17 Mar 2021 16:52:28 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 52EDA64F4F for ; Wed, 17 Mar 2021 16:52:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 52EDA64F4F Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=virtuozzo.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:43906 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lMZPH-0001jb-CH for qemu-devel@archiver.kernel.org; Wed, 17 Mar 2021 12:52:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:36172) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMZ7S-0000tS-HA for qemu-devel@nongnu.org; Wed, 17 Mar 2021 12:34:02 -0400 Received: from relay.sw.ru ([185.231.240.75]:49892) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lMZ7Q-0004sM-N1 for qemu-devel@nongnu.org; Wed, 17 Mar 2021 12:34:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-Id:Date:Subject:From: Content-Type; bh=RrwxIBwXtwLmbUQ/MT7DER+r9mV6A3s/DhkSW9EIpng=; b=teFp42zdibli +2oIk6cy+8OIOBaR4ihZT92uG0f7cx0wtycZvJ8CEX8hFCWfifpwLH1RoUeq+x9t22WjLWvBFe7vv gY1fad2GkbRQp8IXRM1DwQ2nsYo+GUNiZeYilwonlGuGTNxyKlcp16R38miLHQD728n3PwvwpEG96 m05MM=; Received: from [192.168.15.248] (helo=andrey-MS-7B54.sw.ru) by relay.sw.ru with esmtp (Exim 4.94) (envelope-from ) id 1lMZ6p-0034yI-Qh; Wed, 17 Mar 2021 19:33:24 +0300 From: Andrey Gruzdev To: qemu-devel@nongnu.org Cc: Den Lunev , Eric Blake , Paolo Bonzini , Juan Quintela , "Dr . David Alan Gilbert" , Markus Armbruster , Peter Xu , Andrey Gruzdev Subject: [RFC PATCH 3/9] migration/snap-tool: Preparations to run code in main loop context Date: Wed, 17 Mar 2021 19:32:16 +0300 Message-Id: <20210317163222.182609-4-andrey.gruzdev@virtuozzo.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210317163222.182609-1-andrey.gruzdev@virtuozzo.com> References: <20210317163222.182609-1-andrey.gruzdev@virtuozzo.com> MIME-Version: 1.0 Received-SPF: pass client-ip=185.231.240.75; envelope-from=andrey.gruzdev@virtuozzo.com; helo=relay.sw.ru X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Major part of code is using QEMUFile and block layer routines, thus to take advantage from concurrent I/O operations we need to use coroutines and run in the the main loop context. Signed-off-by: Andrey Gruzdev --- include/qemu-snap.h | 3 +++ meson.build | 2 +- qemu-snap-handlers.c | 38 ++++++++++++++++++++++++++ qemu-snap.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 qemu-snap-handlers.c diff --git a/include/qemu-snap.h b/include/qemu-snap.h index b8e48bfcbb..b6fd779b13 100644 --- a/include/qemu-snap.h +++ b/include/qemu-snap.h @@ -32,4 +32,7 @@ typedef struct SnapLoadState { SnapSaveState *snap_save_get_state(void); SnapLoadState *snap_load_get_state(void); +int coroutine_fn snap_save_state_main(SnapSaveState *sn); +int coroutine_fn snap_load_state_main(SnapLoadState *sn); + #endif /* QEMU_SNAP_H */ diff --git a/meson.build b/meson.build index 11564165ba..252c55d6a3 100644 --- a/meson.build +++ b/meson.build @@ -2324,7 +2324,7 @@ if have_tools dependencies: [block, qemuutil], install: true) qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'), dependencies: [blockdev, qemuutil, gnutls], install: true) - qemu_snap = executable('qemu-snap', files('qemu-snap.c'), + qemu_snap = executable('qemu-snap', files('qemu-snap.c', 'qemu-snap-handlers.c'), dependencies: [blockdev, qemuutil, migration], install: true) subdir('storage-daemon') diff --git a/qemu-snap-handlers.c b/qemu-snap-handlers.c new file mode 100644 index 0000000000..bdc1911909 --- /dev/null +++ b/qemu-snap-handlers.c @@ -0,0 +1,38 @@ +/* + * QEMU External Snapshot Utility + * + * Copyright Virtuozzo GmbH, 2021 + * + * Authors: + * Andrey Gruzdev + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "sysemu/block-backend.h" +#include "qemu/coroutine.h" +#include "qemu/cutils.h" +#include "qemu/bitmap.h" +#include "qemu/error-report.h" +#include "io/channel-buffer.h" +#include "migration/qemu-file-channel.h" +#include "migration/qemu-file.h" +#include "migration/savevm.h" +#include "migration/ram.h" +#include "qemu-snap.h" + +/* Save snapshot data from incoming migration stream */ +int coroutine_fn snap_save_state_main(SnapSaveState *sn) +{ + /* TODO: implement */ + return 0; +} + +/* Load snapshot data and send it with outgoing migration stream */ +int coroutine_fn snap_load_state_main(SnapLoadState *sn) +{ + /* TODO: implement */ + return 0; +} diff --git a/qemu-snap.c b/qemu-snap.c index c9f8d7166a..ec56aa55d2 100644 --- a/qemu-snap.c +++ b/qemu-snap.c @@ -44,6 +44,14 @@ #define OPT_CACHE 256 #define OPT_AIO 257 +/* Snapshot task execution state */ +typedef struct SnapTaskState { + QEMUBH *bh; /* BH to enter task's coroutine */ + Coroutine *co; /* Coroutine to execute task */ + + int ret; /* Return code, -EINPROGRESS until complete */ +} SnapTaskState; + /* Parameters for snapshot saving */ typedef struct SnapSaveParams { const char *filename; /* QCOW2 image file name */ @@ -177,6 +185,51 @@ static BlockBackend *snap_open(const char *filename, int flags) return blk; } +static void coroutine_fn do_snap_save_co(void *opaque) +{ + SnapTaskState *task_state = opaque; + SnapSaveState *sn = snap_save_get_state(); + + /* Enter main routine */ + task_state->ret = snap_save_state_main(sn); +} + +static void coroutine_fn do_snap_load_co(void *opaque) +{ + SnapTaskState *task_state = opaque; + SnapLoadState *sn = snap_load_get_state(); + + /* Enter main routine */ + task_state->ret = snap_load_state_main(sn); +} + +/* We use BH to enter coroutine from the main loop context */ +static void enter_co_bh(void *opaque) +{ + SnapTaskState *task_state = opaque; + + qemu_coroutine_enter(task_state->co); + /* Delete BH once we entered coroutine from the main loop */ + qemu_bh_delete(task_state->bh); + task_state->bh = NULL; +} + +static int run_snap_task(CoroutineEntry *entry) +{ + SnapTaskState task_state; + + task_state.bh = qemu_bh_new(enter_co_bh, &task_state); + task_state.co = qemu_coroutine_create(entry, &task_state); + task_state.ret = -EINPROGRESS; + + qemu_bh_schedule(task_state.bh); + while (task_state.ret == -EINPROGRESS) { + main_loop_wait(false); + } + + return task_state.ret; +} + static int snap_save(const SnapSaveParams *params) { SnapSaveState *sn; @@ -191,6 +244,11 @@ static int snap_save(const SnapSaveParams *params) goto fail; } + res = run_snap_task(do_snap_save_co); + if (res) { + error_report("Failed to save snapshot: error=%d", res); + } + fail: snap_save_destroy_state(); @@ -210,6 +268,11 @@ static int snap_load(SnapLoadParams *params) goto fail; } + res = run_snap_task(do_snap_load_co); + if (res) { + error_report("Failed to load snapshot: error=%d", res); + } + fail: snap_load_destroy_state();