forked from Minki/linux
fscache: Implement volume-level access helpers
Add a pair of helper functions to manage access to a volume, pinning the volume in place for the duration to prevent cache withdrawal from removing it: bool fscache_begin_volume_access(struct fscache_volume *volume, enum fscache_access_trace why); void fscache_end_volume_access(struct fscache_volume *volume, enum fscache_access_trace why); The way the access gate on the volume works/will work is: (1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE), then we return false to indicate access was not permitted. (2) If the cache tests as live, then we increment the volume's n_accesses count and then recheck the cache liveness, ending the access if it ceased to be live. (3) When we end the access, we decrement the volume's n_accesses and wake up the any waiters if it reaches 0. (4) Whilst the cache is caching, the volume's n_accesses is kept artificially incremented to prevent wakeups from happening. (5) When the cache is taken offline, the state is changed to prevent new accesses, the volume's n_accesses is decremented and we wait for it to become 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/163819594158.215744.8285859817391683254.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/163906894315.143852.5454793807544710479.stgit@warthog.procyon.org.uk/ # v2 Link: https://lore.kernel.org/r/163967095028.1823006.9173132503876627466.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/164021501546.640689.9631510472149608443.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
parent
23e12e285a
commit
e6acd3299b
@ -130,6 +130,9 @@ struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
|
|||||||
enum fscache_volume_trace where);
|
enum fscache_volume_trace where);
|
||||||
void fscache_put_volume(struct fscache_volume *volume,
|
void fscache_put_volume(struct fscache_volume *volume,
|
||||||
enum fscache_volume_trace where);
|
enum fscache_volume_trace where);
|
||||||
|
bool fscache_begin_volume_access(struct fscache_volume *volume,
|
||||||
|
struct fscache_cookie *cookie,
|
||||||
|
enum fscache_access_trace why);
|
||||||
void fscache_create_volume(struct fscache_volume *volume, bool wait);
|
void fscache_create_volume(struct fscache_volume *volume, bool wait);
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ MODULE_PARM_DESC(fscache_debug,
|
|||||||
"FS-Cache debugging mask");
|
"FS-Cache debugging mask");
|
||||||
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache);
|
EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache);
|
||||||
|
EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume);
|
||||||
|
|
||||||
struct workqueue_struct *fscache_wq;
|
struct workqueue_struct *fscache_wq;
|
||||||
EXPORT_SYMBOL(fscache_wq);
|
EXPORT_SYMBOL(fscache_wq);
|
||||||
|
@ -33,6 +33,90 @@ static void fscache_see_volume(struct fscache_volume *volume,
|
|||||||
trace_fscache_volume(volume->debug_id, ref, where);
|
trace_fscache_volume(volume->debug_id, ref, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pin the cache behind a volume so that we can access it.
|
||||||
|
*/
|
||||||
|
static void __fscache_begin_volume_access(struct fscache_volume *volume,
|
||||||
|
struct fscache_cookie *cookie,
|
||||||
|
enum fscache_access_trace why)
|
||||||
|
{
|
||||||
|
int n_accesses;
|
||||||
|
|
||||||
|
n_accesses = atomic_inc_return(&volume->n_accesses);
|
||||||
|
smp_mb__after_atomic();
|
||||||
|
trace_fscache_access_volume(volume->debug_id, cookie ? cookie->debug_id : 0,
|
||||||
|
refcount_read(&volume->ref),
|
||||||
|
n_accesses, why);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fscache_begin_volume_access - Pin a cache so a volume can be accessed
|
||||||
|
* @volume: The volume cookie
|
||||||
|
* @cookie: A datafile cookie for a tracing reference (or NULL)
|
||||||
|
* @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 a volume and returns true if successful. This works as follows:
|
||||||
|
*
|
||||||
|
* (1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE),
|
||||||
|
* then we return false to indicate access was not permitted.
|
||||||
|
*
|
||||||
|
* (2) If the cache tests as live, then we increment the volume's n_accesses
|
||||||
|
* count and then recheck the cache liveness, ending the access if it
|
||||||
|
* ceased to be live.
|
||||||
|
*
|
||||||
|
* (3) When we end the access, we decrement the volume's n_accesses and wake
|
||||||
|
* up the any waiters if it reaches 0.
|
||||||
|
*
|
||||||
|
* (4) Whilst the cache is caching, the volume's n_accesses is kept
|
||||||
|
* artificially incremented to prevent wakeups from happening.
|
||||||
|
*
|
||||||
|
* (5) When the cache is taken offline, the state is changed to prevent new
|
||||||
|
* accesses, the volume's n_accesses is decremented and we wait for it to
|
||||||
|
* become 0.
|
||||||
|
*
|
||||||
|
* The datafile @cookie and the @why indicator are merely provided for tracing
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
bool fscache_begin_volume_access(struct fscache_volume *volume,
|
||||||
|
struct fscache_cookie *cookie,
|
||||||
|
enum fscache_access_trace why)
|
||||||
|
{
|
||||||
|
if (!fscache_cache_is_live(volume->cache))
|
||||||
|
return false;
|
||||||
|
__fscache_begin_volume_access(volume, cookie, why);
|
||||||
|
if (!fscache_cache_is_live(volume->cache)) {
|
||||||
|
fscache_end_volume_access(volume, cookie, fscache_access_unlive);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fscache_end_volume_access - Unpin a cache at the end of an access.
|
||||||
|
* @volume: The volume cookie
|
||||||
|
* @cookie: A datafile cookie for a tracing reference (or NULL)
|
||||||
|
* @why: An indication of the circumstances of the access for tracing
|
||||||
|
*
|
||||||
|
* Unpin a cache volume after we've accessed it. The datafile @cookie and the
|
||||||
|
* @why indicator are merely provided for tracing purposes.
|
||||||
|
*/
|
||||||
|
void fscache_end_volume_access(struct fscache_volume *volume,
|
||||||
|
struct fscache_cookie *cookie,
|
||||||
|
enum fscache_access_trace why)
|
||||||
|
{
|
||||||
|
int n_accesses;
|
||||||
|
|
||||||
|
smp_mb__before_atomic();
|
||||||
|
n_accesses = atomic_dec_return(&volume->n_accesses);
|
||||||
|
trace_fscache_access_volume(volume->debug_id, cookie ? cookie->debug_id : 0,
|
||||||
|
refcount_read(&volume->ref),
|
||||||
|
n_accesses, why);
|
||||||
|
if (n_accesses == 0)
|
||||||
|
wake_up_var(&volume->n_accesses);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(fscache_end_volume_access);
|
||||||
|
|
||||||
static bool fscache_volume_same(const struct fscache_volume *a,
|
static bool fscache_volume_same(const struct fscache_volume *a,
|
||||||
const struct fscache_volume *b)
|
const struct fscache_volume *b)
|
||||||
{
|
{
|
||||||
|
@ -53,6 +53,10 @@ extern struct rw_semaphore fscache_addremove_sem;
|
|||||||
extern struct fscache_cache *fscache_acquire_cache(const char *name);
|
extern struct fscache_cache *fscache_acquire_cache(const char *name);
|
||||||
extern void fscache_relinquish_cache(struct fscache_cache *cache);
|
extern void fscache_relinquish_cache(struct fscache_cache *cache);
|
||||||
|
|
||||||
|
extern void fscache_end_volume_access(struct fscache_volume *volume,
|
||||||
|
struct fscache_cookie *cookie,
|
||||||
|
enum fscache_access_trace why);
|
||||||
|
|
||||||
extern struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
|
extern struct fscache_cookie *fscache_get_cookie(struct fscache_cookie *cookie,
|
||||||
enum fscache_cookie_trace where);
|
enum fscache_cookie_trace where);
|
||||||
extern void fscache_put_cookie(struct fscache_cookie *cookie,
|
extern void fscache_put_cookie(struct fscache_cookie *cookie,
|
||||||
|
@ -43,6 +43,7 @@ enum fscache_volume_trace {
|
|||||||
fscache_volume_put_relinquish,
|
fscache_volume_put_relinquish,
|
||||||
fscache_volume_see_create_work,
|
fscache_volume_see_create_work,
|
||||||
fscache_volume_see_hash_wake,
|
fscache_volume_see_hash_wake,
|
||||||
|
fscache_volume_wait_create_work,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fscache_cookie_trace {
|
enum fscache_cookie_trace {
|
||||||
@ -245,6 +246,39 @@ TRACE_EVENT(fscache_access_cache,
|
|||||||
__entry->n_accesses)
|
__entry->n_accesses)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(fscache_access_volume,
|
||||||
|
TP_PROTO(unsigned int volume_debug_id,
|
||||||
|
unsigned int cookie_debug_id,
|
||||||
|
int ref,
|
||||||
|
int n_accesses,
|
||||||
|
enum fscache_access_trace why),
|
||||||
|
|
||||||
|
TP_ARGS(volume_debug_id, cookie_debug_id, ref, n_accesses, why),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(unsigned int, volume )
|
||||||
|
__field(unsigned int, cookie )
|
||||||
|
__field(int, ref )
|
||||||
|
__field(int, n_accesses )
|
||||||
|
__field(enum fscache_access_trace, why )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->volume = volume_debug_id;
|
||||||
|
__entry->cookie = cookie_debug_id;
|
||||||
|
__entry->ref = ref;
|
||||||
|
__entry->n_accesses = n_accesses;
|
||||||
|
__entry->why = why;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("V=%08x c=%08x %s r=%d a=%d",
|
||||||
|
__entry->volume,
|
||||||
|
__entry->cookie,
|
||||||
|
__print_symbolic(__entry->why, fscache_access_traces),
|
||||||
|
__entry->ref,
|
||||||
|
__entry->n_accesses)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(fscache_acquire,
|
TRACE_EVENT(fscache_acquire,
|
||||||
TP_PROTO(struct fscache_cookie *cookie),
|
TP_PROTO(struct fscache_cookie *cookie),
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user