Propper use of pci_map_sg

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

 



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
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux