From patchwork Fri Jan 19 13:44:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhang Chen X-Patchwork-Id: 10175347 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3A31A60386 for ; Fri, 19 Jan 2018 13:54:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 26F8028543 for ; Fri, 19 Jan 2018 13:54:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1A7F228698; Fri, 19 Jan 2018 13:54:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 413D028543 for ; Fri, 19 Jan 2018 13:54:53 +0000 (UTC) Received: from localhost ([::1]:50493 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ecX88-0002Fh-JG for patchwork-qemu-devel@patchwork.kernel.org; Fri, 19 Jan 2018 08:54:52 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46690) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ecX08-0003pD-HW for qemu-devel@nongnu.org; Fri, 19 Jan 2018 08:46:38 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ecX04-0003GM-4v for qemu-devel@nongnu.org; Fri, 19 Jan 2018 08:46:36 -0500 Received: from mail-pf0-x244.google.com ([2607:f8b0:400e:c00::244]:44427) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ecX03-0003Fv-T2 for qemu-devel@nongnu.org; Fri, 19 Jan 2018 08:46:32 -0500 Received: by mail-pf0-x244.google.com with SMTP id m26so1386892pfj.11 for ; Fri, 19 Jan 2018 05:46:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sGihzN6AqmRwDgyPk7qcLYr2oDEPUv2W9jiaot/+gyc=; b=Ymsztuf8mDRfZKY6FI6DrFsoc1ffLC5rKm23x8yABFvE1Kg682qS3oW0oytZm8y55C BmLHIiUwjWkXPy6fT1ffj4B0N11cBo46nP47UdjPwlhmom3rU87xUqEqWJ9gFTFiMOnN co11W9k/kzsBVxqdAFiGgIuIqezikPa0+pF4MRc9OO0rcZhyRiSA2hekKccW4lqCZcHI 30f9uwW0vifhqyXiu3tTl+c+4kmZvzGa40zQGKR0oToDWk4fYvBZwJNibEokc4WxV1rO 7d+dDjcJhm3sOhDsZ9/HgGcVmhOpAKCUfnVh71pABoqAi3OPmEj5wFhbzlf7NYihaUWd 21MA== 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; bh=sGihzN6AqmRwDgyPk7qcLYr2oDEPUv2W9jiaot/+gyc=; b=TTHcsvuS5xeyR/NYRm3Vn59bUonGq+AWltWOk29wdw2ZRm2fIU/neCfqYcxlkK5s2j sNg8Y3esMR1/URrkP+llbk0cAmsD5wohMIAYm7ObcMgD73gXKAXMHDCrM1Onq+XgAMxH M5ZVsCCgFap5NoDuqwsINTifDedBVZEmG0RSDmgw0caoLcnRixCjnuhx5J4IePFSrENi YSJk8XMLUhyDRD4qm9ixoX6AjOzETrW7EXvSKGQT4s2AAkjsAVJD+GxTudAjXFKcK51/ 08RAXHQfVMWGYoY9UiFEzaphUsMqTDBVcSs6hYcjDojVmlqUCcBLaiS5FiSBsJ2U4xdP VSCQ== X-Gm-Message-State: AKwxytcBGAYZL6SyRXdCwfqUVoA3pFQTtbv5+t2JiVgjzi+YGYgGgWVu FrhCpl3JQispyh2pWUyrLiprxzWB X-Google-Smtp-Source: ACJfBosDn9HtAg+/IgSKHNC9qK6nS9QGo+fdWxDf5q4TDRORcULrcV9SeS/4/62VmBpA1c1l6vv2UQ== X-Received: by 10.98.206.1 with SMTP id y1mr35689403pfg.136.1516369590586; Fri, 19 Jan 2018 05:46:30 -0800 (PST) Received: from localhost.localdomain (120.236.201.35.bc.googleusercontent.com. [35.201.236.120]) by smtp.gmail.com with ESMTPSA id r88sm14251865pfb.17.2018.01.19.05.46.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 19 Jan 2018 05:46:29 -0800 (PST) From: Zhang Chen To: qemu-devel@nongnu.org Date: Fri, 19 Jan 2018 21:44:36 +0800 Message-Id: <1516369485-5374-8-git-send-email-zhangckid@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516369485-5374-1-git-send-email-zhangckid@gmail.com> References: <1516369485-5374-1-git-send-email-zhangckid@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c00::244 Subject: [Qemu-devel] [PATCH V4 07/16] COLO: Load dirty pages into SVM's RAM cache firstly X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: zhanghailiang , Li Zhijian , Juan Quintela , Jason Wang , "Dr . David Alan Gilbert" , Markus Armbruster , Zhang Chen , Paolo Bonzini Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: zhanghailiang We should not load PVM's state directly into SVM, because there maybe some errors happen when SVM is receving data, which will break SVM. We need to ensure receving all data before load the state into SVM. We use an extra memory to cache these data (PVM's ram). The ram cache in secondary side is initially the same as SVM/PVM's memory. And in the process of checkpoint, we cache the dirty pages of PVM into this ram cache firstly, so this ram cache always the same as PVM's memory at every checkpoint, then we flush this cached ram to SVM after we receive all PVM's state. Signed-off-by: zhanghailiang Signed-off-by: Li Zhijian Signed-off-by: Zhang Chen --- include/exec/ram_addr.h | 1 + migration/migration.c | 2 + migration/ram.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++-- migration/ram.h | 4 ++ migration/savevm.c | 2 +- 5 files changed, 102 insertions(+), 4 deletions(-) diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 7633ef6..15e2474 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -27,6 +27,7 @@ struct RAMBlock { struct rcu_head rcu; struct MemoryRegion *mr; uint8_t *host; + uint8_t *colo_cache; /* For colo, VM's ram cache */ ram_addr_t offset; ram_addr_t used_length; ram_addr_t max_length; diff --git a/migration/migration.c b/migration/migration.c index 6042ee3..be8defd 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -387,6 +387,8 @@ static void process_incoming_migration_co(void *opaque) /* Wait checkpoint incoming thread exit before free resource */ qemu_thread_join(&mis->colo_incoming_thread); + /* We hold the global iothread lock, so it is safe here */ + colo_release_ram_cache(); } if (ret < 0) { diff --git a/migration/ram.c b/migration/ram.c index cb1950f..6460777 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2467,6 +2467,20 @@ static inline void *host_from_ram_block_offset(RAMBlock *block, return block->host + offset; } +static inline void *colo_cache_from_block_offset(RAMBlock *block, + ram_addr_t offset) +{ + if (!offset_in_ramblock(block, offset)) { + return NULL; + } + if (!block->colo_cache) { + error_report("%s: colo_cache is NULL in block :%s", + __func__, block->idstr); + return NULL; + } + return block->colo_cache + offset; +} + /** * ram_handle_compressed: handle the zero page case * @@ -2620,6 +2634,55 @@ static void decompress_data_with_multi_threads(QEMUFile *f, qemu_mutex_unlock(&decomp_done_lock); } +/* + * colo cache: this is for secondary VM, we cache the whole + * memory of the secondary VM, it is need to hold the global lock + * to call this helper. + */ +int colo_init_ram_cache(void) +{ + RAMBlock *block; + + rcu_read_lock(); + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + block->colo_cache = qemu_anon_ram_alloc(block->used_length, NULL); + if (!block->colo_cache) { + error_report("%s: Can't alloc memory for COLO cache of block %s," + "size 0x" RAM_ADDR_FMT, __func__, block->idstr, + block->used_length); + goto out_locked; + } + } + rcu_read_unlock(); + return 0; + +out_locked: + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + if (block->colo_cache) { + qemu_anon_ram_free(block->colo_cache, block->used_length); + block->colo_cache = NULL; + } + } + + rcu_read_unlock(); + return -errno; +} + +/* It is need to hold the global lock to call this helper */ +void colo_release_ram_cache(void) +{ + RAMBlock *block; + + rcu_read_lock(); + QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { + if (block->colo_cache) { + qemu_anon_ram_free(block->colo_cache, block->used_length); + block->colo_cache = NULL; + } + } + rcu_read_unlock(); +} + /** * ram_load_setup: Setup RAM for migration incoming side * @@ -2633,6 +2696,7 @@ static int ram_load_setup(QEMUFile *f, void *opaque) xbzrle_load_setup(); compress_threads_load_setup(); ramblock_recv_map_init(); + return 0; } @@ -2646,6 +2710,7 @@ static int ram_load_cleanup(void *opaque) g_free(rb->receivedmap); rb->receivedmap = NULL; } + return 0; } @@ -2846,7 +2911,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) while (!postcopy_running && !ret && !(flags & RAM_SAVE_FLAG_EOS)) { ram_addr_t addr, total_ram_bytes; - void *host = NULL; + void *host = NULL, *host_bak = NULL; uint8_t ch; addr = qemu_get_be64(f); @@ -2866,13 +2931,36 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) RAM_SAVE_FLAG_COMPRESS_PAGE | RAM_SAVE_FLAG_XBZRLE)) { RAMBlock *block = ram_block_from_stream(f, flags); - host = host_from_ram_block_offset(block, addr); + /* + * After going into COLO, we should load the Page into colo_cache + * NOTE: We need to keep a copy of SVM's ram in colo_cache. + * Privously, we copied all these memory in preparing stage of COLO + * while we need to stop VM, which is a time-consuming process. + * Here we optimize it by a trick, back-up every page while in + * migration process while COLO is enabled, though it affects the + * speed of the migration, but it obviously reduce the downtime of + * back-up all SVM'S memory in COLO preparing stage. + */ + if (migration_incoming_in_colo_state()) { + host = colo_cache_from_block_offset(block, addr); + /* After goes into COLO state, don't backup it any more */ + if (!migration_incoming_in_colo_state()) { + host_bak = host; + } + } + if (!migration_incoming_in_colo_state()) { + host = host_from_ram_block_offset(block, addr); + } if (!host) { error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); ret = -EINVAL; break; } - ramblock_recv_bitmap_set(block, host); + + if (!migration_incoming_in_colo_state()) { + ramblock_recv_bitmap_set(block, host); + } + trace_ram_load_loop(block->idstr, (uint64_t)addr, flags, host); } @@ -2967,6 +3055,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) if (!ret) { ret = qemu_file_get_error(f); } + if (!ret && host_bak && host) { + memcpy(host_bak, host, TARGET_PAGE_SIZE); + } } wait_for_decompress_done(); diff --git a/migration/ram.h b/migration/ram.h index 64d81e9..07abf71 100644 --- a/migration/ram.h +++ b/migration/ram.h @@ -62,4 +62,8 @@ int ramblock_recv_bitmap_test(RAMBlock *rb, void *host_addr); void ramblock_recv_bitmap_set(RAMBlock *rb, void *host_addr); void ramblock_recv_bitmap_set_range(RAMBlock *rb, void *host_addr, size_t nr); +/* ram cache */ +int colo_init_ram_cache(void); +void colo_release_ram_cache(void); + #endif diff --git a/migration/savevm.c b/migration/savevm.c index cd753c4..c582716 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1762,7 +1762,7 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) static int loadvm_process_enable_colo(MigrationIncomingState *mis) { migration_incoming_enable_colo(); - return 0; + return colo_init_ram_cache(); } /*