| 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
 
 |