Propper use of pci_map_sg

Malte Vesper malte.vesper at
Thu Jan 29 14:50:52 EST 2015

I am trying to use pci_map_sg in combination with get_user_pages_fast 
for a driver. However my code screws the processes memory map over. For 
easier testing I bundled the piinin/unpinning and mapping unmapping into 
one ioctl call. The following code misses all the checks on return 
values, since it is only inteneded as a MWE.

When I run my code I get a "*BUG: Bad page map in process ...*", after 
"Done" is printed.

I tried following DMA-API-howto.txt and looking at other code, but I 
fail to see where I go wrong.

Regards, Ted

Code from the IOCTL handler:

         case IOCTL_FPGA_PIN_PAGE:
             struct pageInfo pageInfo;

             dev_dbg(&pcidev->dev, pr_fmt("IOCTL: IOCTL_FPGA_PIN_PAGE\n"));

             if(!copy_from_user(&pageInfo, (void*)arg, sizeof(struct 
pageInfo))) {
                 //horrible test
                 const int noPages = pageInfo.size/PAGE_SIZE;
                 int pinned;
                 int mapped  = 0;
                 struct scatterlist* scatterlist;
                 printk("Test start\n");
                 //userspacestartpointer, nopages, write?, page* array
                 struct page** pages=kmalloc(sizeof(struct 
page*)*noPages, GFP_KERNEL);
long)pageInfo.start, noPages, 1, pages);

                 scatterlist = kmalloc(sizeof(struct 
scatterlist)*pinned, GFP_KERNEL);

                 for(int i=0; i<pinned; ++i) {
                     sg_set_page(&scatterlist[i], pages[i], PAGE_SIZE, 0);

                 mapped =*pci_map_sg*(pcidev, scatterlist, pinned, 
*pci_unmap_sg*(pcidev, scatterlist, pinned, DMA_BIDIRECTIONAL);

                 for(int i=0; i<pinned; ++i) {
*put_page*(pages[i]); //I did place a print here and got two pages 
unpinned as I expected
                 /*pageInfo.pageId = getPageId(getArea(&pageInfo));
                 copy_to_user((void*)arg, &pageInfo, sizeof(struct 
                 return pageInfo.pageId;
             } else {
                 return -EFAULT;

P.S.: I used the following code to allocate the memory in userspace, and 
I use chunk and chunksize to fill pageInfo.start and pageInfo.size 

     const int pagesize = sysconf(_SC_PAGESIZE);
     const int chunksize = 2*pagesize;
     void* chunk;

     if(int error = posix_memalign(&chunk, pagesize, chunksize)) {
         std::cout << "Could not get a page." << std::endl;
         return error;
-------------- next part --------------
An HTML attachment was scrubbed...

More information about the Kernelnewbies mailing list