Re: [Qemu-devel] [PATCH v3 15/15] translate-all: mark updates to PageDesc as atomic

2016-10-03 Thread Paolo Bonzini


On 30/09/2016 23:31, Alex Bennée wrote:
> Updates to the internal page table are protected by the mmap_lock.
> However for defined C11 semantics things that are access across threads
> need to accessed using at least relaxed atomics.

Again, this is only necessary for the initial load-acquire operation.
Everything else synchronizes indirectly, so:

> +PageDesc *pd = atomic_rcu_read(lp);

Using atomics here is correct, but I'd write:

void *p = atomic_rcu_read(lp);

and then assign from p into either "p" or "pp".

>  
> -if (*lp == NULL) {
> -return;

Unnecessary and causes indentation changes elsewhere.  Just use "if (p
== NULL) return;".

> -}
> -if (level == 0) {
> -PageDesc *pd = *lp;
> +if (pd) {
> +if (level == 0) {
>  
> -for (i = 0; i < V_L2_SIZE; ++i) {
> -pd[i].first_tb = NULL;
> -invalidate_page_bitmap(pd + i);
> -}
> -} else {
> -void **pp = *lp;
> +for (i = 0; i < V_L2_SIZE; ++i) {
> +atomic_set(&pd[i].first_tb, NULL);

Right.

> +invalidate_page_bitmap(pd + i);
> +}
> +} else {
> +void **pp = (void **) pd;
>  
> -for (i = 0; i < V_L2_SIZE; ++i) {
> -page_flush_tb_1(level - 1, pp + i);
> +for (i = 0; i < V_L2_SIZE; ++i) {
> +page_flush_tb_1(level - 1, pp + i);
> +}
>  }
>  }
>  }
> @@ -1360,7 +1359,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t 
> start, tb_page_addr_t end,
>  /* we remove all the TBs in the range [start, end[ */
>  /* XXX: see if in some cases it could be faster to invalidate all
> the code */
> -tb = p->first_tb;
> +tb = atomic_read(&p->first_tb);
>  while (tb != NULL) {
>  n = (uintptr_t)tb & 3;
>  tb = (TranslationBlock *)((uintptr_t)tb & ~3);
> @@ -1968,16 +1967,15 @@ void page_set_flags(target_ulong start, target_ulong 
> end, int flags)
> the code inside.  */
>  if (!(p->flags & PAGE_WRITE) &&
>  (flags & PAGE_WRITE) &&
> -p->first_tb) {
> +atomic_read(&p->first_tb)) {
>  tb_invalidate_phys_page(addr, 0);
>  }
> -p->flags = flags;
> +atomic_set(&p->flags, flags);

Should not be necessary, p->flags is only accessed under mmap_lock (or
is it)?

Paolo

>  }
>  }
>  
>  int page_check_range(target_ulong start, target_ulong len, int flags)
>  {
> -PageDesc *p;
>  target_ulong end;
>  target_ulong addr;
>  
> @@ -2003,28 +2001,31 @@ int page_check_range(target_ulong start, target_ulong 
> len, int flags)
>  for (addr = start, len = end - start;
>   len != 0;
>   len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
> -p = page_find(addr >> TARGET_PAGE_BITS);
> -if (!p) {
> -return -1;
> -}
> -if (!(p->flags & PAGE_VALID)) {
> -return -1;
> -}
> +PageDesc *p = page_find(addr >> TARGET_PAGE_BITS);
> +if (p) {
> +int cur_flags = atomic_read(&p->flags);
>  
> -if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) {
> -return -1;
> -}
> -if (flags & PAGE_WRITE) {
> -if (!(p->flags & PAGE_WRITE_ORG)) {
> +if (!(cur_flags & PAGE_VALID)) {
>  return -1;
>  }
> -/* unprotect the page if it was put read-only because it
> -   contains translated code */
> -if (!(p->flags & PAGE_WRITE)) {
> -if (!page_unprotect(addr, 0)) {
> +
> +if ((flags & PAGE_READ) && !(cur_flags & PAGE_READ)) {
> +return -1;
> +}
> +if (flags & PAGE_WRITE) {
> +if (!(cur_flags & PAGE_WRITE_ORG)) {
>  return -1;
>  }
> +/* unprotect the page if it was put read-only because it
> +   contains translated code */
> +if (!(cur_flags & PAGE_WRITE)) {
> +if (!page_unprotect(addr, 0)) {
> +return -1;
> +}
> +}
>  }
> +} else {
> +return -1;
>  }
>  }
>  return 0;
> 



[Qemu-devel] [PATCH v3 15/15] translate-all: mark updates to PageDesc as atomic

2016-09-30 Thread Alex Bennée
Updates to the internal page table are protected by the mmap_lock.
However for defined C11 semantics things that are access across threads
need to accessed using at least relaxed atomics.

Signed-off-by: Alex Bennée 
---
 translate-all.c | 67 +
 1 file changed, 34 insertions(+), 33 deletions(-)

diff --git a/translate-all.c b/translate-all.c
index a6262ae..2d6c0e8 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -805,22 +805,21 @@ static inline void invalidate_page_bitmap(PageDesc *p)
 static void page_flush_tb_1(int level, void **lp)
 {
 int i;
+PageDesc *pd = atomic_rcu_read(lp);
 
-if (*lp == NULL) {
-return;
-}
-if (level == 0) {
-PageDesc *pd = *lp;
+if (pd) {
+if (level == 0) {
 
-for (i = 0; i < V_L2_SIZE; ++i) {
-pd[i].first_tb = NULL;
-invalidate_page_bitmap(pd + i);
-}
-} else {
-void **pp = *lp;
+for (i = 0; i < V_L2_SIZE; ++i) {
+atomic_set(&pd[i].first_tb, NULL);
+invalidate_page_bitmap(pd + i);
+}
+} else {
+void **pp = (void **) pd;
 
-for (i = 0; i < V_L2_SIZE; ++i) {
-page_flush_tb_1(level - 1, pp + i);
+for (i = 0; i < V_L2_SIZE; ++i) {
+page_flush_tb_1(level - 1, pp + i);
+}
 }
 }
 }
@@ -1360,7 +1359,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, 
tb_page_addr_t end,
 /* we remove all the TBs in the range [start, end[ */
 /* XXX: see if in some cases it could be faster to invalidate all
the code */
-tb = p->first_tb;
+tb = atomic_read(&p->first_tb);
 while (tb != NULL) {
 n = (uintptr_t)tb & 3;
 tb = (TranslationBlock *)((uintptr_t)tb & ~3);
@@ -1968,16 +1967,15 @@ void page_set_flags(target_ulong start, target_ulong 
end, int flags)
the code inside.  */
 if (!(p->flags & PAGE_WRITE) &&
 (flags & PAGE_WRITE) &&
-p->first_tb) {
+atomic_read(&p->first_tb)) {
 tb_invalidate_phys_page(addr, 0);
 }
-p->flags = flags;
+atomic_set(&p->flags, flags);
 }
 }
 
 int page_check_range(target_ulong start, target_ulong len, int flags)
 {
-PageDesc *p;
 target_ulong end;
 target_ulong addr;
 
@@ -2003,28 +2001,31 @@ int page_check_range(target_ulong start, target_ulong 
len, int flags)
 for (addr = start, len = end - start;
  len != 0;
  len -= TARGET_PAGE_SIZE, addr += TARGET_PAGE_SIZE) {
-p = page_find(addr >> TARGET_PAGE_BITS);
-if (!p) {
-return -1;
-}
-if (!(p->flags & PAGE_VALID)) {
-return -1;
-}
+PageDesc *p = page_find(addr >> TARGET_PAGE_BITS);
+if (p) {
+int cur_flags = atomic_read(&p->flags);
 
-if ((flags & PAGE_READ) && !(p->flags & PAGE_READ)) {
-return -1;
-}
-if (flags & PAGE_WRITE) {
-if (!(p->flags & PAGE_WRITE_ORG)) {
+if (!(cur_flags & PAGE_VALID)) {
 return -1;
 }
-/* unprotect the page if it was put read-only because it
-   contains translated code */
-if (!(p->flags & PAGE_WRITE)) {
-if (!page_unprotect(addr, 0)) {
+
+if ((flags & PAGE_READ) && !(cur_flags & PAGE_READ)) {
+return -1;
+}
+if (flags & PAGE_WRITE) {
+if (!(cur_flags & PAGE_WRITE_ORG)) {
 return -1;
 }
+/* unprotect the page if it was put read-only because it
+   contains translated code */
+if (!(cur_flags & PAGE_WRITE)) {
+if (!page_unprotect(addr, 0)) {
+return -1;
+}
+}
 }
+} else {
+return -1;
 }
 }
 return 0;
-- 
2.9.3