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

Reply via email to