I think that I found source of problem. I have no simple solution :-(
You are using 'page_cache_entry()' function three times. But you
are using it on kmap()ped memory (cachep, in this oops example). So
it returns almost random value, which caused 'mapping' to be set
to NULL when doing grab_page_cache(), which caused oops later in
add_to_page_cache_unique...
But I'm not 100% sure, as this would mean that you do not
kunmap/UnlockPage/page_cache_release any >1GB page at all in
smb_free_cache_blocks(), as page pointer obtained by page_cache_entry()
points to some random page (to couple just below 1GB boundary) instead
of to correct one, so smbfs should die as soon as it finds first highmem
page... Is it possible?
Same problem is in smb_free_dircache.
You can try using __find_get_page() with index to get 'struct *page'
(it should always suceed, as you have all pages locked...), instead
of page_cache_entry(), but better solution is using couple { page,
page_address } instead of page_address alone.
So your system has couple of chances to deadlock - either on out of
kmaps, or on locked directory cache root (cachep), or on some of locked
directory cache pages (blocks)...
And one nonfatal ;-) In smb_add_to_cache you have:
page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
page = grab_cache_page(mapping, page_off >> PAGE_CACHE_SHIFT);
This does not look correct to me. You should use PAGE_CACHE_SHIFT and
PAGE_CACHE_SIZE, as otherwise you'll receive same page for idx=1 and 2
when cache will use 8KB pages, but CPU 4KB ones. Using only first 4KB
of each cache page is better solution, than using same page for two
different indexes, I think... But as currently PAGE_CACHE_SIZE == PAGE_SIZE...
Best regards,
Petr Vandrovec
vandrove@vc.cvut.cz
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/