Add a pair 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:

        bool fscache_begin_cookie_access(struct fscache_cookie *cookie,
                                         enum fscache_access_trace why);
        void fscache_end_cookie_access(struct fscache_cookie *cookie,
                                       enum fscache_access_trace why);

The first is intended for internal use only, but the second will be used by
the cache backend also.

Signed-off-by: David Howells <dhowe...@redhat.com>
cc: linux-cachefs@redhat.com
---

 fs/fscache/cookie.c            |   60 ++++++++++++++++++++++++++++++++++++++++
 fs/fscache/internal.h          |    3 ++
 fs/fscache/main.c              |    1 +
 include/linux/fscache-cache.h  |    2 +
 include/trace/events/fscache.h |   29 +++++++++++++++++++
 5 files changed, 95 insertions(+)

diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index 87ee8b666765..9b6ddbc01825 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -57,6 +57,66 @@ static void fscache_free_cookie(struct fscache_cookie 
*cookie)
        kmem_cache_free(fscache_cookie_jar, cookie);
 }
 
+static void __fscache_end_cookie_access(struct fscache_cookie *cookie)
+{
+       if (test_bit(FSCACHE_COOKIE_DO_RELINQUISH, &cookie->flags))
+               fscache_set_cookie_stage(cookie, 
FSCACHE_COOKIE_STAGE_RELINQUISHING);
+       else if (test_bit(FSCACHE_COOKIE_DO_WITHDRAW, &cookie->flags))
+               fscache_set_cookie_stage(cookie, 
FSCACHE_COOKIE_STAGE_WITHDRAWING);
+       // PLACEHOLDER: Schedule cookie cleanup
+}
+
+/*
+ * Mark the end of an access on a cookie.  This brings a deferred
+ * relinquishment or withdrawal stage into effect.
+ */
+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)
+               __fscache_end_cookie_access(cookie);
+}
+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 stage after is-caching.
+                                * Reread n_accesses after is-caching
+                                */
+       trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref),
+                            n_accesses, why);
+}
+
+/*
+ * Pin the cache behind a cookie so that we can access it.
+ */
+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_stage(struct fscache_cookie *cookie)
 {
        /* Use a barrier to ensure that waiters see the stage variable
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index 18f9a408a4f4..5669ba4bc8a9 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -34,6 +34,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)
 {
diff --git a/fs/fscache/main.c b/fs/fscache/main.c
index 6a024c45eb0b..01d57433702c 100644
--- a/fs/fscache/main.c
+++ b/fs/fscache/main.c
@@ -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);
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index 7db4dda74951..a10f87421438 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -84,6 +84,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_stage(struct fscache_cookie *cookie,
                                     enum fscache_cookie_stage stage);
 
diff --git a/include/trace/events/fscache.h b/include/trace/events/fscache.h
index 4b35fe9cd906..132381921be9 100644
--- a/include/trace/events/fscache.h
+++ b/include/trace/events/fscache.h
@@ -269,6 +269,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),
 


--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to