[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v1 2/6] mem: make global dispatch table ready fo
From: |
Paolo Bonzini |
Subject: |
Re: [Qemu-devel] [PATCH v1 2/6] mem: make global dispatch table ready for rcu |
Date: |
Wed, 29 May 2013 09:07:51 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130514 Thunderbird/17.0.6 |
Il 29/05/2013 04:11, Liu Ping Fan ha scritto:
> From: Liu Ping Fan <address@hidden>
>
> Currently, phys_node_map and phys_sections are shared by all
> of the AddressSpaceDispatch. When updating mem topology, all
> AddressSpaceDispatch will rebuild dispatch tables sequentially
> on them. In order to use rcu-style, introducing next_node_map
> and next_phys_sections, so that when rebuilding, the new dispatch
> tables will locate on next_*. After all AddressSpaceDispatch
> finished, we can switch to next_* and drop the previous stuff.
>
> This patch still work in the scenario that readers and writer
> can not run in parellel (ie, protected by biglock), so no extra
> lock method needed till now, and the rcu style consistent issue
> will be left to the following patches.
>
> Signed-off-by: Liu Ping Fan <address@hidden>
> ---
> exec.c | 202 ++++++++++++++++++++++++++++++++++-----------------------------
> 1 files changed, 109 insertions(+), 93 deletions(-)
>
> diff --git a/exec.c b/exec.c
> index 6934c2d..e5335f5 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -80,16 +80,33 @@ int use_icount;
>
> #if !defined(CONFIG_USER_ONLY)
>
> -static MemoryRegionSection *phys_sections;
> -static unsigned phys_sections_nb, phys_sections_nb_alloc;
> #define phys_section_unassigned 0
> #define phys_section_notdirty 1
> #define phys_section_rom 2
> #define phys_section_watch 3
>
> -/* Simple allocator for PhysPageEntry nodes */
> -static PhysPageEntry (*phys_map_nodes)[L2_SIZE];
> -static unsigned phys_map_nodes_nb, phys_map_nodes_nb_alloc;
> +typedef PhysPageEntry Node[L2_SIZE];
> +
> +typedef struct AllocInfo {
> + unsigned phys_sections_nb;
> + unsigned phys_sections_nb_alloc;
> + unsigned phys_map_nodes_nb;
> + unsigned phys_map_nodes_nb_alloc;
> + /* Only used for release purpose */
> + Node *map;
Node *nodes;
> + MemoryRegionSection *sections;
> +} AllocInfo;
> +
> +/* For performance, fetch page map related pointers directly, other than
> + * hiding them inside AllocInfo
> + */
> +static MemoryRegionSection *cur_phys_sections;
> +static Node *cur_map_nodes;
> +static AllocInfo *cur_alloc_info;
> +
> +static MemoryRegionSection *next_phys_sections;
> +static Node *next_map_nodes;
> +static AllocInfo *next_alloc_info;
No need for the "next" variables, just make it "static AllocInfo *next_map".
>
> #define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1)
>
> @@ -104,13 +121,15 @@ static MemoryRegion io_mem_watch;
>
> static void phys_map_node_reserve(unsigned nodes)
> {
> - if (phys_map_nodes_nb + nodes > phys_map_nodes_nb_alloc) {
> - typedef PhysPageEntry Node[L2_SIZE];
> - phys_map_nodes_nb_alloc = MAX(phys_map_nodes_nb_alloc * 2, 16);
> - phys_map_nodes_nb_alloc = MAX(phys_map_nodes_nb_alloc,
> - phys_map_nodes_nb + nodes);
> - phys_map_nodes = g_renew(Node, phys_map_nodes,
> - phys_map_nodes_nb_alloc);
> + AllocInfo *info = next_alloc_info;
> +
> + if (info->phys_map_nodes_nb + nodes > info->phys_map_nodes_nb_alloc) {
> + info->phys_map_nodes_nb_alloc = MAX(info->phys_map_nodes_nb_alloc *
> 2,
> + 16);
> + info->phys_map_nodes_nb_alloc = MAX(info->phys_map_nodes_nb_alloc,
> + info->phys_map_nodes_nb + nodes);
> + next_map_nodes = g_renew(Node, next_map_nodes,
> + info->phys_map_nodes_nb_alloc);
> }
> }
>
> @@ -118,23 +137,18 @@ static uint16_t phys_map_node_alloc(void)
> {
> unsigned i;
> uint16_t ret;
> + AllocInfo *info = next_alloc_info;
>
> - ret = phys_map_nodes_nb++;
> + ret = info->phys_map_nodes_nb++;
> assert(ret != PHYS_MAP_NODE_NIL);
> - assert(ret != phys_map_nodes_nb_alloc);
> + assert(ret != info->phys_map_nodes_nb_alloc);
> for (i = 0; i < L2_SIZE; ++i) {
> - phys_map_nodes[ret][i].is_leaf = 0;
> - phys_map_nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
> + next_map_nodes[ret][i].is_leaf = 0;
> + next_map_nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
> }
> return ret;
> }
>
> -static void phys_map_nodes_reset(void)
> -{
> - phys_map_nodes_nb = 0;
> -}
> -
> -
> static void phys_page_set_level(PhysPageEntry *lp, hwaddr *index,
> hwaddr *nb, uint16_t leaf,
> int level)
> @@ -145,7 +159,7 @@ static void phys_page_set_level(PhysPageEntry *lp, hwaddr
> *index,
>
> if (!lp->is_leaf && lp->ptr == PHYS_MAP_NODE_NIL) {
> lp->ptr = phys_map_node_alloc();
> - p = phys_map_nodes[lp->ptr];
> + p = next_map_nodes[lp->ptr];
> if (level == 0) {
> for (i = 0; i < L2_SIZE; i++) {
> p[i].is_leaf = 1;
> @@ -153,7 +167,7 @@ static void phys_page_set_level(PhysPageEntry *lp, hwaddr
> *index,
> }
> }
> } else {
> - p = phys_map_nodes[lp->ptr];
> + p = next_map_nodes[lp->ptr];
> }
> lp = &p[(*index >> (level * L2_BITS)) & (L2_SIZE - 1)];
>
> @@ -180,20 +194,29 @@ static void phys_page_set(AddressSpaceDispatch *d,
> phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
> }
>
> -static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr
> index)
> +static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr
> index, bool cur)
> {
> PhysPageEntry lp = d->phys_map;
> PhysPageEntry *p;
> int i;
> + Node *map_nodes;
> + MemoryRegionSection *sections;
>
> + if (likely(cur)) {
> + map_nodes = cur_map_nodes;
> + sections = cur_phys_sections;
> + } else {
> + map_nodes = next_map_nodes;
> + sections = next_phys_sections;
> + }
Just pass the AllocInfo here.
> for (i = P_L2_LEVELS - 1; i >= 0 && !lp.is_leaf; i--) {
> if (lp.ptr == PHYS_MAP_NODE_NIL) {
> - return &phys_sections[phys_section_unassigned];
> + return §ions[phys_section_unassigned];
> }
> - p = phys_map_nodes[lp.ptr];
> + p = map_nodes[lp.ptr];
> lp = p[(index >> (i * L2_BITS)) & (L2_SIZE - 1)];
> }
> - return &phys_sections[lp.ptr];
> + return §ions[lp.ptr];
> }
>
> bool memory_region_is_unassigned(MemoryRegion *mr)
> @@ -205,7 +228,7 @@ bool memory_region_is_unassigned(MemoryRegion *mr)
> static MemoryRegionSection *address_space_lookup_region(AddressSpace *as,
> hwaddr addr)
> {
> - return phys_page_find(as->dispatch, addr >> TARGET_PAGE_BITS);
> + return phys_page_find(as->dispatch, addr >> TARGET_PAGE_BITS, true);
> }
>
> MemoryRegionSection *address_space_translate(AddressSpace *as, hwaddr addr,
> @@ -213,7 +236,7 @@ MemoryRegionSection *address_space_translate(AddressSpace
> *as, hwaddr addr,
> bool is_write)
> {
> IOMMUTLBEntry iotlb;
> - MemoryRegionSection *section;
> + MemoryRegionSection *section, *base = cur_phys_sections;
> hwaddr len = *plen;
>
> for (;;) {
> @@ -235,7 +258,7 @@ MemoryRegionSection *address_space_translate(AddressSpace
> *as, hwaddr addr,
> | (addr & iotlb.addr_mask));
> len = MIN(len, (addr | iotlb.addr_mask) - addr + 1);
> if (!(iotlb.perm & (1 << is_write))) {
> - section = &phys_sections[phys_section_unassigned];
> + section = &base[phys_section_unassigned];
> break;
> }
>
> @@ -677,7 +700,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env,
> iotlb |= phys_section_rom;
> }
> } else {
> - iotlb = section - phys_sections;
> + iotlb = section - cur_phys_sections;
> iotlb += xlat;
> }
>
> @@ -710,67 +733,31 @@ typedef struct subpage_t {
> static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
> uint16_t section);
> static subpage_t *subpage_init(hwaddr base);
> -static void destroy_page_desc(uint16_t section_index)
> -{
> - MemoryRegionSection *section = &phys_sections[section_index];
> - MemoryRegion *mr = section->mr;
> -
> - if (mr->subpage) {
> - subpage_t *subpage = container_of(mr, subpage_t, iomem);
> - memory_region_destroy(&subpage->iomem);
> - g_free(subpage);
> - }
> -}
> -
> -static void destroy_l2_mapping(PhysPageEntry *lp, unsigned level)
> -{
> - unsigned i;
> - PhysPageEntry *p;
> -
> - if (lp->ptr == PHYS_MAP_NODE_NIL) {
> - return;
> - }
> -
> - p = phys_map_nodes[lp->ptr];
> - for (i = 0; i < L2_SIZE; ++i) {
> - if (!p[i].is_leaf) {
> - destroy_l2_mapping(&p[i], level - 1);
> - } else {
> - destroy_page_desc(p[i].ptr);
> - }
> - }
> - lp->is_leaf = 0;
> - lp->ptr = PHYS_MAP_NODE_NIL;
> -}
> -
> -static void destroy_all_mappings(AddressSpaceDispatch *d)
> -{
> - destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1);
> - phys_map_nodes_reset();
> -}
>
> static uint16_t phys_section_add(MemoryRegionSection *section)
> {
> + AllocInfo *info = next_alloc_info;
> /* The physical section number is ORed with a page-aligned
> * pointer to produce the iotlb entries. Thus it should
> * never overflow into the page-aligned value.
> */
> - assert(phys_sections_nb < TARGET_PAGE_SIZE);
> + assert(info->phys_sections_nb < TARGET_PAGE_SIZE);
>
> - if (phys_sections_nb == phys_sections_nb_alloc) {
> - phys_sections_nb_alloc = MAX(phys_sections_nb_alloc * 2, 16);
> - phys_sections = g_renew(MemoryRegionSection, phys_sections,
> - phys_sections_nb_alloc);
> + if (info->phys_sections_nb == info->phys_sections_nb_alloc) {
> + info->phys_sections_nb_alloc = MAX(info->phys_sections_nb_alloc * 2,
> + 16);
> + next_phys_sections = g_renew(MemoryRegionSection, next_phys_sections,
> + info->phys_sections_nb_alloc);
> }
> - phys_sections[phys_sections_nb] = *section;
> + next_phys_sections[info->phys_sections_nb] = *section;
> memory_region_ref(section->mr);
> - return phys_sections_nb++;
> + return info->phys_sections_nb++;
> }
>
> -static void phys_sections_clear(void)
> +static void phys_sections_clear(unsigned cnt, MemoryRegionSection *mrs)
> {
> - while (phys_sections_nb > 0) {
> - MemoryRegionSection *section = &phys_sections[--phys_sections_nb];
> + while (cnt > 0) {
> + MemoryRegionSection *section = &mrs[--cnt];
> memory_region_unref(section->mr);
> }
> }
> @@ -780,7 +767,8 @@ static void register_subpage(AddressSpaceDispatch *d,
> MemoryRegionSection *secti
> subpage_t *subpage;
> hwaddr base = section->offset_within_address_space
> & TARGET_PAGE_MASK;
> - MemoryRegionSection *existing = phys_page_find(d, base >>
> TARGET_PAGE_BITS);
> + MemoryRegionSection *existing = phys_page_find(d,
> + base >> TARGET_PAGE_BITS, false);
> MemoryRegionSection subsection = {
> .offset_within_address_space = base,
> .size = TARGET_PAGE_SIZE,
> @@ -1572,13 +1560,13 @@ static uint64_t subpage_read(void *opaque, hwaddr
> addr,
> unsigned int idx = SUBPAGE_IDX(addr);
> uint64_t val;
>
> - MemoryRegionSection *section;
> + MemoryRegionSection *section, *base = cur_phys_sections;
> #if defined(DEBUG_SUBPAGE)
> printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n",
> __func__,
> mmio, len, addr, idx);
> #endif
>
> - section = &phys_sections[mmio->sub_section[idx]];
> + section = &base[mmio->sub_section[idx]];
> addr += mmio->base;
> addr -= section->offset_within_address_space;
> addr += section->offset_within_region;
> @@ -1591,14 +1579,14 @@ static void subpage_write(void *opaque, hwaddr addr,
> {
> subpage_t *mmio = opaque;
> unsigned int idx = SUBPAGE_IDX(addr);
> - MemoryRegionSection *section;
> + MemoryRegionSection *section, *base = cur_phys_sections;
> #if defined(DEBUG_SUBPAGE)
> printf("%s: subpage %p len %d addr " TARGET_FMT_plx
> " idx %d value %"PRIx64"\n",
> __func__, mmio, len, addr, idx, value);
> #endif
>
> - section = &phys_sections[mmio->sub_section[idx]];
> + section = &base[mmio->sub_section[idx]];
> addr += mmio->base;
> addr -= section->offset_within_address_space;
> addr += section->offset_within_region;
> @@ -1610,14 +1598,14 @@ static bool subpage_accepts(void *opaque, hwaddr addr,
> {
> subpage_t *mmio = opaque;
> unsigned int idx = SUBPAGE_IDX(addr);
> - MemoryRegionSection *section;
> + MemoryRegionSection *section, *base = cur_phys_sections;;
> #if defined(DEBUG_SUBPAGE)
> printf("%s: subpage %p %c len %d addr " TARGET_FMT_plx
> " idx %d\n", __func__, mmio,
> is_write ? 'w' : 'r', len, addr, idx);
> #endif
>
> - section = &phys_sections[mmio->sub_section[idx]];
> + section = &base[mmio->sub_section[idx]];
> addr += mmio->base;
> addr -= section->offset_within_address_space;
> addr += section->offset_within_region;
> @@ -1676,8 +1664,8 @@ static int subpage_register (subpage_t *mmio, uint32_t
> start, uint32_t end,
> printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n",
> __func__,
> mmio, start, end, idx, eidx, memory);
> #endif
> - if (memory_region_is_ram(phys_sections[section].mr)) {
> - MemoryRegionSection new_section = phys_sections[section];
> + if (memory_region_is_ram(next_phys_sections[section].mr)) {
> + MemoryRegionSection new_section = next_phys_sections[section];
> new_section.mr = &io_mem_subpage_ram;
> section = phys_section_add(&new_section);
> }
> @@ -1721,7 +1709,7 @@ static uint16_t dummy_section(MemoryRegion *mr)
>
> MemoryRegion *iotlb_to_region(hwaddr index)
> {
> - return phys_sections[index & ~TARGET_PAGE_MASK].mr;
> + return cur_phys_sections[index & ~TARGET_PAGE_MASK].mr;
> }
>
> static void io_mem_init(void)
> @@ -1741,7 +1729,6 @@ static void mem_begin(MemoryListener *listener)
> {
> AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch,
> listener);
>
> - destroy_all_mappings(d);
> d->phys_map.ptr = PHYS_MAP_NODE_NIL;
> }
>
> @@ -1749,7 +1736,7 @@ static void core_begin(MemoryListener *listener)
> {
> uint16_t n;
>
> - phys_sections_clear();
> + next_alloc_info = g_malloc0(sizeof(AllocInfo));
> n = dummy_section(&io_mem_unassigned);
> assert(phys_section_unassigned == n);
> n = dummy_section(&io_mem_notdirty);
> @@ -1760,6 +1747,35 @@ static void core_begin(MemoryListener *listener)
> assert(phys_section_watch == n);
> }
>
> +static void release_dispatch_map(AllocInfo *info)
> +{
> + phys_sections_clear(info->phys_sections_nb, info->sections);
> + g_free(info->map);
> + g_free(info->sections);
> + g_free(info);
> +}
> +
> +/* This listener's commit run after the other AddressSpaceDispatch
> listeners'.
> + * It means that AddressSpaceDispatch's deleter has finished, so it can be
> + * the place for call_rcu()
> + */
> +static void core_commit(MemoryListener *listener)
> +{
> + AllocInfo *info = cur_alloc_info;
> + info->map = cur_map_nodes;
> + info->sections = cur_phys_sections;
> +
> + /* Fix me, in future, will be protected by wr seqlock when in parellel
> + * with reader
> + */
> + cur_map_nodes = next_map_nodes;
> + cur_phys_sections = next_phys_sections;
> + cur_alloc_info = next_alloc_info;
> +
> + /* Fix me, will changed to call_rcu */
> + release_dispatch_map(info);
> +}
> +
> static void tcg_commit(MemoryListener *listener)
> {
> CPUArchState *env;
> @@ -1802,6 +1818,7 @@ static void io_region_del(MemoryListener *listener,
>
> static MemoryListener core_memory_listener = {
> .begin = core_begin,
> + .commit = core_commit,
> .log_global_start = core_log_global_start,
> .log_global_stop = core_log_global_stop,
> .priority = 1,
> @@ -1837,7 +1854,6 @@ void address_space_destroy_dispatch(AddressSpace *as)
> AddressSpaceDispatch *d = as->dispatch;
>
> memory_listener_unregister(&d->listener);
> - destroy_l2_mapping(&d->phys_map, P_L2_LEVELS - 1);
> g_free(d);
> as->dispatch = NULL;
> }
>
[Qemu-devel] [PATCH v1 5/6] mem: make dispatch path satify rcu style, Liu Ping Fan, 2013/05/28