The fact that Linus doesn't like O_DIRECT has nothing to do with whether it works or not. I agree with him 100% that you should never need to bypass the page cache. You were the one that was stating that the page cache was limiting your application memory, not me... remember?
So, if you want to you can disagree -- you're still wrong.
I did a search on the LKML, and there are a ton of messages about drop_caches. None of those messages say anything about drop_caches not actually dropping cached pages. Can you point us to a single resource at all which backs up your assertion that drop_caches doesn't work? I'm not saying you're wrong, I just find it suspicious that there's no posts that I can find to back up your claims.
Anyways, since you seem to be so sure of yourself, I did a little checking. Setting the drop_caches proc will execute the following code:
fs/drop_caches.c
Code:
28void drop_pagecache(void)
29{
30 struct super_block *sb;
31
32 spin_lock(&sb_lock);
33restart:
34 list_for_each_entry(sb, &super_blocks, s_list) {
35 sb->s_count++;
36 spin_unlock(&sb_lock);
37 down_read(&sb->s_umount);
38 if (sb->s_root)
39 drop_pagecache_sb(sb);
40 up_read(&sb->s_umount);
41 spin_lock(&sb_lock);
42 if (__put_super_and_need_restart(sb))
43 goto restart;
44 }
45 spin_unlock(&sb_lock);
46}
Which calls the following:
/fs/drop_caches.c
Code:
15static void drop_pagecache_sb(struct super_block *sb)
16{
17 struct inode *inode;
18
19 spin_lock(&inode_lock);
20 list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
21 if (inode->i_state & (I_FREEING|I_WILL_FREE))
22 continue;
23 invalidate_inode_pages(inode->i_mapping);
24 }
25 spin_unlock(&inode_lock);
26}
Now invalidate_inode_pages() just calls invalidate_mapping_pages():
/mm/truncate.c
Code:
223unsigned long invalidate_mapping_pages(struct address_space *mapping,
224 pgoff_t start, pgoff_t end)
225{
226 struct pagevec pvec;
227 pgoff_t next = start;
228 unsigned long ret = 0;
229 int i;
230
231 pagevec_init(&pvec, 0);
232 while (next <= end &&
233 pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
234 for (i = 0; i < pagevec_count(&pvec); i++) {
235 struct page *page = pvec.pages[i];
236 pgoff_t index;
237 int lock_failed;
238
239 lock_failed = TestSetPageLocked(page);
240
241 /*
242 * We really shouldn't be looking at the ->index of an
243 * unlocked page. But we're not allowed to lock these
244 * pages. So we rely upon nobody altering the ->index
245 * of this (pinned-by-us) page.
246 */
247 index = page->index;
248 if (index > next)
249 next = index;
250 next++;
251 if (lock_failed)
252 continue;
253
254 if (PageDirty(page) || PageWriteback(page))
255 goto unlock;
256 if (page_mapped(page))
257 goto unlock;
258 ret += invalidate_complete_page(mapping, page);
259unlock:
260 unlock_page(page);
261 if (next > end)
262 break;
263 }
264 pagevec_release(&pvec);
265 }
266 return ret;
267}
As you can see it will skip dirty pages and memory mapped pages. Well invalidate_complete_page() looks like:
/mm/truncate.c
Code:
61static int
62invalidate_complete_page(struct address_space *mapping, struct page *page)
63{
64 if (page->mapping != mapping)
65 return 0;
66
67 if (PagePrivate(page) && !try_to_release_page(page, 0))
68 return 0;
69
70 write_lock_irq(&mapping->tree_lock);
71 if (PageDirty(page))
72 goto failed;
73 if (page_count(page) != 2) /* caller's ref + pagecache ref */
74 goto failed;
75
76 BUG_ON(PagePrivate(page));
77 __remove_from_page_cache(page);
78 write_unlock_irq(&mapping->tree_lock);
79 ClearPageUptodate(page);
80 page_cache_release(page); /* pagecache ref */
81 return 1;
82failed:
83 write_unlock_irq(&mapping->tree_lock);
84 return 0;
85}
Hmm... the function __remove_from_page_cache() sounds like it may actually do something...
/mm/filemap.c
Code:
110/*
111 * Remove a page from the page cache and free it. Caller has to make
112 * sure the page is locked and that nobody else uses it - or that usage
113 * is safe. The caller must hold a write_lock on the mapping's tree_lock.
114 */
115void __remove_from_page_cache(struct page *page)
116{
117 struct address_space *mapping = page->mapping;
118
119 radix_tree_delete(&mapping->page_tree, page->index);
120 page->mapping = NULL;
121 mapping->nrpages--;
122 __dec_zone_page_state(page, NR_FILE_PAGES);
123}
Are you still sure that I'm wrong? By the way, all this code is from 2.6.18 which is the version you claim has the broken drop_caches implementation.