Sébastien FREMAL [530784]
2013-Jul-24 14:46 UTC
Shared memory between a process in dom0 and a process in domU
Hello, I''m trying to share memory pages between a process executing in dom0 and a process executing in a domU. I work with xen 4.3 and linux 3.2 (it''s necessary due to a compatibility issue). I succeeded in accessing pages from a process in dom0, but I''m encountering problems to access them from a domU. I tried two methods : 1) I allocate a vm area in which I put the pages identified by their grant references. This step works, but I don''t find how to retrieve the pages in the mmap function to map them into user space. Here is the corresponding code (it''s based on the xensocket code) : if (!(x->buffer_area = alloc_vm_area(buffer_num_pages * PAGE_SIZE, NULL))) { DPRINTK("error: cannot allocate %d buffer pages\n", buffer_num_pages); goto err_unmap; } //x->buffer_addr is a pointer used to access more easily to x->buffer_area->addr x->buffer_addr = (unsigned long)x->buffer_area->addr; //we retrieve the first gref grefp = &d->buffer_first_gref; for (i = 0; i < buffer_num_pages; i++) { memset(&op, 0, sizeof(op)); op.host_addr = x->buffer_addr + i * PAGE_SIZE; op.flags = GNTMAP_host_map; op.ref = *grefp; op.dom = x->otherend_id; rc = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); if (rc == -ENOSYS) { goto err_unmap; } if (op.status) { DPRINTK("error: grant table mapping failed\n"); goto err_unmap; } x->buffer_handles[i] = op.handle; grefp = (int *)(x->buffer_addr + i * PAGE_SIZE); } Now, the grefs are mapped and the data they contain is accessible from the module. I instantiated a mmap function to access them from a user process : //I first tried to get the PFN of the page to map it with remap_pfn_range, but it doesn''t work as vmalloc_to_pfn returns 0 and not the PFN unsigned long pfn = vmalloc_to_pfn((void *)(x->buffer_addr+recv_offset*PAGE_SIZE)); if(pfn_valid(pfn)){ printk(KERN_INFO "PFN is valide\n"); } //I studied how gntdev worked and I realised it uses vm_insert_page, I then tried to retrieve the struct page instead of the PFN struct page * shPage = vmalloc_to_page((void *)(x->buffer_addr+recv_offset*PAGE_SIZE)); if(shPage == NULL) printk(KERN_INFO "Page not found\n"); vma->vm_flags |= VM_RESERVED; //This function fails with the error code -22 (invalid value) int err = vm_insert_page(vma, vma->vm_start, shPage); if (err) printk(KERN_INFO "Error while inserting a page\n"); else printk(KERN_INFO "Page inserted !!"); I don''t understand why this method fails. vmalloc_to_page returns a struct page *, but the function page_count (called by vm_insert_page) fails when called for this page. Is there a subtlety specific to Xen to allow this operation to succeed ? 2) As the first method didn''t succeed, I used what was done in gntdev (using pages instead of vm area to "mount" granted references) : if((x->pages = kcalloc(buffer_num_pages, sizeof(x->pages[0]), GFP_KERNEL))==NULL){ printk(KERN_INFO "No space left on device\n"); goto err; } if(alloc_xenballooned_pages(buffer_num_pages, x->pages, false)){ printk(KERN_INFO "No place anymore for ballooned pages"); goto err; } //I did the test for 1 page only for (i = 0; i < 1; i++) { memset(&op, 0, sizeof(op)); //I succeed here to get the PFN and the kaddr corresponding with the page unsigned long pfn = page_to_pfn(x->pages[i]); gnttab_set_map_op(&op, (unsigned long) pfn_to_kaddr(pfn), GNTMAP_host_map, *grefp, x->otherend_id); rc = gnttab_map_refs(&op,NULL,x->pages+i, 1); if(rc){ printk(KERN_INFO "Error while mapping ref\n"); goto err_unmap; } else if (op.status) { DPRINTK("error: grant table mapping failed\n"); goto err_unmap; } else printk(KERN_INFO "Page mapped\n"); } I don''t really know what happens here, but when gnttab_map_refs is called, the calling domU is rebooted and its ID is changed (from 1 to 2 i.e.). Can someone please tell me what''s wrong in my code ? I just have to get the right page in the first method to make it work. Thank you. Best regards, Sebastien Fremal _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Ian Campbell
2013-Jul-29 08:33 UTC
Re: Shared memory between a process in dom0 and a process in domU
On Wed, 2013-07-24 at 14:46 +0000, Sébastien FREMAL [530784] wrote:> Hello, > > I'm trying to share memory pages between a process executing in dom0 > and a process executing in a domU. I work with xen 4.3 and linux 3.2 > (it's necessary due to a compatibility issue). I succeeded in > accessing pages from a process in dom0, but I'm encountering problems > to access them from a domU. I tried two methods : > 1) I allocate a vm area in which I put the pages identified by their > grant references. This step works, but I don't find how to retrieve > the pages in the mmap function to map them into user space. Here is > the corresponding code (it's based on the xensocket code) : > > if (!(x->buffer_area = alloc_vm_area(buffer_num_pages * PAGE_SIZE, > NULL))) { > DPRINTK("error: cannot allocate %d buffer pages\n", > buffer_num_pages); > goto err_unmap; > } > > //x->buffer_addr is a pointer used to access more easily to > x->buffer_area->addr > x->buffer_addr = (unsigned long)x->buffer_area->addr; > > //we retrieve the first gref > grefp = &d->buffer_first_gref; > for (i = 0; i < buffer_num_pages; i++) { > > memset(&op, 0, sizeof(op)); > op.host_addr = x->buffer_addr + i * PAGE_SIZE; > op.flags = GNTMAP_host_map; > op.ref = *grefp; > op.dom = x->otherend_id; > > rc = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); > if (rc == -ENOSYS) { > goto err_unmap; > } > > if (op.status) { > DPRINTK("error: grant table mapping failed\n"); > goto err_unmap; > } > > x->buffer_handles[i] = op.handle; > grefp = (int *)(x->buffer_addr + i * PAGE_SIZE); > } > > Now, the grefs are mapped and the data they contain is accessible from > the module. I instantiated a mmap function to access them from a user > process : > > //I first tried to get the PFN of the page to map it with > remap_pfn_range, but it doesn't work as vmalloc_to_pfn returns 0 and > not the PFN > unsigned long pfn = vmalloc_to_pfn((void *)(x->buffer_addr > +recv_offset*PAGE_SIZE)); > if(pfn_valid(pfn)){ > printk(KERN_INFO "PFN is valide\n"); > } > > //I studied how gntdev worked and I realised it uses vm_insert_page, I > then tried to retrieve the struct page instead of the PFN > struct page * shPage = vmalloc_to_page((void *)(x->buffer_addr > +recv_offset*PAGE_SIZE)); > if(shPage == NULL) > printk(KERN_INFO "Page not found\n"); > > vma->vm_flags |= VM_RESERVED; > > //This function fails with the error code -22 (invalid value) > int err = vm_insert_page(vma, vma->vm_start, shPage); > if (err) > printk(KERN_INFO "Error while inserting a page\n"); > else > printk(KERN_INFO "Page inserted !!"); > > I don't understand why this method fails. vmalloc_to_page returns a > struct page *, but the function page_count (called by vm_insert_page) > fails when called for this page.What do you mean by "fails"? That function returns the current value of the page's reference count it cannot really fail as such.> Is there a subtlety specific to Xen to allow this operation to > succeed ?Not as far as I know, your issue appears to be a generic Linux one. I don't know the answer off hand but you might want to try one of the Linux lists/newgroups perhaps?> I don't really know what happens here, but when gnttab_map_refs is > called, the calling domU is rebooted and its ID is changed (from 1 to > 2 i.e.).Perhaps the guest tried something so illegal that it was killed and the toolstack rebooted it? You should see evidence of this in either the hypervisor logs or the toolstack logs.> Can someone please tell me what's wrong in my code ? I just have to > get the right page in the first method to make it work.If what you want to do is share memory between dom0 and domU userspace then you should look into the gntdev and gntshr device drivers which already exist to support this usecase and will mean you don't need to write any drivers at all. For an example of the use of these existing drivers you could look at libvchan (tools/libvchan). In fact if what you want is a shared memory ring protocol between two processes then libvchan may already do everything you need. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Sébastien Frémal
2013-Jul-31 10:13 UTC
Re: Shared memory between a process in dom0 and a process in domU
Hello, Thank you for your answer. As the struct page * I get with vmalloc_to_page is not a valid reference, page_count returns 0 and the function vm_insert_page returns with an error : int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page) { if (addr < vma->vm_start || addr >= vma->vm_end) return -EFAULT; if (!page_count(page)) return -EINVAL; if (!(vma->vm_flags & VM_MIXEDMAP)) { BUG_ON(down_read_trylock(&vma->vm_mm->mmap_sem)); BUG_ON(vma->vm_flags & VM_PFNMAP); vma->vm_flags |= VM_MIXEDMAP; } return insert_page(vma, addr, page, vma->vm_page_prot); } I already studied the xen drivers and libvchan to understand how xen mechanisms work, but they don''t operate exactly the way I wish (I search to transfer data with a ring buffer without any copy). I decided to work in the user space instead of the kernel space as I have less problem there. I will use xen-evtchn and xen-gntdev to use kernel features. Best regards, Sebastien Fremal 2013/7/29 Ian Campbell <Ian.Campbell@citrix.com>> On Wed, 2013-07-24 at 14:46 +0000, Sébastien FREMAL [530784] wrote: > > Hello, > > > > I''m trying to share memory pages between a process executing in dom0 > > and a process executing in a domU. I work with xen 4.3 and linux 3.2 > > (it''s necessary due to a compatibility issue). I succeeded in > > accessing pages from a process in dom0, but I''m encountering problems > > to access them from a domU. I tried two methods : > > 1) I allocate a vm area in which I put the pages identified by their > > grant references. This step works, but I don''t find how to retrieve > > the pages in the mmap function to map them into user space. Here is > > the corresponding code (it''s based on the xensocket code) : > > > > if (!(x->buffer_area = alloc_vm_area(buffer_num_pages * PAGE_SIZE, > > NULL))) { > > DPRINTK("error: cannot allocate %d buffer pages\n", > > buffer_num_pages); > > goto err_unmap; > > } > > > > //x->buffer_addr is a pointer used to access more easily to > > x->buffer_area->addr > > x->buffer_addr = (unsigned long)x->buffer_area->addr; > > > > //we retrieve the first gref > > grefp = &d->buffer_first_gref; > > for (i = 0; i < buffer_num_pages; i++) { > > > > memset(&op, 0, sizeof(op)); > > op.host_addr = x->buffer_addr + i * PAGE_SIZE; > > op.flags = GNTMAP_host_map; > > op.ref = *grefp; > > op.dom = x->otherend_id; > > > > rc = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); > > if (rc == -ENOSYS) { > > goto err_unmap; > > } > > > > if (op.status) { > > DPRINTK("error: grant table mapping failed\n"); > > goto err_unmap; > > } > > > > x->buffer_handles[i] = op.handle; > > grefp = (int *)(x->buffer_addr + i * PAGE_SIZE); > > } > > > > Now, the grefs are mapped and the data they contain is accessible from > > the module. I instantiated a mmap function to access them from a user > > process : > > > > //I first tried to get the PFN of the page to map it with > > remap_pfn_range, but it doesn''t work as vmalloc_to_pfn returns 0 and > > not the PFN > > unsigned long pfn = vmalloc_to_pfn((void *)(x->buffer_addr > > +recv_offset*PAGE_SIZE)); > > if(pfn_valid(pfn)){ > > printk(KERN_INFO "PFN is valide\n"); > > } > > > > //I studied how gntdev worked and I realised it uses vm_insert_page, I > > then tried to retrieve the struct page instead of the PFN > > struct page * shPage = vmalloc_to_page((void *)(x->buffer_addr > > +recv_offset*PAGE_SIZE)); > > if(shPage == NULL) > > printk(KERN_INFO "Page not found\n"); > > > > vma->vm_flags |= VM_RESERVED; > > > > //This function fails with the error code -22 (invalid value) > > int err = vm_insert_page(vma, vma->vm_start, shPage); > > if (err) > > printk(KERN_INFO "Error while inserting a page\n"); > > else > > printk(KERN_INFO "Page inserted !!"); > > > > I don''t understand why this method fails. vmalloc_to_page returns a > > struct page *, but the function page_count (called by vm_insert_page) > > fails when called for this page. > > What do you mean by "fails"? That function returns the current value of > the page''s reference count it cannot really fail as such. > > > Is there a subtlety specific to Xen to allow this operation to > > succeed ? > > Not as far as I know, your issue appears to be a generic Linux one. I > don''t know the answer off hand but you might want to try one of the > Linux lists/newgroups perhaps? > > > I don''t really know what happens here, but when gnttab_map_refs is > > called, the calling domU is rebooted and its ID is changed (from 1 to > > 2 i.e.). > > Perhaps the guest tried something so illegal that it was killed and the > toolstack rebooted it? You should see evidence of this in either the > hypervisor logs or the toolstack logs. > > > Can someone please tell me what''s wrong in my code ? I just have to > > get the right page in the first method to make it work. > > If what you want to do is share memory between dom0 and domU userspace > then you should look into the gntdev and gntshr device drivers which > already exist to support this usecase and will mean you don''t need to > write any drivers at all. > > For an example of the use of these existing drivers you could look at > libvchan (tools/libvchan). In fact if what you want is a shared memory > ring protocol between two processes then libvchan may already do > everything you need. > > Ian. > > > >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel