Commit c902ce1bfb40d8b049bd2319b388b4b68b04bc27

Authored by David Howells
Committed by Linus Torvalds
1 parent 075d9db131

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>

Showing 5 changed files with 85 additions and 5 deletions Side-by-side Diff

Documentation/filesystems/caching/netfs-api.txt
... ... @@ -673,6 +673,22 @@
673 673 in which case the page will not be stored in the cache this time.
674 674  
675 675  
  676 +BULK INODE PAGE UNCACHE
  677 +-----------------------
  678 +
  679 +A convenience routine is provided to perform an uncache on all the pages
  680 +attached to an inode. This assumes that the pages on the inode correspond on a
  681 +1:1 basis with the pages in the cache.
  682 +
  683 + void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,
  684 + struct inode *inode);
  685 +
  686 +This takes the netfs cookie that the pages were cached with and the inode that
  687 +the pages are attached to. This function will wait for pages to finish being
  688 +written to the cache and for the cache to finish with the page generally. No
  689 +error is returned.
  690 +
  691 +
676 692 ==========================
677 693 INDEX AND DATA FILE UPDATE
678 694 ==========================
... ... @@ -92,6 +92,7 @@
92 92  
93 93 if (cifsi->fscache) {
94 94 cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache);
  95 + fscache_uncache_all_inode_pages(cifsi->fscache, inode);
95 96 fscache_relinquish_cookie(cifsi->fscache, 1);
96 97 cifsi->fscache = NULL;
97 98 }
... ... @@ -954,4 +954,48 @@
954 954 pagevec_reinit(pagevec);
955 955 }
956 956 EXPORT_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 + */
  962 +void __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 +}
  1000 +EXPORT_SYMBOL(__fscache_uncache_all_inode_pages);
... ... @@ -259,12 +259,10 @@
259 259 dfprintk(FSCACHE,
260 260 "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode));
261 261  
262   - /* Need to invalidate any mapped pages that were read in before
263   - * turning off the cache.
  262 + /* Need to uncache any pages attached to this inode that
  263 + * fscache knows about before turning off the cache.
264 264 */
265   - if (inode->i_mapping && inode->i_mapping->nrpages)
266   - invalidate_inode_pages2(inode->i_mapping);
267   -
  265 + fscache_uncache_all_inode_pages(NFS_I(inode)->fscache, inode);
268 266 nfs_fscache_zap_inode_cookie(inode);
269 267 }
270 268 }
include/linux/fscache.h
... ... @@ -204,6 +204,8 @@
204 204 extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *);
205 205 extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct page *,
206 206 gfp_t);
  207 +extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *,
  208 + struct inode *);
207 209  
208 210 /**
209 211 * fscache_register_netfs - Register a filesystem as desiring caching services
... ... @@ -641,6 +643,25 @@
641 643 if (fscache_cookie_valid(cookie) && PageFsCache(page))
642 644 return __fscache_maybe_release_page(cookie, page, gfp);
643 645 return false;
  646 +}
  647 +
  648 +/**
  649 + * fscache_uncache_all_inode_pages - Uncache all an inode's pages
  650 + * @cookie: The cookie representing the inode's cache object.
  651 + * @inode: The inode to uncache pages from.
  652 + *
  653 + * Uncache all the pages in an inode that are marked PG_fscache, assuming them
  654 + * to be associated with the given cookie.
  655 + *
  656 + * This function may sleep. It will wait for pages that are being written out
  657 + * and will wait whilst the PG_fscache mark is removed by the cache.
  658 + */
  659 +static inline
  660 +void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,
  661 + struct inode *inode)
  662 +{
  663 + if (fscache_cookie_valid(cookie))
  664 + __fscache_uncache_all_inode_pages(cookie, inode);
644 665 }
645 666  
646 667 #endif /* _LINUX_FSCACHE_H */