Add a pair of helper functions to manage access to a cookie, pinning the cache object in place for the duration to prevent cache withdrawal from removing it: bool fscache_begin_cookie_access(struct fscache_cookie *cookie, enum fscache_access_trace why); void fscache_end_cookie_access(struct fscache_cookie *cookie, enum fscache_access_trace why); The first is intended for internal use only, but the second will be used by the cache backend also. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: linux-cachefs@xxxxxxxxxx --- fs/fscache/cookie.c | 60 ++++++++++++++++++++++++++++++++++++++++ fs/fscache/internal.h | 3 ++ fs/fscache/main.c | 1 + include/linux/fscache-cache.h | 2 + include/trace/events/fscache.h | 29 +++++++++++++++++++ 5 files changed, 95 insertions(+) diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 87ee8b666765..9b6ddbc01825 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -57,6 +57,66 @@ static void fscache_free_cookie(struct fscache_cookie *cookie) kmem_cache_free(fscache_cookie_jar, cookie); } +static void __fscache_end_cookie_access(struct fscache_cookie *cookie) +{ + if (test_bit(FSCACHE_COOKIE_DO_RELINQUISH, &cookie->flags)) + fscache_set_cookie_stage(cookie, FSCACHE_COOKIE_STAGE_RELINQUISHING); + else if (test_bit(FSCACHE_COOKIE_DO_WITHDRAW, &cookie->flags)) + fscache_set_cookie_stage(cookie, FSCACHE_COOKIE_STAGE_WITHDRAWING); + // PLACEHOLDER: Schedule cookie cleanup +} + +/* + * Mark the end of an access on a cookie. This brings a deferred + * relinquishment or withdrawal stage into effect. + */ +void fscache_end_cookie_access(struct fscache_cookie *cookie, + enum fscache_access_trace why) +{ + int n_accesses; + + smp_mb__before_atomic(); + n_accesses = atomic_dec_return(&cookie->n_accesses); + trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref), + n_accesses, why); + if (n_accesses == 0) + __fscache_end_cookie_access(cookie); +} +EXPORT_SYMBOL(fscache_end_cookie_access); + +/* + * Pin the cache behind a cookie so that we can access it. + */ +static void __fscache_begin_cookie_access(struct fscache_cookie *cookie, + enum fscache_access_trace why) +{ + int n_accesses; + + n_accesses = atomic_inc_return(&cookie->n_accesses); + smp_mb__after_atomic(); /* (Future) read stage after is-caching. + * Reread n_accesses after is-caching + */ + trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref), + n_accesses, why); +} + +/* + * Pin the cache behind a cookie so that we can access it. + */ +bool fscache_begin_cookie_access(struct fscache_cookie *cookie, + enum fscache_access_trace why) +{ + if (!test_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags)) + return false; + __fscache_begin_cookie_access(cookie, why); + if (!test_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags) || + !fscache_cache_is_live(cookie->volume->cache)) { + fscache_end_cookie_access(cookie, fscache_access_unlive); + return false; + } + return true; +} + static inline void wake_up_cookie_stage(struct fscache_cookie *cookie) { /* Use a barrier to ensure that waiters see the stage variable diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 18f9a408a4f4..5669ba4bc8a9 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -34,6 +34,9 @@ extern struct kmem_cache *fscache_cookie_jar; extern const struct seq_operations fscache_cookies_seq_ops; extern void fscache_print_cookie(struct fscache_cookie *cookie, char prefix); +extern bool fscache_begin_cookie_access(struct fscache_cookie *cookie, + enum fscache_access_trace why); + static inline void fscache_see_cookie(struct fscache_cookie *cookie, enum fscache_cookie_trace where) { diff --git a/fs/fscache/main.c b/fs/fscache/main.c index 6a024c45eb0b..01d57433702c 100644 --- a/fs/fscache/main.c +++ b/fs/fscache/main.c @@ -23,6 +23,7 @@ MODULE_PARM_DESC(fscache_debug, EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache); EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume); +EXPORT_TRACEPOINT_SYMBOL(fscache_access); struct workqueue_struct *fscache_wq; EXPORT_SYMBOL(fscache_wq); diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 7db4dda74951..a10f87421438 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -84,6 +84,8 @@ extern struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie, enum fscache_cookie_trace where); extern void fscache_put_cookie(struct fscache_cookie *cookie, enum fscache_cookie_trace where); +extern void fscache_end_cookie_access(struct fscache_cookie *cookie, + enum fscache_access_trace why); extern void fscache_set_cookie_stage(struct fscache_cookie *cookie, enum fscache_cookie_stage stage); diff --git a/include/trace/events/fscache.h b/include/trace/events/fscache.h index 4b35fe9cd906..132381921be9 100644 --- a/include/trace/events/fscache.h +++ b/include/trace/events/fscache.h @@ -269,6 +269,35 @@ TRACE_EVENT(fscache_access_volume, __entry->n_accesses) ); +TRACE_EVENT(fscache_access, + TP_PROTO(unsigned int cookie_debug_id, + int ref, + int n_accesses, + enum fscache_access_trace why), + + TP_ARGS(cookie_debug_id, ref, n_accesses, why), + + TP_STRUCT__entry( + __field(unsigned int, cookie ) + __field(int, ref ) + __field(int, n_accesses ) + __field(enum fscache_access_trace, why ) + ), + + TP_fast_assign( + __entry->cookie = cookie_debug_id; + __entry->ref = ref; + __entry->n_accesses = n_accesses; + __entry->why = why; + ), + + TP_printk("c=%08x %s r=%d a=%d", + __entry->cookie, + __print_symbolic(__entry->why, fscache_access_traces), + __entry->ref, + __entry->n_accesses) + ); + TRACE_EVENT(fscache_acquire, TP_PROTO(struct fscache_cookie *cookie),