From 7c604e5d6e565f34d0156608be6e63fed5fad5c9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 3 Oct 2013 18:54:23 +0100 Subject: [PATCH] FS-Cache: Fix handling of an attempt to store a page that is now beyond EOF Fix the handling of an attempt to store a page that is now beyond EOF. This may happen, for example, if the page got pushed for storage before the netfs file got truncated on the server. In such a case, we should just remove the excessive pages from the cookie->stores radix tree and wake up the waiter. This can be seen in /proc/fs/fscache/stats on this line: Stores : ops=350 run=1895 pgs=1545 rxd=1727 olm=9 where olm=N has N > 0. Reported-by: Milosz Tanski Signed-off-by: David Howells Acked-by: Milosz Tanski --- fs/fscache/page.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 7f5c658af755..b4730cf52aec 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -755,6 +755,7 @@ static void fscache_write_op(struct fscache_operation *_op) struct fscache_object *object = op->op.object; struct fscache_cookie *cookie; struct page *page; + pgoff_t index; unsigned n; void *results[1]; int ret; @@ -803,7 +804,7 @@ static void fscache_write_op(struct fscache_operation *_op) _debug("gang %d [%lx]", n, page->index); if (page->index > op->store_limit) { fscache_stat(&fscache_n_store_pages_over_limit); - goto superseded; + goto page_beyond_limit; } radix_tree_tag_set(&cookie->stores, page->index, @@ -829,6 +830,40 @@ static void fscache_write_op(struct fscache_operation *_op) _leave(""); return; +page_beyond_limit: + spin_unlock(&object->lock); + +page_beyond_limit_unlocked: + /* pages that are now beyond the end of the storage object must have + * their pending storage records cleared. + */ + index = page->index; + radix_tree_tag_clear(&cookie->stores, page->index, + FSCACHE_COOKIE_PENDING_TAG); + if (!radix_tree_tag_get(&cookie->stores, page->index, + FSCACHE_COOKIE_STORING_TAG)) { + fscache_stat(&fscache_n_store_radix_deletes); + radix_tree_delete(&cookie->stores, page->index); + page_cache_release(page); + } + if (!need_resched()) { + n = radix_tree_gang_lookup_tag(&cookie->stores, results, + index + 1, 1, + FSCACHE_COOKIE_PENDING_TAG); + if (n == 1) { + page = results[0]; + goto page_beyond_limit_unlocked; + } + spin_unlock(&cookie->stores_lock); + wake_up_bit(&cookie->flags, 0); + } else { + spin_unlock(&cookie->stores_lock); + } + + fscache_enqueue_operation(&op->op); + _leave(""); + return; + superseded: /* this writer is going away and there aren't any more things to * write */ -- 2.39.5