Commit 2c984257 authored by David Howells's avatar David Howells

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: default avatarDavid Howells <dhowells@redhat.com>
parent d0fb31ec
...@@ -778,6 +778,7 @@ static void fscache_write_op(struct fscache_operation *_op) ...@@ -778,6 +778,7 @@ static void fscache_write_op(struct fscache_operation *_op)
_enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage)); _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
again:
spin_lock(&object->lock); spin_lock(&object->lock);
cookie = object->cookie; cookie = object->cookie;
...@@ -819,10 +820,6 @@ static void fscache_write_op(struct fscache_operation *_op) ...@@ -819,10 +820,6 @@ static void fscache_write_op(struct fscache_operation *_op)
goto superseded; goto superseded;
page = results[0]; page = results[0];
_debug("gang %d [%lx]", n, page->index); _debug("gang %d [%lx]", n, page->index);
if (page->index >= op->store_limit) {
fscache_stat(&fscache_n_store_pages_over_limit);
goto superseded;
}
radix_tree_tag_set(&cookie->stores, page->index, radix_tree_tag_set(&cookie->stores, page->index,
FSCACHE_COOKIE_STORING_TAG); FSCACHE_COOKIE_STORING_TAG);
...@@ -832,6 +829,9 @@ static void fscache_write_op(struct fscache_operation *_op) ...@@ -832,6 +829,9 @@ static void fscache_write_op(struct fscache_operation *_op)
spin_unlock(&cookie->stores_lock); spin_unlock(&cookie->stores_lock);
spin_unlock(&object->lock); spin_unlock(&object->lock);
if (page->index >= op->store_limit)
goto discard_page;
fscache_stat(&fscache_n_store_pages); fscache_stat(&fscache_n_store_pages);
fscache_stat(&fscache_n_cop_write_page); fscache_stat(&fscache_n_cop_write_page);
ret = object->cache->ops->write_page(op, page); ret = object->cache->ops->write_page(op, page);
...@@ -847,6 +847,11 @@ static void fscache_write_op(struct fscache_operation *_op) ...@@ -847,6 +847,11 @@ static void fscache_write_op(struct fscache_operation *_op)
_leave(""); _leave("");
return; return;
discard_page:
fscache_stat(&fscache_n_store_pages_over_limit);
fscache_end_page_write(object, page);
goto again;
superseded: superseded:
/* this writer is going away and there aren't any more things to /* this writer is going away and there aren't any more things to
* write */ * write */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment