Hi,
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); pinned=*get_user_pages_fast*((unsigned 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, DMA_BIDIRECTIONAL);
*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
                }
                kfree(scatterlist);
                kfree(pages);
                printk("Done\n");
                /*pageInfo.pageId = getPageId(getArea(&pageInfo));
copy_to_user((void*)arg, &pageInfo, sizeof(struct pageInfo));*/
                return pageInfo.pageId;
            } else {
                return -EFAULT;
            }
        }
            break;

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

    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;
    }
_______________________________________________
Kernelnewbies mailing list
[email protected]
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

Reply via email to