forked from Minki/linux
fscache: Implement cookie-level access helpers
Add a number 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: (1) void fscache_init_access_gate(struct fscache_cookie *cookie); This function initialises the access count when a cache binds to a cookie. An extra ref is taken on the access count to prevent wakeups while the cache is active. We're only interested in the wakeup when a cookie is being withdrawn and we're waiting for it to quiesce - at which point the counter will be decremented before the wait. The FSCACHE_COOKIE_NACC_ELEVATED flag is set on the cookie to keep track of the extra ref in order to handle a race between relinquishment and withdrawal both trying to drop the extra ref. (2) bool fscache_begin_cookie_access(struct fscache_cookie *cookie, enum fscache_access_trace why); This function attempts to begin access upon a cookie, pinning it in place if it's cached. If successful, it returns true and leaves a the access count incremented. (3) void fscache_end_cookie_access(struct fscache_cookie *cookie, enum fscache_access_trace why); This function drops the access count obtained by (2), permitting object withdrawal to take place when it reaches zero. A tracepoint is provided to track changes to the access counter on a cookie. Changes ======= ver #2: - Don't hold n_accesses elevated whilst cache is bound to a cookie, but rather add a flag that prevents the state machine from being queued when n_accesses reaches 0. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> cc: linux-cachefs@redhat.com Link: https://lore.kernel.org/r/163819595085.215744.1706073049250505427.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906895313.143852.10141619544149102193.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967095980.1823006.1133648159424418877.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021503063.640689.8870918985269528670.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
parent
e6acd3299b
commit
a7733fb632
@ -62,6 +62,104 @@ static void fscache_free_cookie(struct fscache_cookie *cookie)
|
||||
kmem_cache_free(fscache_cookie_jar, cookie);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the access gate on a cookie by setting a flag to prevent the
|
||||
* state machine from being queued when the access counter transitions to 0.
|
||||
* We're only interested in this when we withdraw caching services from the
|
||||
* cookie.
|
||||
*/
|
||||
static void fscache_init_access_gate(struct fscache_cookie *cookie)
|
||||
{
|
||||
int n_accesses;
|
||||
|
||||
n_accesses = atomic_read(&cookie->n_accesses);
|
||||
trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref),
|
||||
n_accesses, fscache_access_cache_pin);
|
||||
set_bit(FSCACHE_COOKIE_NO_ACCESS_WAKE, &cookie->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* fscache_end_cookie_access - Unpin a cache at the end of an access.
|
||||
* @cookie: A data file cookie
|
||||
* @why: An indication of the circumstances of the access for tracing
|
||||
*
|
||||
* Unpin a cache cookie after we've accessed it and bring a deferred
|
||||
* relinquishment or withdrawal state into effect.
|
||||
*
|
||||
* The @why indicator is provided for tracing purposes.
|
||||
*/
|
||||
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 &&
|
||||
!test_bit(FSCACHE_COOKIE_NO_ACCESS_WAKE, &cookie->flags)) {
|
||||
// PLACEHOLDER: Need to poke the state machine
|
||||
}
|
||||
}
|
||||
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 state after is-caching.
|
||||
* Reread n_accesses after is-caching
|
||||
*/
|
||||
trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref),
|
||||
n_accesses, why);
|
||||
}
|
||||
|
||||
/**
|
||||
* fscache_begin_cookie_access - Pin a cache so data can be accessed
|
||||
* @cookie: A data file cookie
|
||||
* @why: An indication of the circumstances of the access for tracing
|
||||
*
|
||||
* Attempt to pin the cache to prevent it from going away whilst we're
|
||||
* accessing data and returns true if successful. This works as follows:
|
||||
*
|
||||
* (1) If the cookie is not being cached (ie. FSCACHE_COOKIE_IS_CACHING is not
|
||||
* set), we return false to indicate access was not permitted.
|
||||
*
|
||||
* (2) If the cookie is being cached, we increment its n_accesses count and
|
||||
* then recheck the IS_CACHING flag, ending the access if it got cleared.
|
||||
*
|
||||
* (3) When we end the access, we decrement the cookie's n_accesses and wake
|
||||
* up the any waiters if it reaches 0.
|
||||
*
|
||||
* (4) Whilst the cookie is actively being cached, its n_accesses is kept
|
||||
* artificially incremented to prevent wakeups from happening.
|
||||
*
|
||||
* (5) When the cache is taken offline or if the cookie is culled, the flag is
|
||||
* cleared to prevent new accesses, the cookie's n_accesses is decremented
|
||||
* and we wait for it to become 0.
|
||||
*
|
||||
* The @why indicator are merely provided for tracing purposes.
|
||||
*/
|
||||
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_state(struct fscache_cookie *cookie)
|
||||
{
|
||||
/* Use a barrier to ensure that waiters see the state variable
|
||||
|
@ -59,6 +59,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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -61,6 +61,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_state(struct fscache_cookie *cookie,
|
||||
enum fscache_cookie_state state);
|
||||
|
||||
|
@ -279,6 +279,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),
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user