aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/include/linux/fscache-cache.h
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2015-02-24 10:05:29 +0000
committerDavid Howells <dhowells@redhat.com>2015-04-02 14:28:53 +0100
commitd3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971 (patch)
treeceae1c413126e7dc02ff40836d779a0b3b28ae99 /include/linux/fscache-cache.h
parentFS-Cache: Put an aborted initialised op so that it is accounted correctly (diff)
downloadwireguard-linux-d3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971.tar.xz
wireguard-linux-d3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971.zip
FS-Cache: The operation cancellation method needs calling in more places
Any time an incomplete operation is cancelled, the operation cancellation function needs to be called to clean up. This is currently being passed directly to some of the functions that might want to call it, but not all. Instead, pass the cancellation method pointer to the fscache_operation_init() and have that cache it in the operation struct. Further, plug in a dummy cancellation handler if the caller declines to set one as this allows us to call the function unconditionally (the extra overhead isn't worth bothering about as we don't expect to be calling this typically). The cancellation method must thence be called everywhere the CANCELLED state is set. Note that we call it *before* setting the CANCELLED state such that the method can use the old state value to guide its operation. fscache_do_cancel_retrieval() needs moving higher up in the sources so that the init function can use it now. Without this, the following oops may be seen: FS-Cache: Assertion failed FS-Cache: 3 == 0 is false ------------[ cut here ]------------ kernel BUG at ../fs/fscache/page.c:261! ... RIP: 0010:[<ffffffffa0089c1b>] fscache_release_retrieval_op+0x77/0x100 [<ffffffffa008853d>] fscache_put_operation+0x114/0x2da [<ffffffffa008b8c2>] __fscache_read_or_alloc_pages+0x358/0x3b3 [<ffffffffa00b761f>] __nfs_readpages_from_fscache+0x59/0xbf [nfs] [<ffffffffa00b06c5>] nfs_readpages+0x10c/0x185 [nfs] [<ffffffff81124925>] ? alloc_pages_current+0x119/0x13e [<ffffffff810ee5fd>] ? __page_cache_alloc+0xfb/0x10a [<ffffffff810f87f8>] __do_page_cache_readahead+0x188/0x22c [<ffffffff810f8b3a>] ondemand_readahead+0x29e/0x2af [<ffffffff810f8c92>] page_cache_sync_readahead+0x38/0x3a [<ffffffff810ef337>] generic_file_read_iter+0x1a2/0x55a [<ffffffffa00a9dff>] ? nfs_revalidate_mapping+0xd6/0x288 [nfs] [<ffffffffa00a6a23>] nfs_file_read+0x49/0x70 [nfs] [<ffffffff811363be>] new_sync_read+0x78/0x9c [<ffffffff81137164>] __vfs_read+0x13/0x38 [<ffffffff8113721e>] vfs_read+0x95/0x121 [<ffffffff811372f6>] SyS_read+0x4c/0x8a [<ffffffff81557a52>] system_call_fastpath+0x12/0x17 The assertion is showing that the remaining number of pages (n_pages) is not 0 when the operation is being released. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Steve Dickson <steved@redhat.com> Acked-by: Jeff Layton <jeff.layton@primarydata.com>
Diffstat (limited to 'include/linux/fscache-cache.h')
-rw-r--r--include/linux/fscache-cache.h5
1 files changed, 5 insertions, 0 deletions
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index 0e26d49972e3..69c6eb10d858 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -74,6 +74,7 @@ extern wait_queue_head_t fscache_cache_cleared_wq;
*/
typedef void (*fscache_operation_release_t)(struct fscache_operation *op);
typedef void (*fscache_operation_processor_t)(struct fscache_operation *op);
+typedef void (*fscache_operation_cancel_t)(struct fscache_operation *op);
enum fscache_operation_state {
FSCACHE_OP_ST_BLANK, /* Op is not yet submitted */
@@ -109,6 +110,9 @@ struct fscache_operation {
* the op in a non-pool thread */
fscache_operation_processor_t processor;
+ /* Operation cancellation cleanup (optional) */
+ fscache_operation_cancel_t cancel;
+
/* operation releaser */
fscache_operation_release_t release;
};
@@ -121,6 +125,7 @@ extern void fscache_op_complete(struct fscache_operation *, bool);
extern void fscache_put_operation(struct fscache_operation *);
extern void fscache_operation_init(struct fscache_operation *,
fscache_operation_processor_t,
+ fscache_operation_cancel_t,
fscache_operation_release_t);
/*