aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fscache
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-07-07 07:19:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-07 16:21:56 -0400
commitc902ce1bfb40d8b049bd2319b388b4b68b04bc27 (patch)
tree7dcb1e8378f8ec8e7ad7684cd26e9d5a1b5b22d1 /fs/fscache
parent075d9db13183c102770dc6cefabfee1b832f9614 (diff)
FS-Cache: Add a helper to bulk uncache pages on an inode
Add an FS-Cache helper to bulk uncache pages on an inode. This will only work for the circumstance where the pages in the cache correspond 1:1 with the pages attached to an inode's page cache. This is required for CIFS and NFS: When disabling inode cookie, we were returning the cookie and setting cifsi->fscache to NULL but failed to invalidate any previously mapped pages. This resulted in "Bad page state" errors and manifested in other kind of errors when running fsstress. Fix it by uncaching mapped pages when we disable the inode cookie. This patch should fix the following oops and "Bad page state" errors seen during fsstress testing. ------------[ cut here ]------------ kernel BUG at fs/cachefiles/namei.c:201! invalid opcode: 0000 [#1] SMP Pid: 5, comm: kworker/u:0 Not tainted 2.6.38.7-30.fc15.x86_64 #1 Bochs Bochs RIP: 0010: cachefiles_walk_to_object+0x436/0x745 [cachefiles] RSP: 0018:ffff88002ce6dd00 EFLAGS: 00010282 RAX: ffff88002ef165f0 RBX: ffff88001811f500 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000100 RDI: 0000000000000282 RBP: ffff88002ce6dda0 R08: 0000000000000100 R09: ffffffff81b3a300 R10: 0000ffff00066c0a R11: 0000000000000003 R12: ffff88002ae54840 R13: ffff88002ae54840 R14: ffff880029c29c00 R15: ffff88001811f4b0 FS: 00007f394dd32720(0000) GS:ffff88002ef00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00007fffcb62ddf8 CR3: 000000001825f000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process kworker/u:0 (pid: 5, threadinfo ffff88002ce6c000, task ffff88002ce55cc0) Stack: 0000000000000246 ffff88002ce55cc0 ffff88002ce6dd58 ffff88001815dc00 ffff8800185246c0 ffff88001811f618 ffff880029c29d18 ffff88001811f380 ffff88002ce6dd50 ffffffff814757e4 ffff88002ce6dda0 ffffffff8106ac56 Call Trace: cachefiles_lookup_object+0x78/0xd4 [cachefiles] fscache_lookup_object+0x131/0x16d [fscache] fscache_object_work_func+0x1bc/0x669 [fscache] process_one_work+0x186/0x298 worker_thread+0xda/0x15d kthread+0x84/0x8c kernel_thread_helper+0x4/0x10 RIP cachefiles_walk_to_object+0x436/0x745 [cachefiles] ---[ end trace 1d481c9af1804caa ]--- I tested the uncaching by the following means: (1) Create a big file on my NFS server (104857600 bytes). (2) Read the file into the cache with md5sum on the NFS client. Look in /proc/fs/fscache/stats: Pages : mrk=25601 unc=0 (3) Open the file for read/write ("bash 5<>/warthog/bigfile"). Look in proc again: Pages : mrk=25601 unc=25601 Reported-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-and-Tested-by: Suresh Jayaraman <sjayaraman@suse.de> cc: stable@kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fscache')
-rw-r--r--fs/fscache/page.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index a2a5d19ece6a..2f343b4d7a7d 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -954,3 +954,47 @@ void fscache_mark_pages_cached(struct fscache_retrieval *op,
954 pagevec_reinit(pagevec); 954 pagevec_reinit(pagevec);
955} 955}
956EXPORT_SYMBOL(fscache_mark_pages_cached); 956EXPORT_SYMBOL(fscache_mark_pages_cached);
957
958/*
959 * Uncache all the pages in an inode that are marked PG_fscache, assuming them
960 * to be associated with the given cookie.
961 */
962void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,
963 struct inode *inode)
964{
965 struct address_space *mapping = inode->i_mapping;
966 struct pagevec pvec;
967 pgoff_t next;
968 int i;
969
970 _enter("%p,%p", cookie, inode);
971
972 if (!mapping || mapping->nrpages == 0) {
973 _leave(" [no pages]");
974 return;
975 }
976
977 pagevec_init(&pvec, 0);
978 next = 0;
979 while (next <= (loff_t)-1 &&
980 pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)
981 ) {
982 for (i = 0; i < pagevec_count(&pvec); i++) {
983 struct page *page = pvec.pages[i];
984 pgoff_t page_index = page->index;
985
986 ASSERTCMP(page_index, >=, next);
987 next = page_index + 1;
988
989 if (PageFsCache(page)) {
990 __fscache_wait_on_page_write(cookie, page);
991 __fscache_uncache_page(cookie, page);
992 }
993 }
994 pagevec_release(&pvec);
995 cond_resched();
996 }
997
998 _leave("");
999}
1000EXPORT_SYMBOL(__fscache_uncache_all_inode_pages);