Skip to content

Commit

Permalink
fscache: Fix hanging wait on page discarded by writeback
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dhowells committed Apr 4, 2018
1 parent d0fb31e commit 2c98425
Showing 1 changed file with 9 additions and 4 deletions.
13 changes: 9 additions & 4 deletions fs/fscache/page.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

again:
spin_lock(&object->lock);
cookie = object->cookie;

Expand Down Expand Up @@ -819,10 +820,6 @@ static void fscache_write_op(struct fscache_operation *_op)
goto superseded;
page = results[0];
_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,
FSCACHE_COOKIE_STORING_TAG);
Expand All @@ -832,6 +829,9 @@ static void fscache_write_op(struct fscache_operation *_op)
spin_unlock(&cookie->stores_lock);
spin_unlock(&object->lock);

if (page->index >= op->store_limit)
goto discard_page;

fscache_stat(&fscache_n_store_pages);
fscache_stat(&fscache_n_cop_write_page);
ret = object->cache->ops->write_page(op, page);
Expand All @@ -847,6 +847,11 @@ static void fscache_write_op(struct fscache_operation *_op)
_leave("");
return;

discard_page:
fscache_stat(&fscache_n_store_pages_over_limit);
fscache_end_page_write(object, page);
goto again;

superseded:
/* this writer is going away and there aren't any more things to
* write */
Expand Down

0 comments on commit 2c98425

Please sign in to comment.