Add cache methods to lookup, create and remove a volume. Looking up or creating the volume requires the cache pinning for access; freeing the volume requires the volume pinning for access. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: linux-cachefs@xxxxxxxxxx --- fs/fscache/volume.c | 66 ++++++++++++++++++++++++++++++++++++++-- include/linux/fscache-cache.h | 6 ++++ include/trace/events/fscache.h | 11 ++++++- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/fs/fscache/volume.c b/fs/fscache/volume.c index d539d6ec2664..d1e57ce95b72 100644 --- a/fs/fscache/volume.c +++ b/fs/fscache/volume.c @@ -15,6 +15,8 @@ static struct hlist_bl_head fscache_volume_hash[1 << fscache_volume_hash_shift]; static atomic_t fscache_volume_debug_id; static LIST_HEAD(fscache_volumes); +static void fscache_create_volume_work(struct work_struct *work); + struct fscache_volume *fscache_get_volume(struct fscache_volume *volume, enum fscache_volume_trace where) { @@ -179,7 +181,7 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key, volume->cache = cache; volume->coherency = coherency_data; INIT_LIST_HEAD(&volume->proc_link); - INIT_WORK(&volume->work, NULL /* PLACEHOLDER */); + INIT_WORK(&volume->work, fscache_create_volume_work); refcount_set(&volume->ref, 1); spin_lock_init(&volume->lock); @@ -216,6 +218,58 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key, return NULL; } +/* + * Create a volume's representation on disk. Have a volume ref and a cache + * access we have to release. + */ +static void fscache_create_volume_work(struct work_struct *work) +{ + const struct fscache_cache_ops *ops; + struct fscache_volume *volume = + container_of(work, struct fscache_volume, work); + + fscache_see_volume(volume, fscache_volume_see_create_work); + + ops = volume->cache->ops; + if (ops->acquire_volume) + ops->acquire_volume(volume); + fscache_end_cache_access(volume->cache, + fscache_access_acquire_volume_end); + + clear_bit_unlock(FSCACHE_VOLUME_CREATING, &volume->flags); + wake_up_bit(&volume->flags, FSCACHE_VOLUME_CREATING); + fscache_put_volume(volume, fscache_volume_put_create_work); +} + +/* + * Dispatch a worker thread to create a volume's representation on disk. + */ +void fscache_create_volume(struct fscache_volume *volume, bool wait) +{ + if (test_and_set_bit(FSCACHE_VOLUME_CREATING, &volume->flags)) + goto maybe_wait; + if (volume->cache_priv) + goto no_wait; /* We raced */ + if (!fscache_begin_cache_access(volume->cache, + fscache_access_acquire_volume)) + goto no_wait; + + fscache_get_volume(volume, fscache_volume_get_create_work); + if (!schedule_work(&volume->work)) + fscache_put_volume(volume, fscache_volume_put_create_work); + +maybe_wait: + if (wait) { + fscache_see_volume(volume, fscache_volume_wait_create_work); + wait_on_bit(&volume->flags, FSCACHE_VOLUME_CREATING, + TASK_UNINTERRUPTIBLE); + } + return; +no_wait: + clear_bit_unlock(FSCACHE_VOLUME_CREATING, &volume->flags); + wake_up_bit(&volume->flags, FSCACHE_VOLUME_CREATING); +} + /* * Acquire a volume representation cookie and link it to a (proposed) cache. */ @@ -234,7 +288,7 @@ struct fscache_volume *__fscache_acquire_volume(const char *volume_key, return NULL; } - // PLACEHOLDER: Create the volume if we have a cache available + fscache_create_volume(volume, false); return volume; } EXPORT_SYMBOL(__fscache_acquire_volume); @@ -281,7 +335,13 @@ static void fscache_free_volume(struct fscache_volume *volume) struct fscache_cache *cache = volume->cache; if (volume->cache_priv) { - // PLACEHOLDER: Detach any attached cache + __fscache_begin_volume_access(volume, fscache_access_relinquish_volume); + if (volume->cache_priv) { + const struct fscache_cache_ops *ops = cache->ops; + if (ops->free_volume) + ops->free_volume(volume); + } + fscache_end_volume_access(volume, fscache_access_relinquish_volume_end); } down_write(&fscache_addremove_sem); diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index d2301ec88ff9..558d4bbbe486 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -53,6 +53,12 @@ struct fscache_cache { struct fscache_cache_ops { /* name of cache provider */ const char *name; + + /* Acquire a volume */ + void (*acquire_volume)(struct fscache_volume *volume); + + /* Free the cache's data attached to a volume */ + void (*free_volume)(struct fscache_volume *volume); }; static inline enum fscache_cache_state fscache_cache_state(const struct fscache_cache *cache) diff --git a/include/trace/events/fscache.h b/include/trace/events/fscache.h index c256f30d4dd4..3476cc7fdb25 100644 --- a/include/trace/events/fscache.h +++ b/include/trace/events/fscache.h @@ -63,8 +63,12 @@ enum fscache_cookie_trace { }; enum fscache_access_trace { + fscache_access_acquire_volume, + fscache_access_acquire_volume_end, fscache_access_cache_pin, fscache_access_cache_unpin, + fscache_access_relinquish_volume, + fscache_access_relinquish_volume_end, fscache_access_unlive, }; @@ -94,7 +98,8 @@ enum fscache_access_trace { EM(fscache_volume_put_hash_collision, "PUT hcoll") \ EM(fscache_volume_put_relinquish, "PUT relnq") \ EM(fscache_volume_see_create_work, "SEE creat") \ - E_(fscache_volume_see_hash_wake, "SEE hwake") + EM(fscache_volume_see_hash_wake, "SEE hwake") \ + E_(fscache_volume_wait_create_work, "WAIT crea") #define fscache_cookie_traces \ EM(fscache_cookie_collision, "*COLLIDE*") \ @@ -113,8 +118,12 @@ enum fscache_access_trace { E_(fscache_cookie_see_work, "- work ") #define fscache_access_traces \ + EM(fscache_access_acquire_volume, "BEGIN acq_vol") \ + EM(fscache_access_acquire_volume_end, "END acq_vol") \ EM(fscache_access_cache_pin, "PIN cache ") \ EM(fscache_access_cache_unpin, "UNPIN cache ") \ + EM(fscache_access_relinquish_volume, "BEGIN rlq_vol") \ + EM(fscache_access_relinquish_volume_end,"END rlq_vol") \ E_(fscache_access_unlive, "END unlive ") /*