Richard Henderson <richard.hender...@linaro.org> writes:

> Finish weaning user-only away from PageDesc.
>
> Using an interval tree to track page permissions means that
> we can represent very large regions efficiently.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/290
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/967
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1214
> Signed-off-by: Richard Henderson <richard.hender...@linaro.org>
> ---
>  accel/tcg/internal.h           |   4 +-
>  accel/tcg/tb-maint.c           |  20 +-
>  accel/tcg/user-exec.c          | 614 ++++++++++++++++++++++-----------
>  tests/tcg/multiarch/test-vma.c |  22 ++
>  4 files changed, 451 insertions(+), 209 deletions(-)
>  create mode 100644 tests/tcg/multiarch/test-vma.c
>
> diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h
> index 250f0daac9..c7e157d1cd 100644
> --- a/accel/tcg/internal.h
> +++ b/accel/tcg/internal.h
> @@ -24,9 +24,7 @@
>  #endif
>  
>  typedef struct PageDesc {
> -#ifdef CONFIG_USER_ONLY
> -    unsigned long flags;
> -#else
> +#ifndef CONFIG_USER_ONLY
>      QemuSpin lock;
>      /* list of TBs intersecting this ram page */
>      uintptr_t first_tb;
> diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
> index 14e8e47a6a..694440cb4a 100644
> --- a/accel/tcg/tb-maint.c
> +++ b/accel/tcg/tb-maint.c
> @@ -68,15 +68,23 @@ static void page_flush_tb(void)
<snip>
>  
>  int page_get_flags(target_ulong address)
>  {
> -    PageDesc *p;
> +    PageFlagsNode *p = pageflags_find(address, address);
>  
> -    p = page_find(address >> TARGET_PAGE_BITS);
> +    /*
> +     * See util/interval-tree.c re lockless lookups: no false positives but
> +     * there are false negatives.  If we find nothing, retry with the mmap
> +     * lock acquired.
> +     */
>      if (!p) {
> -        return 0;
> +        if (have_mmap_lock()) {
> +            return 0;
> +        }
> +        mmap_lock();
> +        p = pageflags_find(address, address);
> +        mmap_unlock();
> +        if (!p) {
> +            return 0;
> +        }
>      }
>      return p->flags;

To avoid the brain twisting following locks and multiple return legs how about 
this:

  int page_get_flags(target_ulong address)
  {
      PageFlagsNode *p = pageflags_find(address, address);

      /*
       * See util/interval-tree.c re lockless lookups: no false positives but
       * there are false negatives.  If we had the lock and found
       * nothing we are done, otherwise retry with the mmap lock acquired.
       */
      if (have_mmap_lock()) {
          return p ? p->flags : 0;
      }

      mmap_lock();
      p = pageflags_find(address, address);
      mmap_unlock();

      return p ? p->flags : 0;
  }


> diff --git a/tests/tcg/multiarch/test-vma.c b/tests/tcg/multiarch/test-vma.c
> new file mode 100644
> index 0000000000..2893d60334
> --- /dev/null
> +++ b/tests/tcg/multiarch/test-vma.c
> @@ -0,0 +1,22 @@
> +/*
> + * Test very large vma allocations.
> + * The qemu out-of-memory condition was within the mmap syscall itself.
> + * If the syscall actually returns with MAP_FAILED, the test succeeded.
> + */
> +#include <sys/mman.h>
> +
> +int main()
> +{
> +    int n = sizeof(size_t) == 4 ? 32 : 45;
> +
> +    for (int i = 28; i < n; i++) {
> +        size_t l = (size_t)1 << i;
> +        void *p = mmap(0, l, PROT_NONE,
> +                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
> +        if (p == MAP_FAILED) {
> +            break;
> +        }
> +        munmap(p, l);
> +    }
> +    return 0;
> +}

So is the failure mode here we actually seg or bus out?

-- 
Alex Bennée

Reply via email to