On Thu, Jul 07, 2011 at 04:14:31PM -0700, gre...@suse.de wrote: > > The patch below does not apply to the .39-stable tree. > If someone wants it applied there, or to any other stable or longterm > tree, then please email the backport, including the original git commit > id to <sta...@kernel.org>.
Oops, no, I got it to work, sorry for the noise. greg k-h > ------------------ original commit in Linus's tree ------------------ > > >From c902ce1bfb40d8b049bd2319b388b4b68b04bc27 Mon Sep 17 00:00:00 2001 > From: David Howells <dhowe...@redhat.com> > Date: Thu, 7 Jul 2011 12:19:48 +0100 > Subject: [PATCH] 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 <jlay...@redhat.com> > Signed-off-by: David Howells <dhowe...@redhat.com> > Reviewed-and-Tested-by: Suresh Jayaraman <sjayara...@suse.de> > cc: sta...@kernel.org > Signed-off-by: Linus Torvalds <torva...@linux-foundation.org> > > diff --git a/Documentation/filesystems/caching/netfs-api.txt > b/Documentation/filesystems/caching/netfs-api.txt > index a167ab8..7cc6bf2 100644 > --- a/Documentation/filesystems/caching/netfs-api.txt > +++ b/Documentation/filesystems/caching/netfs-api.txt > @@ -673,6 +673,22 @@ storage request to complete, or it may attempt to cancel > the storage request - > in which case the page will not be stored in the cache this time. > > > +BULK INODE PAGE UNCACHE > +----------------------- > + > +A convenience routine is provided to perform an uncache on all the pages > +attached to an inode. This assumes that the pages on the inode correspond > on a > +1:1 basis with the pages in the cache. > + > + void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, > + struct inode *inode); > + > +This takes the netfs cookie that the pages were cached with and the inode > that > +the pages are attached to. This function will wait for pages to finish being > +written to the cache and for the cache to finish with the page generally. No > +error is returned. > + > + > ========================== > INDEX AND DATA FILE UPDATE > ========================== > diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c > index 8166966..42e5363 100644 > --- a/fs/cifs/fscache.c > +++ b/fs/cifs/fscache.c > @@ -92,6 +92,7 @@ static void cifs_fscache_disable_inode_cookie(struct inode > *inode) > > if (cifsi->fscache) { > cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache); > + fscache_uncache_all_inode_pages(cifsi->fscache, inode); > fscache_relinquish_cookie(cifsi->fscache, 1); > cifsi->fscache = NULL; > } > diff --git a/fs/fscache/page.c b/fs/fscache/page.c > index a2a5d19..2f343b4 100644 > --- a/fs/fscache/page.c > +++ b/fs/fscache/page.c > @@ -954,3 +954,47 @@ void fscache_mark_pages_cached(struct fscache_retrieval > *op, > pagevec_reinit(pagevec); > } > EXPORT_SYMBOL(fscache_mark_pages_cached); > + > +/* > + * Uncache all the pages in an inode that are marked PG_fscache, assuming > them > + * to be associated with the given cookie. > + */ > +void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, > + struct inode *inode) > +{ > + struct address_space *mapping = inode->i_mapping; > + struct pagevec pvec; > + pgoff_t next; > + int i; > + > + _enter("%p,%p", cookie, inode); > + > + if (!mapping || mapping->nrpages == 0) { > + _leave(" [no pages]"); > + return; > + } > + > + pagevec_init(&pvec, 0); > + next = 0; > + while (next <= (loff_t)-1 && > + pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE) > + ) { > + for (i = 0; i < pagevec_count(&pvec); i++) { > + struct page *page = pvec.pages[i]; > + pgoff_t page_index = page->index; > + > + ASSERTCMP(page_index, >=, next); > + next = page_index + 1; > + > + if (PageFsCache(page)) { > + __fscache_wait_on_page_write(cookie, page); > + __fscache_uncache_page(cookie, page); > + } > + } > + pagevec_release(&pvec); > + cond_resched(); > + } > + > + _leave(""); > +} > +EXPORT_SYMBOL(__fscache_uncache_all_inode_pages); > diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c > index ce153a6..419119c 100644 > --- a/fs/nfs/fscache.c > +++ b/fs/nfs/fscache.c > @@ -259,12 +259,10 @@ static void nfs_fscache_disable_inode_cookie(struct > inode *inode) > dfprintk(FSCACHE, > "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode)); > > - /* Need to invalidate any mapped pages that were read in before > - * turning off the cache. > + /* Need to uncache any pages attached to this inode that > + * fscache knows about before turning off the cache. > */ > - if (inode->i_mapping && inode->i_mapping->nrpages) > - invalidate_inode_pages2(inode->i_mapping); > - > + fscache_uncache_all_inode_pages(NFS_I(inode)->fscache, inode); > nfs_fscache_zap_inode_cookie(inode); > } > } > diff --git a/include/linux/fscache.h b/include/linux/fscache.h > index 7c4d72f..9ec20de 100644 > --- a/include/linux/fscache.h > +++ b/include/linux/fscache.h > @@ -204,6 +204,8 @@ extern bool __fscache_check_page_write(struct > fscache_cookie *, struct page *); > extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct > page *); > extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct > page *, > gfp_t); > +extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *, > + struct inode *); > > /** > * fscache_register_netfs - Register a filesystem as desiring caching > services > @@ -643,4 +645,23 @@ bool fscache_maybe_release_page(struct fscache_cookie > *cookie, > return false; > } > > +/** > + * fscache_uncache_all_inode_pages - Uncache all an inode's pages > + * @cookie: The cookie representing the inode's cache object. > + * @inode: The inode to uncache pages from. > + * > + * Uncache all the pages in an inode that are marked PG_fscache, assuming > them > + * to be associated with the given cookie. > + * > + * This function may sleep. It will wait for pages that are being written > out > + * and will wait whilst the PG_fscache mark is removed by the cache. > + */ > +static inline > +void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, > + struct inode *inode) > +{ > + if (fscache_cookie_valid(cookie)) > + __fscache_uncache_all_inode_pages(cookie, inode); > +} > + > #endif /* _LINUX_FSCACHE_H */ > > _______________________________________________ > stable mailing list > stable@linux.kernel.org > http://linux.kernel.org/mailman/listinfo/stable _______________________________________________ stable mailing list stable@linux.kernel.org http://linux.kernel.org/mailman/listinfo/stable