From patchwork Thu Jan 22 14:47:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 431844 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F33FB14012E for ; Fri, 23 Jan 2015 01:55:32 +1100 (AEDT) Received: from localhost ([::1]:53767 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YEJAR-0001rn-7e for incoming@patchwork.ozlabs.org; Thu, 22 Jan 2015 09:55:31 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46953) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YEJ3N-00069w-3s for qemu-devel@nongnu.org; Thu, 22 Jan 2015 09:48:16 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YEJ3M-0002CM-0d for qemu-devel@nongnu.org; Thu, 22 Jan 2015 09:48:13 -0500 Received: from mail-wi0-x22e.google.com ([2a00:1450:400c:c05::22e]:54560) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YEJ3L-0002C5-LD for qemu-devel@nongnu.org; Thu, 22 Jan 2015 09:48:11 -0500 Received: by mail-wi0-f174.google.com with SMTP id n3so22042383wiv.1 for ; Thu, 22 Jan 2015 06:48:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=JNfZBE0Fcr8xdyhmYB5anIek3e5rvVaiobRXtso2I4g=; b=uCO8xZE2DPD7GIMOaNWkFTV4xVtPE+aF2W8NEztsqVLy+pH5i9vLqtSmx5F0Gr/9N+ D9lvAvTrIAYyIbehVUbOD8BXxzTfL8vphoMCwUSJHaaGEXizt60DJyIVDK+RNqm6sQOt 6U+a8yli/xfmk51GsVCywq/Oi0bTbpuMciXcx15NepttnQ88WGBQiyFKEQ/m+2BanV1C Otat0b5mGtmIaKTfi022xGp60EgCs1Ic12nFvwRmWFxiTk4FwB/M8RXkiIE3IOGKl5R/ Jx1wh9TWyndo8dcG+MbdZH3dJu6oWPSUoC37pzoQMcxWhL1ryBIsIW9Lnkzz+U5rqBPv 7rxQ== X-Received: by 10.181.13.42 with SMTP id ev10mr5820226wid.78.1421938091043; Thu, 22 Jan 2015 06:48:11 -0800 (PST) Received: from playground.station (net-2-35-193-154.cust.vodafonedsl.it. [2.35.193.154]) by mx.google.com with ESMTPSA id gm10sm3283287wib.19.2015.01.22.06.48.09 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Jan 2015 06:48:10 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Thu, 22 Jan 2015 15:47:30 +0100 Message-Id: <1421938053-10318-13-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1421938053-10318-1-git-send-email-pbonzini@redhat.com> References: <1421938053-10318-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::22e Cc: borntraeger@de.ibm.com, famz@redhat.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH 12/15] exec: protect mru_block with RCU 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 Hence, freeing a RAMBlock has to be switched to call_rcu. Signed-off-by: Paolo Bonzini --- exec.c | 61 ++++++++++++++++++++++++++++++++++---------------- include/exec/cpu-all.h | 2 ++ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/exec.c b/exec.c index 262e8bc..2a142fe 100644 --- a/exec.c +++ b/exec.c @@ -811,7 +811,7 @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr) RAMBlock *block; /* The list is protected by the iothread lock here. */ - block = ram_list.mru_block; + block = atomic_rcu_read(&ram_list.mru_block); if (block && addr - block->offset < block->max_length) { goto found; } @@ -825,6 +825,22 @@ static RAMBlock *qemu_get_ram_block(ram_addr_t addr) abort(); found: + /* It is safe to write mru_block outside the iothread lock. This + * is what happens: + * + * mru_block = xxx + * rcu_read_unlock() + * xxx removed from list + * rcu_read_lock() + * read mru_block + * mru_block = NULL; + * call_rcu(reclaim_ramblock, xxx); + * rcu_read_unlock() + * + * atomic_rcu_set is not needed here. The block was already published + * when it was placed into the list. Here we're just making an extra + * copy of the pointer. + */ ram_list.mru_block = block; return block; } @@ -1381,14 +1397,16 @@ static ram_addr_t ram_block_add(RAMBlock *new_block, Error **errp) QTAILQ_INSERT_TAIL(&ram_list.blocks, new_block, next); } ram_list.mru_block = NULL; + atomic_rcu_set(&ram_list.version, ram_list.version + 1); - ram_list.version++; qemu_mutex_unlock_ramlist(); new_ram_size = last_ram_offset() >> TARGET_PAGE_BITS; if (new_ram_size > old_ram_size) { int i; + + /* ram_list.dirty_memory[] is protected by the iothread lock. */ for (i = 0; i < DIRTY_MEMORY_NUM; i++) { ram_list.dirty_memory[i] = bitmap_zero_extend(ram_list.dirty_memory[i], @@ -1524,14 +1542,31 @@ void qemu_ram_free_from_ptr(ram_addr_t addr) if (addr == block->offset) { QTAILQ_REMOVE(&ram_list.blocks, block, next); ram_list.mru_block = NULL; - ram_list.version++; - g_free(block); + atomic_rcu_set(&ram_list.version, ram_list.version + 1); + call_rcu(block, (void (*)(struct RAMBlock *))g_free, rcu); break; } } - qemu_mutex_unlock_ramlist(); } +static void reclaim_ramblock(RAMBlock *block) +{ + if (block->flags & RAM_PREALLOC) { + ; + } else if (xen_enabled()) { + xen_invalidate_map_cache_entry(block->host); +#ifndef _WIN32 + } else if (block->fd >= 0) { + munmap(block->host, block->max_length); + close(block->fd); +#endif + } else { + qemu_anon_ram_free(block->host, block->max_length); + } + g_free(block); +} + +/* Called with the iothread lock held */ void qemu_ram_free(ram_addr_t addr) { RAMBlock *block; @@ -1542,20 +1577,8 @@ void qemu_ram_free(ram_addr_t addr) if (addr == block->offset) { QTAILQ_REMOVE(&ram_list.blocks, block, next); ram_list.mru_block = NULL; - ram_list.version++; - if (block->flags & RAM_PREALLOC) { - ; - } else if (xen_enabled()) { - xen_invalidate_map_cache_entry(block->host); -#ifndef _WIN32 - } else if (block->fd >= 0) { - munmap(block->host, block->max_length); - close(block->fd); -#endif - } else { - qemu_anon_ram_free(block->host, block->max_length); - } - g_free(block); + atomic_rcu_set(&ram_list.version, ram_list.version + 1); + call_rcu(block, reclaim_ramblock, rcu); break; } } diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 2c48286..b8781d1 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -24,6 +24,7 @@ #include "exec/memory.h" #include "qemu/thread.h" #include "qom/cpu.h" +#include "qemu/rcu.h" /* some important defines: * @@ -268,6 +269,7 @@ CPUArchState *cpu_copy(CPUArchState *env); typedef struct RAMBlock RAMBlock; struct RAMBlock { + struct rcu_head rcu; struct MemoryRegion *mr; uint8_t *host; ram_addr_t offset;