aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-04-04 08:41:26 -0400
committerDavid Howells <dhowells@redhat.com>2018-04-04 08:41:26 -0400
commit2c98425720233ae3e135add0c7e869b32913502f (patch)
tree100789f2ccb035a3ec3bbfc76d6a63eaeedf18d8
parentd0fb31ecda2c3c6092d0c2a46a6a72653e7dcabb (diff)
fscache: Fix hanging wait on page discarded by writeback
If the fscache asynchronous write operation elects to discard a page that's pending storage to the cache because the page would be over the store limit then it needs to wake the page as someone may be waiting on completion of the write. The problem is that the store limit may be updated by a different asynchronous operation - and so may miss the write - and that the store limit may not even get updated until later by the netfs. Fix the kernel hang by making fscache_write_op() mark as written any pages that are over the limit. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--fs/fscache/page.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index adc39c0c62df..b9f18bf4227d 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -778,6 +778,7 @@ static void fscache_write_op(struct fscache_operation *_op)
778 778
779 _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); 779 _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
780 780
781again:
781 spin_lock(&object->lock); 782 spin_lock(&object->lock);
782 cookie = object->cookie; 783 cookie = object->cookie;
783 784
@@ -819,10 +820,6 @@ static void fscache_write_op(struct fscache_operation *_op)
819 goto superseded; 820 goto superseded;
820 page = results[0]; 821 page = results[0];
821 _debug("gang %d [%lx]", n, page->index); 822 _debug("gang %d [%lx]", n, page->index);
822 if (page->index >= op->store_limit) {
823 fscache_stat(&fscache_n_store_pages_over_limit);
824 goto superseded;
825 }
826 823
827 radix_tree_tag_set(&cookie->stores, page->index, 824 radix_tree_tag_set(&cookie->stores, page->index,
828 FSCACHE_COOKIE_STORING_TAG); 825 FSCACHE_COOKIE_STORING_TAG);
@@ -832,6 +829,9 @@ static void fscache_write_op(struct fscache_operation *_op)
832 spin_unlock(&cookie->stores_lock); 829 spin_unlock(&cookie->stores_lock);
833 spin_unlock(&object->lock); 830 spin_unlock(&object->lock);
834 831
832 if (page->index >= op->store_limit)
833 goto discard_page;
834
835 fscache_stat(&fscache_n_store_pages); 835 fscache_stat(&fscache_n_store_pages);
836 fscache_stat(&fscache_n_cop_write_page); 836 fscache_stat(&fscache_n_cop_write_page);
837 ret = object->cache->ops->write_page(op, page); 837 ret = object->cache->ops->write_page(op, page);
@@ -847,6 +847,11 @@ static void fscache_write_op(struct fscache_operation *_op)
847 _leave(""); 847 _leave("");
848 return; 848 return;
849 849
850discard_page:
851 fscache_stat(&fscache_n_store_pages_over_limit);
852 fscache_end_page_write(object, page);
853 goto again;
854
850superseded: 855superseded:
851 /* this writer is going away and there aren't any more things to 856 /* this writer is going away and there aren't any more things to
852 * write */ 857 * write */