fscache: Implement volume-level access helpers
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 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/
Link: https://lore.kernel.org/r/163906894315.143852.5454793807544710479.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/163967095028.1823006.9173132503876627466.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/164021501546.640689.9631510472149608443.stgit@warthog.procyon.org.uk/
fs/fscache/internal.h
fs/fscache/main.c
fs/fscache/volume.c
include/linux/fscache-cache.h
include/trace/events/fscache.h

index be29816..91a4ea0 100644 (file)
@@ -130,6 +130,9 @@ struct fscache_volume *fscache_get_volume(struct fscache_volume *volume,
                                          enum fscache_volume_trace where);
 void fscache_put_volume(struct fscache_volume *volume,
                        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);
 
 
index 876f4be..6cab5d9 100644 (file)
@@ -22,6 +22,7 @@ MODULE_PARM_DESC(fscache_debug,
                 "FS-Cache debugging mask");
 
 EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache);
+EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume);
 
 struct workqueue_struct *fscache_wq;
 EXPORT_SYMBOL(fscache_wq);
index 630894f..20497f0 100644 (file)
@@ -33,6 +33,90 @@ static void fscache_see_volume(struct fscache_volume *volume,
        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,
                                const struct fscache_volume *b)
 {
index c4355b8..fbbd8a2 100644 (file)
@@ -53,6 +53,10 @@ extern struct rw_semaphore fscache_addremove_sem;
 extern struct fscache_cache *fscache_acquire_cache(const char *name);
 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,
                                                 enum fscache_cookie_trace where);
 extern void fscache_put_cookie(struct fscache_cookie *cookie,
index 734966b..4f40cfa 100644 (file)
@@ -43,6 +43,7 @@ enum fscache_volume_trace {
        fscache_volume_put_relinquish,
        fscache_volume_see_create_work,
        fscache_volume_see_hash_wake,
+       fscache_volume_wait_create_work,
 };
 
 enum fscache_cookie_trace {
@@ -245,6 +246,39 @@ TRACE_EVENT(fscache_access_cache,
                      __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,
            TP_PROTO(struct fscache_cookie *cookie),