From patchwork Sun Nov 25 02:03:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: pingfan liu X-Patchwork-Id: 201508 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 D93842C008E for ; Sun, 25 Nov 2012 13:06:43 +1100 (EST) Received: from localhost ([::1]:33262 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TcRcI-0002Tx-09 for incoming@patchwork.ozlabs.org; Sat, 24 Nov 2012 21:06:42 -0500 Received: from eggs.gnu.org ([208.118.235.92]:59282) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TcRc8-0002Tr-Dd for qemu-devel@nongnu.org; Sat, 24 Nov 2012 21:06:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TcRc6-0004xI-CU for qemu-devel@nongnu.org; Sat, 24 Nov 2012 21:06:32 -0500 Received: from mail-pb0-f45.google.com ([209.85.160.45]:41078) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TcRc6-0004wb-31 for qemu-devel@nongnu.org; Sat, 24 Nov 2012 21:06:30 -0500 Received: by mail-pb0-f45.google.com with SMTP id mc8so6902572pbc.4 for ; Sat, 24 Nov 2012 18:06:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=COzsd5rPzaLzHOMEK04S7iyPIPDk6+oJpwn+Th9xaQc=; b=sp7uVMpWgFu0BNa7+E5Z8bjqTRIlq+SRofiCpVNaTUBV8dL/kW7oMDXxCLFeSZlb1y iH/WbMn7IwKJi7QA5twYE/TTa+ppNqA7cEd47lcHuBZJUtxlKA8Jb7aAG+gfeHG4qYvi vUeWp6AG4X4XEqwF0RltQZg1MTEDpuq4jhbcIr83oKJrdTr6W28/WKhWg6XDfceEeLnd PpPEcEz5AE1WXIHmEshYGaOdKvN2Mv1XLnQvU1wISCw+bIk2ZMJUMM5VNso//ysUQQLI 3brmco9YEn8FPg0GJ/sMTBtpVa7JqEJi+HB8jbck+hWVoT1FUNn+azRk5PgBLsEZcqV2 59og== Received: by 10.68.251.130 with SMTP id zk2mr26807895pbc.19.1353809189515; Sat, 24 Nov 2012 18:06:29 -0800 (PST) Received: from localhost ([222.128.159.174]) by mx.google.com with ESMTPS id oi3sm6290580pbb.1.2012.11.24.18.06.08 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 24 Nov 2012 18:06:28 -0800 (PST) From: Liu Ping Fan To: qemu-devel@nongnu.org Date: Sun, 25 Nov 2012 10:03:02 +0800 Message-Id: <1353808984-22368-6-git-send-email-qemulist@gmail.com> X-Mailer: git-send-email 1.7.4.4 In-Reply-To: <1353808984-22368-1-git-send-email-qemulist@gmail.com> References: <1353808984-22368-1-git-send-email-qemulist@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 209.85.160.45 Cc: Peter Maydell , gleb@redhat.com, Jan Kiszka , Marcelo Tosatti , Anthony Liguori , Stefan Hajnoczi , Paolo Bonzini Subject: [Qemu-devel] [PATCH v7 5/7] memory: make mmio dispatch able to be out of biglock 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 From: Liu Ping Fan Without biglock, we try to protect the mr by increase refcnt. If we cannot inc refcnt, go backward and resort to biglock. Another point is memory radix-tree can be flushed by another thread, so we should get the copy of terminal mr to survive from such issue. Signed-off-by: Liu Ping Fan --- docs/memory.txt | 4 ++ exec.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++----- memory-internal.h | 1 + memory.h | 2 + 4 files changed, 146 insertions(+), 15 deletions(-) diff --git a/docs/memory.txt b/docs/memory.txt index 5bbee8e..6b3d15a 100644 --- a/docs/memory.txt +++ b/docs/memory.txt @@ -170,3 +170,7 @@ various constraints can be supplied to control how these callbacks are called: - .old_portio and .old_mmio can be used to ease porting from code using cpu_register_io_memory() and register_ioport(). They should not be used in new code. + +MMIO regions are provided with ->ref() and ->unref() callbacks; This pair callbacks +are optional. When ref() return non-zero, Both MemoryRegion and its opaque are +safe to use. diff --git a/exec.c b/exec.c index 750008c..fa34ef9 100644 --- a/exec.c +++ b/exec.c @@ -2280,7 +2280,7 @@ static void register_multipage(AddressSpaceDispatch *d, MemoryRegionSection *sec section_index); } -static void mem_add(MemoryListener *listener, MemoryRegionSection *section) +static void mem_nop(MemoryListener *listener, MemoryRegionSection *section) { AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); MemoryRegionSection now = *section, remain = *section; @@ -2314,6 +2314,26 @@ static void mem_add(MemoryListener *listener, MemoryRegionSection *section) } } +static void mem_add(MemoryListener *listener, MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + + if (mr->ops && mr->ops->ref) { + mr->ops->ref(mr); + } + mem_nop(listener, section); +} + +static void mem_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + MemoryRegion *mr = section->mr; + + if (mr->ops && mr->ops->unref) { + mr->ops->unref(mr); + } +} + void qemu_flush_coalesced_mmio_buffer(void) { if (kvm_enabled()) @@ -3165,11 +3185,23 @@ static void io_mem_init(void) static void mem_begin(MemoryListener *listener) { AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); + AddressSpace *as = d->as; + /* protect the updating process of mrs in memory core agaist readers */ + qemu_mutex_lock(&as->lock); destroy_all_mappings(d); d->phys_map.ptr = PHYS_MAP_NODE_NIL; } +static void mem_commit(MemoryListener *listener) +{ + AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, + listener); + AddressSpace *as = d->as; + + qemu_mutex_unlock(&as->lock); +} + static void core_begin(MemoryListener *listener) { phys_sections_clear(); @@ -3243,11 +3275,14 @@ void address_space_init_dispatch(AddressSpace *as) d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 }; d->listener = (MemoryListener) { .begin = mem_begin, + .commit = mem_commit, .region_add = mem_add, - .region_nop = mem_add, + .region_del = mem_del, + .region_nop = mem_nop, .priority = 0, }; as->dispatch = d; + as->dispatch->as = as; memory_listener_register(&d->listener, as); } @@ -3345,6 +3380,68 @@ static void invalidate_and_set_dirty(target_phys_addr_t addr, xen_modified_memory(addr, length); } +static MemoryRegionSection *subpage_get_terminal(subpage_t *mmio, + target_phys_addr_t addr) +{ + MemoryRegionSection *section; + unsigned int idx = SUBPAGE_IDX(addr); + + section = &phys_sections[mmio->sub_section[idx]]; + return section; +} + +static bool memory_region_section_ref(MemoryRegionSection *mrs) +{ + MemoryRegion *mr; + bool ret = false; + + mr = mrs->mr; + if (mr->ops && mr->ops->ref) { + mr->ops->ref(mr); + ret = true; + } + return ret; +} + +static void memory_region_section_unref(MemoryRegionSection *mrs) +{ + MemoryRegion *mr; + + mr = mrs->mr; + if (mr->ops && mr->ops->unref) { + mr->ops->unref(mr); + } +} + +static bool memory_region_section_lookup_ref(AddressSpaceDispatch *d, + target_phys_addr_t addr, MemoryRegionSection *mrs) +{ + MemoryRegionSection *section; + bool ret; + + section = phys_page_find(d, addr >> TARGET_PAGE_BITS); + if (section->mr->subpage) { + section = subpage_get_terminal(section->mr->opaque, addr); + } + *mrs = *section; + ret = memory_region_section_ref(mrs); + + return ret; +} + +static bool address_space_section_lookup_ref(AddressSpace *as, + target_phys_addr_t page, MemoryRegionSection *mrs) +{ + bool safe_ref; + AddressSpaceDispatch *d = as->dispatch; + + qemu_mutex_lock(&as->lock); + safe_ref = memory_region_section_lookup_ref(d, page, mrs); + qemu_mutex_unlock(&as->lock); + + return safe_ref; +} + void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, int len, bool is_write) { @@ -3353,14 +3450,29 @@ void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, uint8_t *ptr; uint32_t val; target_phys_addr_t page; - MemoryRegionSection *section; + bool safe_ref; + MemoryRegionSection *section, obj_mrs; while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + + qemu_mutex_lock(&as->lock); + safe_ref = memory_region_section_lookup_ref(d, page, &obj_mrs); + qemu_mutex_unlock(&as->lock); + if (!safe_ref) { + qemu_mutex_lock_iothread(); + qemu_mutex_lock(&as->lock); + /* when 2nd try, mem map can change, need to judge it again */ + safe_ref = memory_region_section_lookup_ref(d, page, &obj_mrs); + qemu_mutex_unlock(&as->lock); + if (safe_ref) { + qemu_mutex_unlock_iothread(); + } + } + section = &obj_mrs; if (is_write) { if (!memory_region_is_ram(section->mr)) { @@ -3425,9 +3537,13 @@ void address_space_rw(AddressSpace *as, target_phys_addr_t addr, uint8_t *buf, qemu_put_ram_ptr(ptr); } } + memory_region_section_unref(&obj_mrs); len -= l; buf += l; addr += l; + if (!safe_ref) { + qemu_mutex_unlock_iothread(); + } } } @@ -3460,18 +3576,19 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, void cpu_physical_memory_write_rom(target_phys_addr_t addr, const uint8_t *buf, int len) { - AddressSpaceDispatch *d = address_space_memory.dispatch; int l; uint8_t *ptr; target_phys_addr_t page; - MemoryRegionSection *section; + MemoryRegionSection *section, mr_obj; while (len > 0) { page = addr & TARGET_PAGE_MASK; l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + address_space_section_lookup_ref(&address_space_memory, + page >> TARGET_PAGE_BITS, &mr_obj); + section = &mr_obj; if (!(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr))) { @@ -3489,6 +3606,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, len -= l; buf += l; addr += l; + memory_region_section_unref(&mr_obj); } } @@ -3550,12 +3668,11 @@ void *address_space_map(AddressSpace *as, target_phys_addr_t *plen, bool is_write) { - AddressSpaceDispatch *d = as->dispatch; target_phys_addr_t len = *plen; target_phys_addr_t todo = 0; int l; target_phys_addr_t page; - MemoryRegionSection *section; + MemoryRegionSection *section, mr_obj; ram_addr_t raddr = RAM_ADDR_MAX; ram_addr_t rlen; void *ret; @@ -3565,7 +3682,8 @@ void *address_space_map(AddressSpace *as, l = (page + TARGET_PAGE_SIZE) - addr; if (l > len) l = len; - section = phys_page_find(d, page >> TARGET_PAGE_BITS); + address_space_section_lookup_ref(as, page >> TARGET_PAGE_BITS, &mr_obj); + section = &mr_obj; if (!(memory_region_is_ram(section->mr) && !section->readonly)) { if (todo || bounce.buffer) { @@ -3579,6 +3697,7 @@ void *address_space_map(AddressSpace *as, } *plen = l; + memory_region_section_unref(&mr_obj); return bounce.buffer; } if (!todo) { @@ -3589,6 +3708,7 @@ void *address_space_map(AddressSpace *as, len -= l; addr += l; todo += l; + memory_region_section_unref(&mr_obj); } rlen = todo; ret = qemu_ram_ptr_length(raddr, &rlen); @@ -4197,12 +4317,16 @@ bool virtio_is_big_endian(void) #ifndef CONFIG_USER_ONLY bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr) { - MemoryRegionSection *section; + MemoryRegionSection *section, mr_obj; + bool ret; - section = phys_page_find(address_space_memory.dispatch, - phys_addr >> TARGET_PAGE_BITS); - - return !(memory_region_is_ram(section->mr) || + address_space_section_lookup_ref(&address_space_memory, + phys_addr >> TARGET_PAGE_BITS, &mr_obj); + section = &mr_obj; + ret = !(memory_region_is_ram(section->mr) || memory_region_is_romd(section->mr)); + memory_region_section_unref(&mr_obj); + + return ret; } #endif diff --git a/memory-internal.h b/memory-internal.h index b33a99d..ea06bfb 100644 --- a/memory-internal.h +++ b/memory-internal.h @@ -38,6 +38,7 @@ struct AddressSpaceDispatch { */ PhysPageEntry phys_map; MemoryListener listener; + AddressSpace *as; }; void address_space_init_dispatch(AddressSpace *as); diff --git a/memory.h b/memory.h index 13a9e3e..704d014 100644 --- a/memory.h +++ b/memory.h @@ -67,6 +67,8 @@ struct MemoryRegionOps { target_phys_addr_t addr, uint64_t data, unsigned size); + void (*ref)(MemoryRegion *mr); + void (*unref)(MemoryRegion *mr); enum device_endian endianness; /* Guest-visible constraints: */