Re: [PATCH 10 of 20] ipath - support for userspace apps using coredriver

From: Linus Torvalds
Date: Thu Mar 16 2006 - 12:05:46 EST




On Thu, 16 Mar 2006, Bryan O'Sullivan wrote:
>
> This is precisely our case, btw. The pages in question are allocated
> during fops->open (some during dev->probe). mmap and nopage never
> allocate anything.

If the mapping isn't actually dynamic, then you really should use either:

- remap_pfn_range() (for when you have a physically consecutive page
mapping)
- vm_insert_page() (for when you have individual pages).

at mmap time. Either of those will then do the right thing at unmap.

The rules are:

- remap_pfn_range() doesn't muck around with "struct page" AT ALL, so you
can pass it damn well anything you want these days. It doesn't care,
the VM doesn't care, there's no ref-counting or page flag checking
either on the mmap or the munmap parh.

So with remap_pfn_range(), you can literally do just

remap_pfn_range(vma,
vma->vm_start,
device->phys_dma_address >> PAGE_SHIFT,
device->phys_dma_size,
vma->vm_page_prot);

and the VM will not care what that DMA region is (it might, for
example, be actual device memory, not real RAM at all). But this should
only be used on memory that will be guaranteed to be around for as long
as the mapping exists (which you can guarantee by doing refcounting of
your own "struct file"s, of course).

Normally, you'd use remap_pfn_range() only for special allocations.
Most commonly, it's not RAM at all, but the PCI MMIO memory window to
the hardware itself.

- vm_insert_page() wants _individual_ pages that have been allocated as
such by the page allocator. You can't pass it a kmalloc'ed area or
anything like that, but you _can_ pass it anything that works with the
page allocator. It will increment the page count appropriately for the
mapping, so you should think of it as a no-op: you can do

...
page = get_free_page(..);
if (!page)
return -ENOMEM;
vm_insert_page(mm, addr, page, prot);
...

.. and then in your close/module_exit routine ..
free_page(page);

ie you should do the freeing of _your_ references (you got one when you
allocated the page, so you should free it), and the VM layer will track
_its_ references (ie vm_insert_page() will do whatever is correct so
that when the VM gets unmapped, the page really gets freed)

As a special case (it's not actually a special case in the VM, but as
far as _usage_ is concerned, it's different from the "allocate
individual pages" case), if you allocate a single large _compound_ page
with __GFP_COMP, you can then use vm_insert_page() to insert the
sub-pages individually in the mapping. IOW, you can do

/* Get a compound page of order 4 (16 pages) */
bigpage = __get_free_pages(GFP_USER | __GFP_COMP, 4);
for (i = 0; i < 15; i++)
vm_insert_page(mm, addr + (i << PAGE_SHIFT), bigpage + i, prot);


.. in close/module-exit ..
free_page(bigpage);

Hope this clarifies.

Linus
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/