fscache: Provide and use cache methods to lookup/create/free a volume
authorDavid Howells <dhowells@redhat.com>
Wed, 20 Oct 2021 14:26:17 +0000 (15:26 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 7 Jan 2022 09:22:19 +0000 (09:22 +0000)
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.  The
->acquire_volume() method is used to ask the cache backend to lookup and,
if necessary, create a volume; the ->free_volume() method is used to free
the resources for a volume.

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/163819597821.215744.5225318658134989949.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/163906898645.143852.8537799955945956818.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/163967099771.1823006.1455197910571061835.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/164021507345.640689.4073511598838843040.stgit@warthog.procyon.org.uk/
fs/fscache/volume.c
include/linux/fscache-cache.h
include/trace/events/fscache.h

index 20497f0..e1a8e92 100644 (file)
@@ -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)
 {
@@ -213,7 +215,7 @@ static struct fscache_volume *fscache_alloc_volume(const char *volume_key,
 
        volume->cache = cache;
        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);
 
@@ -250,6 +252,58 @@ err_cache:
 }
 
 /*
+ * 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.
  */
 struct fscache_volume *__fscache_acquire_volume(const char *volume_key,
@@ -269,7 +323,7 @@ struct fscache_volume *__fscache_acquire_volume(const char *volume_key,
                return ERR_PTR(-EBUSY);
        }
 
-       // PLACEHOLDER: Create the volume if we have a cache available
+       fscache_create_volume(volume, false);
        return volume;
 }
 EXPORT_SYMBOL(__fscache_acquire_volume);
@@ -316,7 +370,12 @@ 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, NULL,
+                                             fscache_access_relinquish_volume);
+               if (volume->cache_priv)
+                       cache->ops->free_volume(volume);
+               fscache_end_volume_access(volume, NULL,
+                                         fscache_access_relinquish_volume_end);
        }
 
        down_write(&fscache_addremove_sem);
@@ -369,6 +428,30 @@ void __fscache_relinquish_volume(struct fscache_volume *volume,
 }
 EXPORT_SYMBOL(__fscache_relinquish_volume);
 
+/**
+ * fscache_withdraw_volume - Withdraw a volume from being cached
+ * @volume: Volume cookie
+ *
+ * Withdraw a cache volume from service, waiting for all accesses to complete
+ * before returning.
+ */
+void fscache_withdraw_volume(struct fscache_volume *volume)
+{
+       int n_accesses;
+
+       _debug("withdraw V=%x", volume->debug_id);
+
+       /* Allow wakeups on dec-to-0 */
+       n_accesses = atomic_dec_return(&volume->n_accesses);
+       trace_fscache_access_volume(volume->debug_id, 0,
+                                   refcount_read(&volume->ref),
+                                   n_accesses, fscache_access_cache_unpin);
+
+       wait_var_event(&volume->n_accesses,
+                      atomic_read(&volume->n_accesses) == 0);
+}
+EXPORT_SYMBOL(fscache_withdraw_volume);
+
 #ifdef CONFIG_PROC_FS
 /*
  * Generate a list of volumes in /proc/fs/fscache/volumes
index f78add6..a10b66c 100644 (file)
@@ -51,6 +51,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);
 };
 
 extern struct workqueue_struct *fscache_wq;
@@ -65,6 +71,7 @@ extern int fscache_add_cache(struct fscache_cache *cache,
                             const struct fscache_cache_ops *ops,
                             void *cache_priv);
 extern void fscache_withdraw_cache(struct fscache_cache *cache);
+extern void fscache_withdraw_volume(struct fscache_volume *volume);
 
 extern void fscache_end_volume_access(struct fscache_volume *volume,
                                      struct fscache_cookie *cookie,
index b1a962a..1d576bd 100644 (file)
@@ -64,8 +64,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,
 };
 
@@ -96,7 +100,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*")            \
@@ -115,8 +120,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 ")
 
 /*