From: Roland Dreier <hidden> Date: 2009-02-04 19:11:34
> > > huge_page_size(page_hstate(page))
> > That would suit. I assume the intention is for that to be usable by
> > driver modules on any architecture?
> erm, you overestimate the amount of planning and forethought which goes
> into these things ;)
> The lack of any EXPORT_SYMBOL(size_to_hstate) is a broadish hint.
Heh. Looking into the implementation, it seems that I could actually do
PAGE_SIZE << compound_order(page)
directly (since there's no reason to go from size to hstate and back to
size. I don't know all the details of these VM internals, but that
seems to only work on the first (small) page of a giant page? Which
causes problems for what we're trying to do here...
To summarize the goal, we are mapping user memory to a device that has
its own page tables, where the device's page tables can also use
multiple page sizes. Using big pages on the device leads to similar
efficiencies as hugetlb pages do on the CPU, and in fact if a user has
used hugetlb pages for the memory they're giving to the device, that's a
very strong hint that the device should use big pages too.
But one valid situation we have to handle in the driver is if, say,
userspace has a hugetlb mapped at virtual address 0x200000, and wants to
map 0x80000 bytes at 0x280000 to the device. In that case, we're going
to do essentially
get_user_pages(..., 0x280000, 0x80000 / PAGE_SIZE, ...)
and get_user_pages() is going to give us a bunch of normal PAGE_SIZE
pages starting at offset 0x800000 within the compound page that makes up
the huge page mapped at 0x200000.
get_user_pages() also gives us the vma back, and we can see from
is_vm_hugetlb_page() (-- BTW can I just say that a function
is_xxx_page() that operates on vmas is horribly misnamed --) that these
pages all come from a hugetlb mapping, but figuring out the size of that
mapping is I guess a challenge.
- R.
On Wed, Feb 04, 2009 at 11:11:22AM -0800, Roland Dreier wrote:
Heh. Looking into the implementation, it seems that I could actually do
PAGE_SIZE << compound_order(page)
directly (since there's no reason to go from size to hstate and back to
size. I don't know all the details of these VM internals, but that
seems to only work on the first (small) page of a giant page? Which
causes problems for what we're trying to do here...
You should be able to find the head of a compound page using the
compound_head() inline, so try
PAGE_SIZE << compound_order(compound_head(page))
-- wli
From: Andrew Morton <akpm@linux-foundation.org> Date: 2009-02-04 21:24:01
On Wed, 04 Feb 2009 11:11:22 -0800
Roland Dreier [off-list ref] wrote:
> > > huge_page_size(page_hstate(page))
> > That would suit. I assume the intention is for that to be usable by
> > driver modules on any architecture?
> erm, you overestimate the amount of planning and forethought which goes
> into these things ;)
> The lack of any EXPORT_SYMBOL(size_to_hstate) is a broadish hint.
Heh. Looking into the implementation, it seems that I could actually do
PAGE_SIZE << compound_order(page)
directly (since there's no reason to go from size to hstate and back to
size. I don't know all the details of these VM internals, but that
seems to only work on the first (small) page of a giant page? Which
causes problems for what we're trying to do here...
To summarize the goal, we are mapping user memory to a device that has
its own page tables, where the device's page tables can also use
multiple page sizes. Using big pages on the device leads to similar
efficiencies as hugetlb pages do on the CPU, and in fact if a user has
used hugetlb pages for the memory they're giving to the device, that's a
very strong hint that the device should use big pages too.
But one valid situation we have to handle in the driver is if, say,
userspace has a hugetlb mapped at virtual address 0x200000, and wants to
map 0x80000 bytes at 0x280000 to the device. In that case, we're going
to do essentially
get_user_pages(..., 0x280000, 0x80000 / PAGE_SIZE, ...)
and get_user_pages() is going to give us a bunch of normal PAGE_SIZE
pages starting at offset 0x800000 within the compound page that makes up
the huge page mapped at 0x200000.
get_user_pages() also gives us the vma back, and we can see from
is_vm_hugetlb_page() (-- BTW can I just say that a function
is_xxx_page() that operates on vmas is horribly misnamed --) that these
pages all come from a hugetlb mapping, but figuring out the size of that
mapping is I guess a challenge.
compound_head() will convert any page* inside a hugepage into a pointer
to the head page. It should work OK for regular pages as well as
CONFIG_HUGETLB=n.
So..
PAGE_SIZE << compound_order(compound_head(page))
?
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2009-02-04 23:56:59
get_user_pages() also gives us the vma back, and we can see from
is_vm_hugetlb_page() (-- BTW can I just say that a function
is_xxx_page() that operates on vmas is horribly misnamed --) that these
pages all come from a hugetlb mapping, but figuring out the size of that
mapping is I guess a challenge.
Note that g_u_p() has all sort of shortcommings... we were discussing
some of that recently due to bugs reported from the field.
The problem mostly is that you cannot guarantee that the physical page
will remain mapped to that virtual address in the process. For example,
if your code is part of some library used by an application, and that
application somewhere does a fork/exec (for example, a system() call to
run a shell helper), copy-on-write will hit, and you may end up with
the child process getting the original physical page and the original
process getting the copy...
So your HW will still DMA to a valid page (ie, it's count will have
been incremented) but it's not going to be the one the application
uses any more.
There are similar issues that can be cause, afaik, by madvise, etc...
We've been discussing that at KS with various people, Linus says g_u_p()
sucks, don't do that :-) Most of the time, the other approach should be
used, ie, the driver allocates memory, and userspace mmap's it, in which
case you get access to the VMA to set flags such as don't copy on fork.
An option possibly would be to make fork() pre-COW pages with an
elevated count to ensure that at least the original process is the one
to keep the original physical page... but that has other potential side
effects or performance issues.
A can of worms..
Cheers,
Ben.