[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] The hypercall will fail and return EFAULT when the page becomes COW by forking process in linux



On Mon, 2012-08-06 at 14:01 +0100, Wangzhenguo wrote:
> > -----Original Message-----
> > From: Ian Campbell [mailto:Ian.Campbell@xxxxxxxxxx]
> > Sent: Friday, August 03, 2012 6:10 PM
> > 
> > BTW, I think this would be a good fix to have for 4.2.0 if you are able
> > to produce a patch.
> > 
> Hi, Ian
> There is a patch that changes:
> 1. use madvise(MADV_DONTFORK) decleare that don't copy the vma when fork 
>    after allocating pages, and usr madvise(MADV_DOFORK) restore the flags 
>    of vma before freeing the pages.
> 2. use mmap/nunmap to alloc/free memory instead of malloc/free for passing 
>    through libc.
>    The free interface in libc may not really free memory, just returns the 
>    control to libc. If the memeory set not copy when call fork(), after 
> forking:
>    a, In child process, you call free() to the memory, then malloc(), 
>       the libc maybe return the same memory, if you access the memeory, 
>       and it causes segment fault.
>    b, If you not call the free() in child process, it maybe leak the memory 
>       which manages the malloc's memory in libc.
>    mmap/munmap don't those problems.
> 3. In the same thread, do not call fork() syscall between 
> xc__hypercall_buffer_alloc_pages 
>    and xc__hypercall_buffer_free_pages,otherwise it will cause segment fault 
>    when access the hypercall buffer in child process.
>   In normal context, we call alloc hypercall buffer, then call hypercall, 
> and free the hypercall buffer (or free to the cache). No one call fork() 
> between alloc and free hypercall buffers, so, I don't think it's a problem

Another thread in the process might fork though, wasn't that the main
observation you made when you first posted?

I think perhaps you mean it is forbidden to fork and then access a
hypercall buffer allocated before the fork, which sounds ok, since no
thread which allocates a hypercall buffer should fork with it still
allocated.

> .
> 
> We test the patch and it's OK on multi-threads and multi-processes context.
> 
> Thanks Ian and xiaowei for giving good ideas.

Thanks, this will need a Signed-off-by and a commit message as described
in: http://wiki.xen.org/wiki/Submitting_Xen_Patches

> diff -r 3d17148e465c tools/libxc/xc_hcall_buf.c
> --- a/tools/libxc/xc_hcall_buf.c      Thu Aug 02 11:49:37 2012 +0200
> +++ b/tools/libxc/xc_hcall_buf.c      Mon Aug 06 19:45:00 2012 +0800
> @@ -19,6 +19,7 @@

Please can you add this to your ~/.hgrc:
        [diff]
        showfunc = True

That will make "hg diff" and similar functions show the name of the
changed function here which is very useful for reviewers.

> @@ -135,6 +136,9 @@
>  
>      b->hbuf = p;
>  
> +    /*Do not copy the VMA to child process when call fork(), avoid the page 
> being COW when hyper calling*/
> +    madvise(p, nr_pages * PAGE_SIZE, MADV_DONTFORK);

madvise(2) tells me that MADV_{DO,DONT}FORK are Linux specific, so I
think this belongs in the Linux specific alloc_hypercall_buffer hook.

>      memset(p, 0, nr_pages * PAGE_SIZE);
>  
>      return b->hbuf;
> @@ -145,6 +149,8 @@
>      if ( b->hbuf == NULL )
>          return;
>  
> +    /*Recover the VMA flags, allow copy the VMA when call fork()*/
> +    madvise(b->hbuf, nr_pages * PAGE_SIZE, MADV_DOFORK) ;

Likewise I think this belongs in the free_hypercall_buffer hook.

>      if ( !hypercall_buffer_cache_free(xch, b->hbuf, nr_pages) )
>          xch->ops->u.privcmd.free_hypercall_buffer(xch, xch->ops_handle, 
> b->hbuf, nr_pages);
>  }
> diff -r 3d17148e465c tools/libxc/xc_linux_osdep.c
> --- a/tools/libxc/xc_linux_osdep.c    Thu Aug 02 11:49:37 2012 +0200
> +++ b/tools/libxc/xc_linux_osdep.c    Mon Aug 06 19:45:00 2012 +0800
> @@ -93,22 +93,14 @@
>      size_t size = npages * XC_PAGE_SIZE;
>      void *p;
>  
> -    p = xc_memalign(xch, XC_PAGE_SIZE, size);
> -    if (!p)
> -        return NULL;
> +    p = mmap(NULL, size, PROT_READ|PROT_WRITE, 
> MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, -1, 0);

I suppose this must necessarily return a page aligned result?

>  
> -    if ( mlock(p, size) < 0 )
> -    {
> -        free(p);
> -        return NULL;
> -    }
>      return p;
>  }
>  
>  static void linux_privcmd_free_hypercall_buffer(xc_interface *xch, 
> xc_osdep_handle h, void *ptr, int npages)
>  {
> -    munlock(ptr, npages * XC_PAGE_SIZE);
> -    free(ptr);
> +    munmap(ptr, npages * XC_PAGE_SIZE);
>  }
>  
>  static int linux_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, 
> privcmd_hypercall_t *hypercall)



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.