From patchwork Fri Mar 2 10:44:52 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wen Congyang X-Patchwork-Id: 144212 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3A9061007D3 for ; Fri, 2 Mar 2012 21:44:27 +1100 (EST) Received: from localhost ([::1]:54215 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S3PyL-0007SJ-1N for incoming@patchwork.ozlabs.org; Fri, 02 Mar 2012 05:44:25 -0500 Received: from eggs.gnu.org ([208.118.235.92]:40470) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S3Pxu-0007Qx-84 for qemu-devel@nongnu.org; Fri, 02 Mar 2012 05:44:18 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S3PxV-0003YB-7p for qemu-devel@nongnu.org; Fri, 02 Mar 2012 05:43:57 -0500 Received: from [222.73.24.84] (port=46355 helo=song.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S3PxU-0003Xm-BQ for qemu-devel@nongnu.org; Fri, 02 Mar 2012 05:43:33 -0500 X-IronPort-AV: E=Sophos;i="4.73,517,1325433600"; d="scan'208";a="4434314" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 02 Mar 2012 18:43:27 +0800 Received: from mailserver.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id q22AhS54028566; Fri, 2 Mar 2012 18:43:29 +0800 Received: from [10.167.225.226] ([10.167.225.226]) by mailserver.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.1FP4) with ESMTP id 2012030218413876-855039 ; Fri, 2 Mar 2012 18:41:38 +0800 Message-ID: <4F50A4A4.3070201@cn.fujitsu.com> Date: Fri, 02 Mar 2012 18:44:52 +0800 From: Wen Congyang User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.9) Gecko/20100413 Fedora/3.0.4-2.fc13 Thunderbird/3.0.4 MIME-Version: 1.0 To: qemu-devel , Jan Kiszka , Dave Anderson , HATAYAMA Daisuke , Luiz Capitulino , Eric Blake References: <4F509A00.80207@cn.fujitsu.com> In-Reply-To: <4F509A00.80207@cn.fujitsu.com> X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2012-03-02 18:41:38, Serialize by Router on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2012-03-02 18:41:40, Serialize complete at 2012-03-02 18:41:40 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 222.73.24.84 Subject: [Qemu-devel] [RFC][PATCH 14/16 v8] run dump at the background X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org The new monitor command dump may take long time to finish. So we need run it at the background. Signed-off-by: Wen Congyang --- dump.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- vl.c | 5 +- 2 files changed, 150 insertions(+), 23 deletions(-) diff --git a/dump.c b/dump.c index d569867..4c8038d 100644 --- a/dump.c +++ b/dump.c @@ -80,9 +80,21 @@ typedef struct DumpState { bool resume; char *error; target_phys_addr_t memory_offset; + + /* + * Return value: + * -2: EAGAIN + * -1: error + * 0: success + */ write_core_dump_function f; void (*cleanup)(void *opaque); + int (*dump_begin_iterate)(struct DumpState *, void *opaque); void *opaque; + RAMBlock *block; + ram_addr_t start; + target_phys_addr_t offset; + VMChangeStateEntry *handler; } DumpState; static DumpState *dump_get_current(void) @@ -100,6 +112,12 @@ static int dump_cleanup(DumpState *s) memory_mapping_list_free(&s->list); s->cleanup(s->opaque); + + if (s->handler) { + qemu_del_vm_change_state_handler(s->handler); + s->handler = NULL; + } + if (s->resume) { vm_start(); } @@ -373,40 +391,70 @@ static int write_elf_section(DumpState *s, target_phys_addr_t *offset, int type) return 0; } +/* + * Return value: + * -2: blocked + * -1: failed + * 0: sucess + */ static int write_data(DumpState *s, void *buf, int length, target_phys_addr_t *offset) { int ret; ret = s->f(*offset, buf, length, s->opaque); - if (ret < 0) { + if (ret == -1) { dump_error(s, "dump: failed to save memory.\n"); return -1; } + if (ret == -2) { + return -2; + } + *offset += length; return 0; } /* write the memroy to vmcore. 1 page per I/O. */ -static int write_memory(DumpState *s, RAMBlock *block, - target_phys_addr_t *offset) +static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, + target_phys_addr_t *offset, int64_t *size, + int64_t deadline) { int i, ret; + int64_t writen_size = 0; + int64_t time; - for (i = 0; i < block->length / TARGET_PAGE_SIZE; i++) { - ret = write_data(s, block->host + i * TARGET_PAGE_SIZE, + *size = block->length - start; + for (i = 0; i < *size / TARGET_PAGE_SIZE; i++) { + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, TARGET_PAGE_SIZE, offset); if (ret < 0) { - return -1; + *size = writen_size; + return ret; + } + + writen_size += TARGET_PAGE_SIZE; + time = qemu_get_clock_ms(rt_clock); + if (time >= deadline) { + /* time out */ + *size = writen_size; + return -2; } } - if ((block->length % TARGET_PAGE_SIZE) != 0) { - ret = write_data(s, block->host + i * TARGET_PAGE_SIZE, - block->length % TARGET_PAGE_SIZE, offset); + if ((*size % TARGET_PAGE_SIZE) != 0) { + ret = write_data(s, block->host + start + i * TARGET_PAGE_SIZE, + *size % TARGET_PAGE_SIZE, offset); if (ret < 0) { - return -1; + *size = writen_size; + return ret; + } + + time = qemu_get_clock_ms(rt_clock); + if (time >= deadline) { + /* time out */ + return -2; } } @@ -501,6 +549,7 @@ static int dump_begin(DumpState *s) } s->memory_offset = offset; + s->offset = offset; return 0; } @@ -528,22 +577,65 @@ static int dump_completed(DumpState *s) return 0; } -/* write all memory to vmcore */ -static int dump_iterate(DumpState *s) +static int get_next_block(DumpState *s, RAMBlock *block) +{ + while (1) { + block = QLIST_NEXT(block, next); + if (!block) { + /* no more block */ + return 1; + } + + s->start = 0; + s->block = block; + + return 0; + } +} + +/* write memory to vmcore */ +static void dump_iterate(void *opaque) { + DumpState *s = opaque; RAMBlock *block; - target_phys_addr_t offset = s->memory_offset; + target_phys_addr_t offset = s->offset; + int64_t size; + int64_t deadline, now; int ret; - /* write all memory to vmcore */ - QLIST_FOREACH(block, &ram_list.blocks, next) { - ret = write_memory(s, block, &offset); - if (ret < 0) { - return -1; + now = qemu_get_clock_ms(rt_clock); + deadline = now + 5; + while(1) { + block = s->block; + ret = write_memory(s, block, s->start, &offset, &size, deadline); + if (ret == -1) { + return; + } + + if (ret == -2) { + break; + } + + ret = get_next_block(s, block); + if (ret == 1) { + dump_completed(s); + return; } } - return dump_completed(s); + if (size == block->length - s->start) { + ret = get_next_block(s, block); + if (ret == 1) { + dump_completed(s); + return; + } + } else { + s->start += size; + } + + s->offset = offset; + + return; } static int create_vmcore(DumpState *s) @@ -555,7 +647,7 @@ static int create_vmcore(DumpState *s) return -1; } - ret = dump_iterate(s); + ret = s->dump_begin_iterate(s, s->opaque); if (ret < 0) { return -1; } @@ -563,6 +655,17 @@ static int create_vmcore(DumpState *s) return 0; } +static void dump_vm_state_change(void *opaque, int running, RunState state) +{ + DumpState *s = opaque; + + if (running) { + qmp_dump_cancel(NULL); + s->state = DUMP_STATE_ERROR; + s->error = g_strdup("vm state is changed to run\n"); + } +} + static DumpState *dump_init(bool paging, Error **errp) { CPUState *env; @@ -580,6 +683,9 @@ static DumpState *dump_init(bool paging, Error **errp) g_free(s->error); s->error = NULL; } + s->block = QLIST_FIRST(&ram_list.blocks); + s->start = 0; + s->handler = qemu_add_vm_change_state_handler(dump_vm_state_change, s); /* * get dump info: endian, class and architecture. @@ -639,14 +745,24 @@ static int fd_write_vmcore(target_phys_addr_t offset, void *buf, size_t size, ret = lseek(fd, offset, SEEK_SET); if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return -2; + } return -1; } ret = write(fd, buf, size); - if (ret != size) { + if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return -2; + } return -1; } + if (ret != size) { + return -2; + } + return 0; } @@ -655,10 +771,18 @@ static void fd_cleanup(void *opaque) int fd = (int)(intptr_t)opaque; if (fd != -1) { + qemu_set_fd_handler(fd, NULL, NULL, NULL); close(fd); } } +static int fd_dump_begin_iterate(DumpState *s, void *opaque) +{ + int fd = (int)(intptr_t)opaque; + + return qemu_set_fd_handler(fd, NULL, dump_iterate, s); +} + static DumpState *dump_init_fd(int fd, bool paging, Error **errp) { DumpState *s = dump_init(paging, errp); @@ -669,7 +793,9 @@ static DumpState *dump_init_fd(int fd, bool paging, Error **errp) s->f = fd_write_vmcore; s->cleanup = fd_cleanup; + s->dump_begin_iterate = fd_dump_begin_iterate; s->opaque = (void *)(intptr_t)fd; + fcntl(fd, F_SETFL, O_NONBLOCK); return s; } diff --git a/vl.c b/vl.c index 4a77696..0f31906 100644 --- a/vl.c +++ b/vl.c @@ -1249,11 +1249,12 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) void vm_state_notify(int running, RunState state) { - VMChangeStateEntry *e; + VMChangeStateEntry *e, *next; trace_vm_state_notify(running, state); - for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { + /* e->cb() may remove itself */ + QLIST_FOREACH_SAFE(e, &vm_change_state_head, entries, next) { e->cb(e->opaque, running, state); } }