From patchwork Tue Jun 12 17:33:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Cao, Lei" X-Patchwork-Id: 10460845 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 68AF76020F for ; Tue, 12 Jun 2018 17:40:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4CC8728B12 for ; Tue, 12 Jun 2018 17:40:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 281D328B9A; Tue, 12 Jun 2018 17:40:11 +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=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C035628B79 for ; Tue, 12 Jun 2018 17:40:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754209AbeFLRkE (ORCPT ); Tue, 12 Jun 2018 13:40:04 -0400 Received: from us-smtp-delivery-131.mimecast.com ([216.205.24.131]:48908 "EHLO us-smtp-delivery-131.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754223AbeFLRkC (ORCPT ); Tue, 12 Jun 2018 13:40:02 -0400 X-Greylist: delayed 408 seconds by postgrey-1.27 at vger.kernel.org; Tue, 12 Jun 2018 13:40:02 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=StratusTechnologies.onmicrosoft.com; s=selector1-stratus-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=yRQx1dXCgDxGsnfO0r+L/RCIbpY8LuZPmctxB9z11Es=; b=3a0WrIibSs6AGbH27QIt6GLK0l4pvyQj7Kzfrz1hta/363b3UjbDhwwRdWDPxJvGEKLBMFwTjjkYfCSPWb/5eXpQUPklj6vLkqB3c7/DtaepFqneAR0rO15wW1uPV0b+m5/W/W19ZLszovwlRNYRknILQH4bYbVDDoTYQNmo+bQ= Received: from NAM04-SN1-obe.outbound.protection.outlook.com (mail-sn1nam04lp0086.outbound.protection.outlook.com [216.32.180.86]) (Using TLS) by us-smtp-1.mimecast.com with ESMTP id us-mta-241-u41y7DyUOLqPo7DHvvmsAw-1; Tue, 12 Jun 2018 13:33:12 -0400 Received: from BYAPR08MB3973.namprd08.prod.outlook.com (52.135.194.143) by BYAPR08MB4391.namprd08.prod.outlook.com (20.176.249.154) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.841.15; Tue, 12 Jun 2018 17:33:09 +0000 Received: from BYAPR08MB3973.namprd08.prod.outlook.com ([fe80::d5b7:b17:722f:1905]) by BYAPR08MB3973.namprd08.prod.outlook.com ([fe80::d5b7:b17:722f:1905%4]) with mapi id 15.20.0841.019; Tue, 12 Jun 2018 17:33:09 +0000 From: "Cao, Lei" To: "kvm@vger.kernel.org" Subject: qemu 2.9 patch to support kernel ring-based dirty memory tracking Thread-Topic: qemu 2.9 patch to support kernel ring-based dirty memory tracking Thread-Index: AQHUAnNtGg3o11QKaEGriHWNYa8uYA== Date: Tue, 12 Jun 2018 17:33:08 +0000 Message-ID: References: <201806121729.w5CHTd2T025041@dev1.evr.stratus.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [198.97.42.5] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; BYAPR08MB4391; 7:pKuhW89OZfZwuzjoP7YtTGHlggN9gkdIv0jUDxc3f2WFBslVIJ+lyRvIoUXYvxylm5mmDomTKdHAdMjab6gAF25KxOX+2ToqJOABBSOL+4z04IWTNtX4KxpRtFPHC8hOTeIfFEeoOX3QbALm4M+S5BR7H76OMUw+i7O++rsRJhRbV+2w71FqkwjcaUtw9ETJSL9EiD6VTYgXG0GTbHeodYOk9VQe+zDwvC54x9IZEi7aA84jTxH8pV7OJ9q3md1f; 20:weleA1tc27R8YHOwL6L7bzvBUzD1ivZcsjLpkeKdr51JdWvh/S9xz7BrbF0Hmg+4YfxWpATaLoiHnsfhK/ySUVAB8I1r7q2mTULi/MA+L9mPig+BRcLw5myTcd4yFcwEawC/KdqAydweYDAL5n8C4lwUMMo7sfjOdpuHaUVM3IY= x-ms-exchange-antispam-srfa-diagnostics: SOS; x-microsoft-antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(5600026)(4534165)(4627221)(201703031133081)(201702281549075)(2017052603328)(7153060)(7193020); SRVR:BYAPR08MB4391; x-ms-traffictypediagnostic: BYAPR08MB4391: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(6040522)(2401047)(5005006)(8121501046)(3002001)(3231254)(944501410)(52105095)(93006095)(93001095)(10201501046)(149027)(150027)(6041310)(20161123564045)(20161123558120)(20161123560045)(20161123562045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011)(7699016); SRVR:BYAPR08MB4391; BCL:0; PCL:0; RULEID:; SRVR:BYAPR08MB4391; x-forefront-prvs: 07013D7479 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(39850400004)(376002)(396003)(366004)(39380400002)(346002)(199004)(189003)(6506007)(9686003)(86362001)(66066001)(575784001)(2900100001)(3660700001)(81156014)(5660300001)(7736002)(3280700002)(6916009)(5250100002)(2501003)(8676002)(14454004)(99286004)(53936002)(102836004)(76176011)(26005)(55016002)(59450400001)(186003)(8936002)(53946003)(7696005)(6116002)(2351001)(72206003)(478600001)(5640700003)(6436002)(476003)(2906002)(1730700003)(97736004)(305945005)(74316002)(81166006)(68736007)(105586002)(446003)(25786009)(3846002)(486006)(106356001)(316002)(33656002)(14143004); DIR:OUT; SFP:1102; SCL:1; SRVR:BYAPR08MB4391; H:BYAPR08MB3973.namprd08.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; x-microsoft-antispam-message-info: h+/dQQKEz5yoCCHPlNQXL0mOlWtnNklaFZPinptVOhg5XkBbjpEpDiiBcYArcDcNjaGw7yQ+a5wZKe6bCCnNmigy1wrjjlgcDI9qY9xB6uEGveiP6Ob/IDOOXOGsFqKBAtRi3NEjJy1HvAHfEGzdIZT7tFLLoG4eo8hoaEYhii4NXf4gXlCb7lVNqjsrR7Bq spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-MS-Office365-Filtering-Correlation-Id: da11d2eb-9cfa-4c0f-226f-08d5d08a907c X-OriginatorOrg: stratus.com X-MS-Exchange-CrossTenant-Network-Message-Id: da11d2eb-9cfa-4c0f-226f-08d5d08a907c X-MS-Exchange-CrossTenant-originalarrivaltime: 12 Jun 2018 17:33:08.9741 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: de36b473-b8ad-46ff-837f-9da16b8d1b77 X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR08MB4391 X-MC-Unique: u41y7DyUOLqPo7DHvvmsAw-1 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for kernel ring-based dirty memory tracking to qemu stable-2.9. Kernel support for ring-based dirty memory tracking is currently in the 'dirty-ring-buffer' branch of KVM, against which this patch was tested. The patch modifies the live migration code to utilize ring-based instead of bitmap-based dirty memory tracking. --- hw/usb/bus.c | 3 +- include/migration/migration.h | 6 ++ include/qom/cpu.h | 18 ++++++ include/sysemu/kvm.h | 10 +++ kvm-all.c | 138 ++++++++++++++++++++++++++++++++++++++++++ linux-headers/linux/kvm.h | 3 + migration/migration.c | 6 +- migration/ram.c | 102 ++++++++++++++++++++++++++++++- net/slirp.c | 9 ++- 9 files changed, 288 insertions(+), 7 deletions(-) diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 24f1608..50b6913 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -407,8 +407,9 @@ void usb_register_companion(const char *masterbus, USBPort *ports[], void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr) { if (upstream) { - snprintf(downstream->path, sizeof(downstream->path), "%s.%d", + int l = snprintf(downstream->path, sizeof(downstream->path), "%s.%d", upstream->path, portnr); + assert(l < sizeof(downstream->path)); downstream->hubcount = upstream->hubcount + 1; } else { snprintf(downstream->path, sizeof(downstream->path), "%d", portnr); diff --git a/include/migration/migration.h b/include/migration/migration.h index 5720c88..08d1b31 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -385,4 +385,10 @@ uint64_t ram_pagesize_summary(void); PostcopyState postcopy_state_get(void); /* Set the state and return the old state */ PostcopyState postcopy_state_set(PostcopyState new_state); + +#ifdef KVM_CAP_DIRTY_LOG_RING +int get_dirty_count_from_ring(void); +int fetch_dirty_pages(bool); +#endif + #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 5d10359..6839b5b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -231,6 +231,24 @@ struct CPUWatchpoint { struct KVMState; struct kvm_run; +#ifdef KVM_CAP_DIRTY_LOG_RING +struct dirty_gfn { + uint32_t pad; + uint32_t slot; + uint64_t offset; +}; + +struct dirty_ring { + union { + struct { + uint16_t avail_index; + uint16_t fetch_index; + } indices; + struct dirty_gfn dirty_gfns[0]; /* slot/offset */ + }; +}; +#endif + struct hax_vcpu_state; #define TB_JMP_CACHE_BITS 12 diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 24281fc..f283d7d 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -227,6 +227,16 @@ int kvm_init_vcpu(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu); int kvm_destroy_vcpu(CPUState *cpu); +#ifdef KVM_CAP_DIRTY_LOG_RING +struct dirty_page { + RAMBlock *block; + ram_addr_t offset; +}; +int kvm_get_dirty_page_count(void); +void kvm_sync_dirty_page_from_ring(struct dirty_page *pages, + int *dirty_index, int max); +#endif + #ifdef NEED_CPU_H #include "cpu.h" diff --git a/kvm-all.c b/kvm-all.c index 90b8573..5ee57ef 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -62,6 +62,10 @@ #define KVM_MSI_HASHTAB_SIZE 256 +#ifdef KVM_CAP_DIRTY_LOG_RING +#define KVM_DIRTY_LOG_PAGE_NUM 16 +#endif + struct KVMParkedVcpu { unsigned long vcpu_id; int kvm_fd; @@ -102,6 +106,10 @@ struct KVMState #endif KVMMemoryListener memory_listener; QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; +#ifdef KVM_CAP_DIRTY_LOG_RING + struct dirty_ring *dirty_logs; + int max_dirty_logs; +#endif }; KVMState *kvm_state; @@ -301,6 +309,99 @@ static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id) return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id); } +#ifdef KVM_CAP_DIRTY_LOG_RING +int kvm_get_dirty_page_count(void) +{ + CPUState *cpu; + struct dirty_ring *ring; + unsigned int avail, fetch; + int total = 0; + + CPU_FOREACH(cpu) { + ring = (void *)cpu->kvm_run + 64 * PAGE_SIZE; + avail = ring->indices.avail_index; + fetch = ring->indices.fetch_index; + total += (avail-fetch)%kvm_state->max_dirty_logs; + } + + ring = kvm_state->dirty_logs; + avail = ring->indices.avail_index; + fetch = ring->indices.fetch_index; + total += (avail-fetch)%kvm_state->max_dirty_logs; + + return total; +} + +void kvm_sync_dirty_page_from_ring(struct dirty_page *pages, + int *dirty_index, + int max) +{ + CPUState *cpu; + int i, j; + struct dirty_ring *ring; + unsigned int avail; + void *host; + int as_id; + uint16_t slot_id; + int index = 0; + + CPU_FOREACH(cpu) { + ring = (void *)cpu->kvm_run + 64 * PAGE_SIZE; + avail = ring->indices.avail_index; + while(ring->indices.fetch_index != avail) { + for (i = 0; i < kvm_state->nr_slots; i++) { + j = ring->indices.fetch_index & (kvm_state->max_dirty_logs-1); + as_id = ring->dirty_gfns[j].slot >> 16; + slot_id = (uint16_t)ring->dirty_gfns[j].slot; + if ((kvm_state->memory_listener.as_id == as_id) && + (kvm_state->memory_listener.slots[i].slot == slot_id)) { + host = kvm_state->memory_listener.slots[i].ram + + (ring->dirty_gfns[j].offset << TARGET_PAGE_BITS); + pages[*dirty_index+index].block = qemu_ram_block_from_host(host, 0, + &pages[*dirty_index+index].offset); + index++; + if (index == max) { + ring->indices.fetch_index++; + goto reset; + } + } + } + ring->indices.fetch_index++; + } + } + + ring = kvm_state->dirty_logs; + avail = ring->indices.avail_index; + while(ring->indices.fetch_index != avail) { + for (i = 0; i < kvm_state->nr_slots; i++) { + j = ring->indices.fetch_index & (kvm_state->max_dirty_logs-1); + as_id = ring->dirty_gfns[j].slot >> 16; + slot_id = (uint16_t)ring->dirty_gfns[j].slot; + if ((kvm_state->memory_listener.as_id == as_id) && + (kvm_state->memory_listener.slots[i].slot == slot_id)) { + host = kvm_state->memory_listener.slots[i].ram + + (ring->dirty_gfns[j].offset << TARGET_PAGE_BITS); + pages[*dirty_index+index].block = qemu_ram_block_from_host(host, 0, + &pages[*dirty_index+index].offset); + index++; + if (index == max) { + ring->indices.fetch_index++; + goto reset; + } + } + } + ring->indices.fetch_index++; + } + +reset: + if (index) { + kvm_vm_ioctl(kvm_state, KVM_RESET_DIRTY_PAGES); + } + + *dirty_index += index; +} +#endif + int kvm_init_vcpu(CPUState *cpu) { KVMState *s = kvm_state; @@ -326,8 +427,13 @@ int kvm_init_vcpu(CPUState *cpu) goto err; } +#ifdef KVM_CAP_DIRTY_LOG_RING + cpu->kvm_run = mmap(NULL, (64+KVM_DIRTY_LOG_PAGE_NUM)*PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, cpu->kvm_fd, 0); +#else cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, cpu->kvm_fd, 0); +#endif if (cpu->kvm_run == MAP_FAILED) { ret = -errno; DPRINTF("mmap'ing vcpu state failed\n"); @@ -1581,6 +1687,9 @@ static int kvm_init(MachineState *ms) int ret; int type = 0; const char *kvm_type; +#ifdef KVM_CAP_DIRTY_LOG_RING + int size = KVM_DIRTY_LOG_PAGE_NUM*PAGE_SIZE; +#endif s = KVM_STATE(ms->accelerator); @@ -1684,6 +1793,24 @@ static int kvm_init(MachineState *ms) } s->vmfd = ret; + +#ifdef KVM_CAP_DIRTY_LOG_RING + ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, size); + if (ret < 0) { + fprintf(stderr, "ioctl KVM_CAP_DIRTY_LOG_RING %d: failed: %d %s\n", size, -ret, + strerror(-ret)); + goto err; + } + s->max_dirty_logs = size/sizeof(struct dirty_gfn); + s->dirty_logs = mmap(NULL, KVM_DIRTY_LOG_PAGE_NUM*PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, s->vmfd, 0); + if (s->dirty_logs == MAP_FAILED) { + ret = -errno; + fprintf(stderr, "mmap'ing vm dirty logs failed\n"); + goto err; + } +#endif + missing_cap = kvm_check_extension_list(s, kvm_required_capabilites); if (!missing_cap) { missing_cap = @@ -1951,6 +2078,8 @@ static void kvm_eat_signals(CPUState *cpu) } while (sigismember(&chkset, SIG_IPI)); } +extern int fetch_dirty_pages(bool); + int kvm_cpu_exec(CPUState *cpu) { struct kvm_run *run = cpu->kvm_run; @@ -2005,6 +2134,15 @@ int kvm_cpu_exec(CPUState *cpu) if (run_ret < 0) { if (run_ret == -EINTR || run_ret == -EAGAIN) { +#ifdef KVM_CAP_DIRTY_LOG_RING + if ((run_ret == -EINTR) && (run->exit_reason == KVM_EXIT_DIRTY_LOG_FULL)) { + //error_report("kvm dirty log full\n"); + ret = fetch_dirty_pages(true); + kvm_eat_signals(cpu); + continue; + } +#endif + DPRINTF("io window exit\n"); kvm_eat_signals(cpu); ret = EXCP_INTERRUPT; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 4e082a8..0546d0a 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -205,6 +205,7 @@ struct kvm_hyperv_exit { #define KVM_EXIT_S390_STSI 25 #define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_HYPERV 27 +#define KVM_EXIT_DIRTY_LOG_FULL 28 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -883,6 +884,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_MMU_RADIX 134 #define KVM_CAP_PPC_MMU_HASH_V3 135 #define KVM_CAP_IMMEDIATE_EXIT 136 +#define KVM_CAP_DIRTY_LOG_RING 151 #ifdef KVM_CAP_IRQ_ROUTING @@ -1300,6 +1302,7 @@ struct kvm_s390_ucas_mapping { #define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state) /* Available with KVM_CAP_X86_SMM */ #define KVM_SMI _IO(KVMIO, 0xb7) +#define KVM_RESET_DIRTY_PAGES _IO(KVMIO, 0xba) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) diff --git a/migration/migration.c b/migration/migration.c index ad4036f..63b8a0f 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -17,6 +17,7 @@ #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "linux/kvm.h" #include "migration/migration.h" #include "migration/qemu-file.h" #include "sysemu/sysemu.h" @@ -1959,10 +1960,13 @@ static void *migration_thread(void *opaque) if (!qemu_file_rate_limit(s->to_dst_file)) { uint64_t pend_post, pend_nonpost; - qemu_savevm_state_pending(s->to_dst_file, max_size, &pend_nonpost, &pend_post); +#ifdef KVM_CAP_DIRTY_LOG_RING + pending_size = pend_nonpost + pend_post + get_dirty_count_from_ring(); +#else pending_size = pend_nonpost + pend_post; +#endif trace_migrate_pending(pending_size, max_size, pend_post, pend_nonpost); if (pending_size && pending_size >= max_size) { diff --git a/migration/ram.c b/migration/ram.c index de1e0a3..05b1dff 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -35,6 +35,7 @@ #include "qemu/bitmap.h" #include "qemu/timer.h" #include "qemu/main-loop.h" +#include "linux/kvm.h" #include "migration/migration.h" #include "migration/postcopy-ram.h" #include "exec/address-spaces.h" @@ -44,6 +45,7 @@ #include "exec/ram_addr.h" #include "qemu/rcu_queue.h" #include "migration/colo.h" +#include "sysemu/kvm.h" static int dirty_rate_high_cnt; @@ -230,6 +232,8 @@ struct PageSearchStatus { ram_addr_t offset; /* Set once we wrap around */ bool complete_round; + /* page is from dirty ring */ + bool from_ring; }; typedef struct PageSearchStatus PageSearchStatus; @@ -1055,6 +1059,70 @@ static bool find_dirty_block(QEMUFile *f, PageSearchStatus *pss, } } +#ifdef KVM_CAP_DIRTY_LOG_RING +#define NUM_DIRTY_PAGES 1024*1024 +struct dirty_page *pages; +static pthread_mutex_t pages_mutex = PTHREAD_MUTEX_INITIALIZER; +int dirty_index = 0; +int fetch_index = 0; + +int fetch_dirty_pages(bool lock) +{ + if (lock) + pthread_mutex_lock(&pages_mutex); + if (!pages) + pages = malloc(sizeof(struct dirty_page)*NUM_DIRTY_PAGES); + + if (!(NUM_DIRTY_PAGES-dirty_index)) + error_report("dirty ring full\n"); + else + kvm_sync_dirty_page_from_ring(pages, &dirty_index, NUM_DIRTY_PAGES-dirty_index); + + if (lock) + pthread_mutex_unlock(&pages_mutex); + + return 0; +} + +static bool find_dirty_block_from_ring(QEMUFile *f, PageSearchStatus *pss, + bool *again, ram_addr_t *ram_addr_abs, bool last) +{ + bool found = false; + + *again = true; + + pthread_mutex_lock(&pages_mutex); + fetch_dirty_pages(false); + if (!dirty_index) { + if (last) + *again = false; + goto out; + } + + if (fetch_index < dirty_index) { + pss->block = pages[fetch_index].block; + pss->offset = pages[fetch_index].offset; + *ram_addr_abs = pss->block->offset + pss->offset; + found = true; + fetch_index++; + } + + if (dirty_index == fetch_index) { + dirty_index = 0; + fetch_index = 0; + } + +out: + pthread_mutex_unlock(&pages_mutex); + return found; +} + +int get_dirty_count_from_ring(void) +{ + return kvm_get_dirty_page_count() * TARGET_PAGE_SIZE; +} +#endif + /* * Helper for 'get_queued_page' - gets a page off the queue * ms: MigrationState in @@ -1264,7 +1332,7 @@ static int ram_save_target_page(MigrationState *ms, QEMUFile *f, int res = 0; /* Check the pages is dirty and if it is send it */ - if (migration_bitmap_clear_dirty(dirty_ram_abs)) { + if (pss->from_ring || migration_bitmap_clear_dirty(dirty_ram_abs)) { unsigned long *unsentmap; if (compression_switch && migrate_use_compression()) { res = ram_save_compressed_page(ms, f, pss, @@ -1364,6 +1432,10 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, bool again, found; ram_addr_t dirty_ram_abs; /* Address of the start of the dirty page in ram_addr_t space */ +#ifdef KVM_CAP_DIRTY_LOG_RING + PageSearchStatus pss_ring; +#endif + PageSearchStatus *ptr = NULL; /* No dirty page as there is zero RAM */ if (!ram_bytes_total()) { @@ -1373,6 +1445,7 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, pss.block = last_seen_block; pss.offset = last_offset; pss.complete_round = false; + pss.from_ring = false; if (!pss.block) { pss.block = QLIST_FIRST_RCU(&ram_list.blocks); @@ -1381,14 +1454,32 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, do { again = true; found = get_queued_page(ms, &pss, &dirty_ram_abs); + if (found) + ptr = &pss; if (!found) { /* priority queue empty, so just search for something dirty */ found = find_dirty_block(f, &pss, &again, &dirty_ram_abs); + if (found) { + ptr = &pss; + } } +#ifdef KVM_CAP_DIRTY_LOG_RING + if (!found && !again) { + pss_ring.block = NULL; + pss_ring.offset = 0; + pss_ring.complete_round = false; + pss_ring.from_ring = true; + found = find_dirty_block_from_ring(f, &pss_ring, &again, &dirty_ram_abs, last_stage); + if (found) { + ptr = &pss_ring; + } + } +#endif + if (found) { - pages = ram_save_host_page(ms, f, &pss, + pages = ram_save_host_page(ms, f, ptr, last_stage, bytes_transferred, dirty_ram_abs); } @@ -1415,6 +1506,7 @@ void acct_update_position(QEMUFile *f, size_t size, bool zero) static ram_addr_t ram_save_remaining(void) { return migration_dirty_pages; + } uint64_t ram_bytes_remaining(void) @@ -1979,7 +2071,9 @@ static int ram_save_init_globals(void) migration_dirty_pages = ram_bytes_total() >> TARGET_PAGE_BITS; memory_global_dirty_log_start(); +#ifndef KVM_CAP_DIRTY_LOG_RING migration_bitmap_sync(); +#endif qemu_mutex_unlock_ramlist(); qemu_mutex_unlock_iothread(); rcu_read_unlock(); @@ -2097,7 +2191,9 @@ static int ram_save_complete(QEMUFile *f, void *opaque) rcu_read_lock(); if (!migration_in_postcopy(migrate_get_current())) { +#ifndef KVM_CAP_DIRTY_LOG_RING migration_bitmap_sync(); +#endif } ram_control_before_iterate(f, RAM_CONTROL_FINISH); @@ -2136,11 +2232,13 @@ static void ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size, if (!migration_in_postcopy(migrate_get_current()) && remaining_size < max_size) { +#ifndef KVM_CAP_DIRTY_LOG_RING qemu_mutex_lock_iothread(); rcu_read_lock(); migration_bitmap_sync(); rcu_read_unlock(); qemu_mutex_unlock_iothread(); +#endif remaining_size = ram_save_remaining() * TARGET_PAGE_SIZE; } diff --git a/net/slirp.c b/net/slirp.c index f97ec23..4471af3 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -562,7 +562,8 @@ static void slirp_smb_cleanup(SlirpState *s) int ret; if (s->smb_dir[0] != '\0') { - snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); + int l = snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); + assert(l < 128); ret = system(cmd); if (ret == -1 || !WIFEXITED(ret)) { error_report("'%s' failed.", cmd); @@ -606,7 +607,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, s->smb_dir[0] = 0; return -1; } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); + int l = snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); + assert(l < 128); f = fopen(smb_conf, "w"); if (!f) { @@ -651,8 +653,9 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, ); fclose(f); - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -l %s -s %s", + l = snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -l %s -s %s", CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf); + assert(l < 128); if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 || slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) {