* [parisc-linux] Bug in flush_dcache_page?
@ 2001-10-31 17:39 Matthew Wilcox
2001-10-31 18:08 ` Matthew Wilcox
0 siblings, 1 reply; 4+ messages in thread
From: Matthew Wilcox @ 2001-10-31 17:39 UTC (permalink / raw)
To: parisc-linux
Thomas Bogendoerfer's being trying to get an L3000 to boot, and is seeing
similar problems to those seen by Bjorn on Superdome. I think I have a lead.
Documentation/cachetlb.txt says:
void flush_dcache_page(struct page *page)
Any time the kernel writes to a page cache page, _OR_
the kernel is about to read from a page cache page and
user space shared/writable mappings of this page potentially
exist, this routine is called.
Our implementation does:
static inline void flush_dcache_page(struct page *page)
{
if (page->mapping && !page->mapping->i_mmap &&
!page->mapping->i_mmap_shared) {
set_bit(PG_dcache_dirty, &page->flags);
} else {
flush_kernel_dcache_page(page_address(page));
}
}
What we're missing is the case where the user has dirtied the page,
then the kernel calls flush_dcache_page before writing to the page.
This strikes me as a bad interface... there should be different interfaces
for `before the kernel writes' and `after the kernel writes', but let's
see if we can fix our implementation.
we have an interface to use, flush_user_dcache_range. so we can iterate
over all the mappings and flush each of the user ranges. btw, we're missing
an optimisation -- if page->mapping is NULL, we can set the PG_dcache_dirty
bit. This lets us optimise a little more:
static inline void flush_dcache_page(struct page *page)
{
if (!page->mapping || (page->mapping && !page->mapping->i_mmap &&
!page->mapping->i_mmap_shared)) {
set_bit(PG_dcache_dirty, &page->flags);
} else {
struct vm_area_struct *vma;
for (vma = page->mapping->i_mmap; vma; vma = vma->vm_next) {
flush_user_page(vma->vm_mm, vma->vm_start + page->index);
}
if (page->mapping->i_mmap_shared) {
vma = page->mapping->i_mmap_shared;
flush_user_page(vma->vm_mm, vma->vm_start + page->index);
}
flush_kernel_dcache_page(page_address(page));
}
}
We only need to flush the first shared mapping because they're all congruent
modulo 4MB. I suspect there are other optimisations possible (is it
really possible to have multiple _dirty_ pages on the i_mmap list?)
but this might work better.
OTOH this is adding a lot of complexity for an inline function. maybe we
should just call flush_data_cache() and have done with it :-(
--
Revolutions do not require corporate support.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [parisc-linux] Bug in flush_dcache_page?
2001-10-31 17:39 [parisc-linux] Bug in flush_dcache_page? Matthew Wilcox
@ 2001-10-31 18:08 ` Matthew Wilcox
2001-11-01 1:56 ` Carlos O'Donell Jr.
0 siblings, 1 reply; 4+ messages in thread
From: Matthew Wilcox @ 2001-10-31 18:08 UTC (permalink / raw)
To: Matthew Wilcox; +Cc: parisc-linux
On Wed, Oct 31, 2001 at 05:39:05PM +0000, Matthew Wilcox wrote:
> static inline void flush_dcache_page(struct page *page)
> {
> if (!page->mapping || (page->mapping && !page->mapping->i_mmap &&
> !page->mapping->i_mmap_shared)) {
> set_bit(PG_dcache_dirty, &page->flags);
> } else {
> struct vm_area_struct *vma;
> for (vma = page->mapping->i_mmap; vma; vma = vma->vm_next) {
> flush_user_page(vma->vm_mm, vma->vm_start + page->index);
> }
> if (page->mapping->i_mmap_shared) {
> vma = page->mapping->i_mmap_shared;
> flush_user_page(vma->vm_mm, vma->vm_start + page->index);
> }
> flush_kernel_dcache_page(page_address(page));
> }
> }
Aha. A couple of things from talking to various VM/VFS people...
1. page->mapping is guaranteed to exist for pages in the page cache --
this is how they're located.
2. If a page is simultaneously mapped in both user and kernel space, and
user space touches it, either it leaves the page cache or it was mapped
shared.
flush_dcache_page is only called on pages in the page cache, so we can
assume that page->mapping exists, and we don't need to flush any user
mappings of this page.
if (!page->mapping->i_mmap & !page->mapping->i_mmap_shared) {
set_bit(PG_dcache_dirty, &page->flags);
} else {
struct vm_area_struct *vma = page->mapping->i_mmap_shared;
if (vma) {
flush_user_page(vma->vm_mm, vma->vm_start + page->index);
}
flush_kernel_dcache_page(page_address(page));
}
--
Revolutions do not require corporate support.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [parisc-linux] Bug in flush_dcache_page?
2001-10-31 18:08 ` Matthew Wilcox
@ 2001-11-01 1:56 ` Carlos O'Donell Jr.
2001-11-01 3:03 ` Matthew Wilcox
0 siblings, 1 reply; 4+ messages in thread
From: Carlos O'Donell Jr. @ 2001-11-01 1:56 UTC (permalink / raw)
To: parisc-linux
>
> Aha. A couple of things from talking to various VM/VFS people...
> 1. page->mapping is guaranteed to exist for pages in the page cache --
> this is how they're located.
> 2. If a page is simultaneously mapped in both user and kernel space, and
> user space touches it, either it leaves the page cache or it was mapped
> shared.
>
Why would a user touch cause the page to leave the cache?
(Maybe I'm not reading enough into it...)
The shared case I can see.
> flush_dcache_page is only called on pages in the page cache, so we can
> assume that page->mapping exists, and we don't need to flush any user
> mappings of this page.
>
> if (!page->mapping->i_mmap & !page->mapping->i_mmap_shared) {
> set_bit(PG_dcache_dirty, &page->flags);
> } else {
> struct vm_area_struct *vma = page->mapping->i_mmap_shared;
> if (vma) {
> flush_user_page(vma->vm_mm, vma->vm_start + page->index);
> }
> flush_kernel_dcache_page(page_address(page));
> }
>
Any particular reason for the bitwise and?
c.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [parisc-linux] Bug in flush_dcache_page?
2001-11-01 1:56 ` Carlos O'Donell Jr.
@ 2001-11-01 3:03 ` Matthew Wilcox
0 siblings, 0 replies; 4+ messages in thread
From: Matthew Wilcox @ 2001-11-01 3:03 UTC (permalink / raw)
To: Carlos O'Donell Jr., parisc-linux
On Wed, Oct 31, 2001 at 08:56:06PM -0500, Carlos O'Donell Jr. wrote:
> > 2. If a page is simultaneously mapped in both user and kernel space, and
> > user space touches it, either it leaves the page cache or it was mapped
> > shared.
>
> Why would a user touch cause the page to leave the cache?
> (Maybe I'm not reading enough into it...)
>
> The shared case I can see.
I meant `dirty' rather than `touch'. If the page is mapped shared, writes
to it are visible to all users. If it's mapped private, a write does
a copy-on-write. The page leaves the page cache at this point because its
contents are no longer valuable to anyone except the process.
> > if (!page->mapping->i_mmap & !page->mapping->i_mmap_shared) {
> > set_bit(PG_dcache_dirty, &page->flags);
> > } else {
>
> Any particular reason for the bitwise and?
It's not a sequence point. So it doesn't have to be test, branch, test,
branch; it can be test, test, branch. I'm not sure how the compiler does
on this, to be honest. It's a microoptimisation that's almost certainly
not worth making.
--
Revolutions do not require corporate support.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2001-11-01 3:03 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-10-31 17:39 [parisc-linux] Bug in flush_dcache_page? Matthew Wilcox
2001-10-31 18:08 ` Matthew Wilcox
2001-11-01 1:56 ` Carlos O'Donell Jr.
2001-11-01 3:03 ` Matthew Wilcox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox