From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Howells Subject: [PATCH 3/7] FS-Cache: Release page->private after failed readahead [try #13] Date: Wed, 30 Aug 2006 20:32:00 +0100 Message-ID: <20060830193200.12446.89054.stgit@warthog.cambridge.redhat.com> References: <20060830193153.12446.24095.stgit@warthog.cambridge.redhat.com> Content-Type: text/plain; charset=utf-8; format=fixed Content-Transfer-Encoding: quoted-printable Cc: linux-fsdevel@vger.kernel.org, linux-cachefs@redhat.com, nfsv4@linux-nfs.org, linux-kernel@vger.kernel.org Return-path: To: torvalds@osdl.org, akpm@osdl.org, steved@redhat.com, trond.myklebust@fys.uio.no In-Reply-To: <20060830193153.12446.24095.stgit@warthog.cambridge.redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: nfsv4-bounces@linux-nfs.org Errors-To: nfsv4-bounces@linux-nfs.org List-Id: linux-fsdevel.vger.kernel.org The attached patch causes read_cache_pages() to release page-private data= on a page for which add_to_page_cache() fails or the filler function fails. Th= is permits pages with caching references associated with them to be cleaned = up. The invalidatepage() address space op is called (indirectly) to do the ho= nours. Signed-Off-By: David Howells --- mm/readahead.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 38 insertions(+), 8 deletions(-) diff --git a/mm/readahead.c b/mm/readahead.c index aa7ec42..b0788ae 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -14,6 +14,7 @@ #include #include #include #include +#include =20 void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *pag= e) { @@ -117,6 +118,41 @@ static inline unsigned long get_next_ra_ =20 #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) =20 +/* + * see if a page needs releasing upon read_cache_pages() failure + * - the caller of read_cache_pages() may have set PG_private before cal= ling, + * such as the NFS fs marking pages that are cached locally on disk, t= hus we + * need to give the fs a chance to clean up in the event of an error + */ +static void read_cache_pages_invalidate_page(struct address_space *mappi= ng, + struct page *page) +{ + if (PagePrivate(page)) { + if (TestSetPageLocked(page)) + BUG(); + page->mapping =3D mapping; + do_invalidatepage(page, 0); + page->mapping =3D NULL; + unlock_page(page); + } + page_cache_release(page); +} + +/* + * release a list of pages, invalidating them first if need be + */ +static void read_cache_pages_invalidate_pages(struct address_space *mapp= ing, + struct list_head *pages) +{ + struct page *victim; + + while (!list_empty(pages)) { + victim =3D list_to_page(pages); + list_del(&victim->lru); + read_cache_pages_invalidate_page(mapping, victim); + } +} + /** * read_cache_pages - populate an address space with some pages & start = reads against them * @mapping: the address_space @@ -140,20 +176,14 @@ int read_cache_pages(struct address_spac page =3D list_to_page(pages); list_del(&page->lru); if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { - page_cache_release(page); + read_cache_pages_invalidate_page(mapping, page); continue; } ret =3D filler(data, page); if (!pagevec_add(&lru_pvec, page)) __pagevec_lru_add(&lru_pvec); if (ret) { - while (!list_empty(pages)) { - struct page *victim; - - victim =3D list_to_page(pages); - list_del(&victim->lru); - page_cache_release(victim); - } + read_cache_pages_invalidate_pages(mapping, pages); break; } }