Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* FS-Cache cache handling
0003  *
0004  * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #define FSCACHE_DEBUG_LEVEL CACHE
0009 #include <linux/export.h>
0010 #include <linux/slab.h>
0011 #include "internal.h"
0012 
0013 static LIST_HEAD(fscache_caches);
0014 DECLARE_RWSEM(fscache_addremove_sem);
0015 EXPORT_SYMBOL(fscache_addremove_sem);
0016 DECLARE_WAIT_QUEUE_HEAD(fscache_clearance_waiters);
0017 EXPORT_SYMBOL(fscache_clearance_waiters);
0018 
0019 static atomic_t fscache_cache_debug_id;
0020 
0021 /*
0022  * Allocate a cache cookie.
0023  */
0024 static struct fscache_cache *fscache_alloc_cache(const char *name)
0025 {
0026     struct fscache_cache *cache;
0027 
0028     cache = kzalloc(sizeof(*cache), GFP_KERNEL);
0029     if (cache) {
0030         if (name) {
0031             cache->name = kstrdup(name, GFP_KERNEL);
0032             if (!cache->name) {
0033                 kfree(cache);
0034                 return NULL;
0035             }
0036         }
0037         refcount_set(&cache->ref, 1);
0038         INIT_LIST_HEAD(&cache->cache_link);
0039         cache->debug_id = atomic_inc_return(&fscache_cache_debug_id);
0040     }
0041     return cache;
0042 }
0043 
0044 static bool fscache_get_cache_maybe(struct fscache_cache *cache,
0045                     enum fscache_cache_trace where)
0046 {
0047     bool success;
0048     int ref;
0049 
0050     success = __refcount_inc_not_zero(&cache->ref, &ref);
0051     if (success)
0052         trace_fscache_cache(cache->debug_id, ref + 1, where);
0053     return success;
0054 }
0055 
0056 /*
0057  * Look up a cache cookie.
0058  */
0059 struct fscache_cache *fscache_lookup_cache(const char *name, bool is_cache)
0060 {
0061     struct fscache_cache *candidate, *cache, *unnamed = NULL;
0062 
0063     /* firstly check for the existence of the cache under read lock */
0064     down_read(&fscache_addremove_sem);
0065 
0066     list_for_each_entry(cache, &fscache_caches, cache_link) {
0067         if (cache->name && name && strcmp(cache->name, name) == 0 &&
0068             fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0069             goto got_cache_r;
0070         if (!cache->name && !name &&
0071             fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0072             goto got_cache_r;
0073     }
0074 
0075     if (!name) {
0076         list_for_each_entry(cache, &fscache_caches, cache_link) {
0077             if (cache->name &&
0078                 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0079                 goto got_cache_r;
0080         }
0081     }
0082 
0083     up_read(&fscache_addremove_sem);
0084 
0085     /* the cache does not exist - create a candidate */
0086     candidate = fscache_alloc_cache(name);
0087     if (!candidate)
0088         return ERR_PTR(-ENOMEM);
0089 
0090     /* write lock, search again and add if still not present */
0091     down_write(&fscache_addremove_sem);
0092 
0093     list_for_each_entry(cache, &fscache_caches, cache_link) {
0094         if (cache->name && name && strcmp(cache->name, name) == 0 &&
0095             fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0096             goto got_cache_w;
0097         if (!cache->name) {
0098             unnamed = cache;
0099             if (!name &&
0100                 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0101                 goto got_cache_w;
0102         }
0103     }
0104 
0105     if (unnamed && is_cache &&
0106         fscache_get_cache_maybe(unnamed, fscache_cache_get_acquire))
0107         goto use_unnamed_cache;
0108 
0109     if (!name) {
0110         list_for_each_entry(cache, &fscache_caches, cache_link) {
0111             if (cache->name &&
0112                 fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
0113                 goto got_cache_w;
0114         }
0115     }
0116 
0117     list_add_tail(&candidate->cache_link, &fscache_caches);
0118     trace_fscache_cache(candidate->debug_id,
0119                 refcount_read(&candidate->ref),
0120                 fscache_cache_new_acquire);
0121     up_write(&fscache_addremove_sem);
0122     return candidate;
0123 
0124 got_cache_r:
0125     up_read(&fscache_addremove_sem);
0126     return cache;
0127 use_unnamed_cache:
0128     cache = unnamed;
0129     cache->name = candidate->name;
0130     candidate->name = NULL;
0131 got_cache_w:
0132     up_write(&fscache_addremove_sem);
0133     kfree(candidate->name);
0134     kfree(candidate);
0135     return cache;
0136 }
0137 
0138 /**
0139  * fscache_acquire_cache - Acquire a cache-level cookie.
0140  * @name: The name of the cache.
0141  *
0142  * Get a cookie to represent an actual cache.  If a name is given and there is
0143  * a nameless cache record available, this will acquire that and set its name,
0144  * directing all the volumes using it to this cache.
0145  *
0146  * The cache will be switched over to the preparing state if not currently in
0147  * use, otherwise -EBUSY will be returned.
0148  */
0149 struct fscache_cache *fscache_acquire_cache(const char *name)
0150 {
0151     struct fscache_cache *cache;
0152 
0153     ASSERT(name);
0154     cache = fscache_lookup_cache(name, true);
0155     if (IS_ERR(cache))
0156         return cache;
0157 
0158     if (!fscache_set_cache_state_maybe(cache,
0159                        FSCACHE_CACHE_IS_NOT_PRESENT,
0160                        FSCACHE_CACHE_IS_PREPARING)) {
0161         pr_warn("Cache tag %s in use\n", name);
0162         fscache_put_cache(cache, fscache_cache_put_cache);
0163         return ERR_PTR(-EBUSY);
0164     }
0165 
0166     return cache;
0167 }
0168 EXPORT_SYMBOL(fscache_acquire_cache);
0169 
0170 /**
0171  * fscache_put_cache - Release a cache-level cookie.
0172  * @cache: The cache cookie to be released
0173  * @where: An indication of where the release happened
0174  *
0175  * Release the caller's reference on a cache-level cookie.  The @where
0176  * indication should give information about the circumstances in which the call
0177  * occurs and will be logged through a tracepoint.
0178  */
0179 void fscache_put_cache(struct fscache_cache *cache,
0180                enum fscache_cache_trace where)
0181 {
0182     unsigned int debug_id = cache->debug_id;
0183     bool zero;
0184     int ref;
0185 
0186     if (IS_ERR_OR_NULL(cache))
0187         return;
0188 
0189     zero = __refcount_dec_and_test(&cache->ref, &ref);
0190     trace_fscache_cache(debug_id, ref - 1, where);
0191 
0192     if (zero) {
0193         down_write(&fscache_addremove_sem);
0194         list_del_init(&cache->cache_link);
0195         up_write(&fscache_addremove_sem);
0196         kfree(cache->name);
0197         kfree(cache);
0198     }
0199 }
0200 
0201 /**
0202  * fscache_relinquish_cache - Reset cache state and release cookie
0203  * @cache: The cache cookie to be released
0204  *
0205  * Reset the state of a cache and release the caller's reference on a cache
0206  * cookie.
0207  */
0208 void fscache_relinquish_cache(struct fscache_cache *cache)
0209 {
0210     enum fscache_cache_trace where =
0211         (cache->state == FSCACHE_CACHE_IS_PREPARING) ?
0212         fscache_cache_put_prep_failed :
0213         fscache_cache_put_relinquish;
0214 
0215     cache->ops = NULL;
0216     cache->cache_priv = NULL;
0217     fscache_set_cache_state(cache, FSCACHE_CACHE_IS_NOT_PRESENT);
0218     fscache_put_cache(cache, where);
0219 }
0220 EXPORT_SYMBOL(fscache_relinquish_cache);
0221 
0222 /**
0223  * fscache_add_cache - Declare a cache as being open for business
0224  * @cache: The cache-level cookie representing the cache
0225  * @ops: Table of cache operations to use
0226  * @cache_priv: Private data for the cache record
0227  *
0228  * Add a cache to the system, making it available for netfs's to use.
0229  *
0230  * See Documentation/filesystems/caching/backend-api.rst for a complete
0231  * description.
0232  */
0233 int fscache_add_cache(struct fscache_cache *cache,
0234               const struct fscache_cache_ops *ops,
0235               void *cache_priv)
0236 {
0237     int n_accesses;
0238 
0239     _enter("{%s,%s}", ops->name, cache->name);
0240 
0241     BUG_ON(fscache_cache_state(cache) != FSCACHE_CACHE_IS_PREPARING);
0242 
0243     /* Get a ref on the cache cookie and keep its n_accesses counter raised
0244      * by 1 to prevent wakeups from transitioning it to 0 until we're
0245      * withdrawing caching services from it.
0246      */
0247     n_accesses = atomic_inc_return(&cache->n_accesses);
0248     trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0249                    n_accesses, fscache_access_cache_pin);
0250 
0251     down_write(&fscache_addremove_sem);
0252 
0253     cache->ops = ops;
0254     cache->cache_priv = cache_priv;
0255     fscache_set_cache_state(cache, FSCACHE_CACHE_IS_ACTIVE);
0256 
0257     up_write(&fscache_addremove_sem);
0258     pr_notice("Cache \"%s\" added (type %s)\n", cache->name, ops->name);
0259     _leave(" = 0 [%s]", cache->name);
0260     return 0;
0261 }
0262 EXPORT_SYMBOL(fscache_add_cache);
0263 
0264 /**
0265  * fscache_begin_cache_access - Pin a cache so it can be accessed
0266  * @cache: The cache-level cookie
0267  * @why: An indication of the circumstances of the access for tracing
0268  *
0269  * Attempt to pin the cache to prevent it from going away whilst we're
0270  * accessing it and returns true if successful.  This works as follows:
0271  *
0272  *  (1) If the cache tests as not live (state is not FSCACHE_CACHE_IS_ACTIVE),
0273  *      then we return false to indicate access was not permitted.
0274  *
0275  *  (2) If the cache tests as live, then we increment the n_accesses count and
0276  *      then recheck the liveness, ending the access if it ceased to be live.
0277  *
0278  *  (3) When we end the access, we decrement n_accesses and wake up the any
0279  *      waiters if it reaches 0.
0280  *
0281  *  (4) Whilst the cache is caching, n_accesses is kept artificially
0282  *      incremented to prevent wakeups from happening.
0283  *
0284  *  (5) When the cache is taken offline, the state is changed to prevent new
0285  *      accesses, n_accesses is decremented and we wait for n_accesses to
0286  *      become 0.
0287  */
0288 bool fscache_begin_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
0289 {
0290     int n_accesses;
0291 
0292     if (!fscache_cache_is_live(cache))
0293         return false;
0294 
0295     n_accesses = atomic_inc_return(&cache->n_accesses);
0296     smp_mb__after_atomic(); /* Reread live flag after n_accesses */
0297     trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0298                    n_accesses, why);
0299     if (!fscache_cache_is_live(cache)) {
0300         fscache_end_cache_access(cache, fscache_access_unlive);
0301         return false;
0302     }
0303     return true;
0304 }
0305 
0306 /**
0307  * fscache_end_cache_access - Unpin a cache at the end of an access.
0308  * @cache: The cache-level cookie
0309  * @why: An indication of the circumstances of the access for tracing
0310  *
0311  * Unpin a cache after we've accessed it.  The @why indicator is merely
0312  * provided for tracing purposes.
0313  */
0314 void fscache_end_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
0315 {
0316     int n_accesses;
0317 
0318     smp_mb__before_atomic();
0319     n_accesses = atomic_dec_return(&cache->n_accesses);
0320     trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0321                    n_accesses, why);
0322     if (n_accesses == 0)
0323         wake_up_var(&cache->n_accesses);
0324 }
0325 
0326 /**
0327  * fscache_io_error - Note a cache I/O error
0328  * @cache: The record describing the cache
0329  *
0330  * Note that an I/O error occurred in a cache and that it should no longer be
0331  * used for anything.  This also reports the error into the kernel log.
0332  *
0333  * See Documentation/filesystems/caching/backend-api.rst for a complete
0334  * description.
0335  */
0336 void fscache_io_error(struct fscache_cache *cache)
0337 {
0338     if (fscache_set_cache_state_maybe(cache,
0339                       FSCACHE_CACHE_IS_ACTIVE,
0340                       FSCACHE_CACHE_GOT_IOERROR))
0341         pr_err("Cache '%s' stopped due to I/O error\n",
0342                cache->name);
0343 }
0344 EXPORT_SYMBOL(fscache_io_error);
0345 
0346 /**
0347  * fscache_withdraw_cache - Withdraw a cache from the active service
0348  * @cache: The cache cookie
0349  *
0350  * Begin the process of withdrawing a cache from service.  This stops new
0351  * cache-level and volume-level accesses from taking place and waits for
0352  * currently ongoing cache-level accesses to end.
0353  */
0354 void fscache_withdraw_cache(struct fscache_cache *cache)
0355 {
0356     int n_accesses;
0357 
0358     pr_notice("Withdrawing cache \"%s\" (%u objs)\n",
0359           cache->name, atomic_read(&cache->object_count));
0360 
0361     fscache_set_cache_state(cache, FSCACHE_CACHE_IS_WITHDRAWN);
0362 
0363     /* Allow wakeups on dec-to-0 */
0364     n_accesses = atomic_dec_return(&cache->n_accesses);
0365     trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
0366                    n_accesses, fscache_access_cache_unpin);
0367 
0368     wait_var_event(&cache->n_accesses,
0369                atomic_read(&cache->n_accesses) == 0);
0370 }
0371 EXPORT_SYMBOL(fscache_withdraw_cache);
0372 
0373 #ifdef CONFIG_PROC_FS
0374 static const char fscache_cache_states[NR__FSCACHE_CACHE_STATE] = "-PAEW";
0375 
0376 /*
0377  * Generate a list of caches in /proc/fs/fscache/caches
0378  */
0379 static int fscache_caches_seq_show(struct seq_file *m, void *v)
0380 {
0381     struct fscache_cache *cache;
0382 
0383     if (v == &fscache_caches) {
0384         seq_puts(m,
0385              "CACHE    REF   VOLS  OBJS  ACCES S NAME\n"
0386              "======== ===== ===== ===== ===== = ===============\n"
0387              );
0388         return 0;
0389     }
0390 
0391     cache = list_entry(v, struct fscache_cache, cache_link);
0392     seq_printf(m,
0393            "%08x %5d %5d %5d %5d %c %s\n",
0394            cache->debug_id,
0395            refcount_read(&cache->ref),
0396            atomic_read(&cache->n_volumes),
0397            atomic_read(&cache->object_count),
0398            atomic_read(&cache->n_accesses),
0399            fscache_cache_states[cache->state],
0400            cache->name ?: "-");
0401     return 0;
0402 }
0403 
0404 static void *fscache_caches_seq_start(struct seq_file *m, loff_t *_pos)
0405     __acquires(fscache_addremove_sem)
0406 {
0407     down_read(&fscache_addremove_sem);
0408     return seq_list_start_head(&fscache_caches, *_pos);
0409 }
0410 
0411 static void *fscache_caches_seq_next(struct seq_file *m, void *v, loff_t *_pos)
0412 {
0413     return seq_list_next(v, &fscache_caches, _pos);
0414 }
0415 
0416 static void fscache_caches_seq_stop(struct seq_file *m, void *v)
0417     __releases(fscache_addremove_sem)
0418 {
0419     up_read(&fscache_addremove_sem);
0420 }
0421 
0422 const struct seq_operations fscache_caches_seq_ops = {
0423     .start  = fscache_caches_seq_start,
0424     .next   = fscache_caches_seq_next,
0425     .stop   = fscache_caches_seq_stop,
0426     .show   = fscache_caches_seq_show,
0427 };
0428 #endif /* CONFIG_PROC_FS */