summaryrefslogtreecommitdiffstats
path: root/fs/fscache/cache.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:36 +0000
commit50ba0232fd5312410f1b65247e774244f89a628e (patch)
treefd8f2fc78e9e548af0ff9590276602ee6125be00 /fs/fscache/cache.c
parentReleasing progress-linux version 6.7.12-1~progress7.99u1. (diff)
downloadlinux-50ba0232fd5312410f1b65247e774244f89a628e.tar.xz
linux-50ba0232fd5312410f1b65247e774244f89a628e.zip
Merging upstream version 6.8.9.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'fs/fscache/cache.c')
-rw-r--r--fs/fscache/cache.c429
1 files changed, 0 insertions, 429 deletions
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c
deleted file mode 100644
index 9397ed39b..000000000
--- a/fs/fscache/cache.c
+++ /dev/null
@@ -1,429 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* FS-Cache cache handling
- *
- * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- */
-
-#define FSCACHE_DEBUG_LEVEL CACHE
-#include <linux/export.h>
-#include <linux/slab.h>
-#include "internal.h"
-
-static LIST_HEAD(fscache_caches);
-DECLARE_RWSEM(fscache_addremove_sem);
-EXPORT_SYMBOL(fscache_addremove_sem);
-DECLARE_WAIT_QUEUE_HEAD(fscache_clearance_waiters);
-EXPORT_SYMBOL(fscache_clearance_waiters);
-
-static atomic_t fscache_cache_debug_id;
-
-/*
- * Allocate a cache cookie.
- */
-static struct fscache_cache *fscache_alloc_cache(const char *name)
-{
- struct fscache_cache *cache;
-
- cache = kzalloc(sizeof(*cache), GFP_KERNEL);
- if (cache) {
- if (name) {
- cache->name = kstrdup(name, GFP_KERNEL);
- if (!cache->name) {
- kfree(cache);
- return NULL;
- }
- }
- refcount_set(&cache->ref, 1);
- INIT_LIST_HEAD(&cache->cache_link);
- cache->debug_id = atomic_inc_return(&fscache_cache_debug_id);
- }
- return cache;
-}
-
-static bool fscache_get_cache_maybe(struct fscache_cache *cache,
- enum fscache_cache_trace where)
-{
- bool success;
- int ref;
-
- success = __refcount_inc_not_zero(&cache->ref, &ref);
- if (success)
- trace_fscache_cache(cache->debug_id, ref + 1, where);
- return success;
-}
-
-/*
- * Look up a cache cookie.
- */
-struct fscache_cache *fscache_lookup_cache(const char *name, bool is_cache)
-{
- struct fscache_cache *candidate, *cache, *unnamed = NULL;
-
- /* firstly check for the existence of the cache under read lock */
- down_read(&fscache_addremove_sem);
-
- list_for_each_entry(cache, &fscache_caches, cache_link) {
- if (cache->name && name && strcmp(cache->name, name) == 0 &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_r;
- if (!cache->name && !name &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_r;
- }
-
- if (!name) {
- list_for_each_entry(cache, &fscache_caches, cache_link) {
- if (cache->name &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_r;
- }
- }
-
- up_read(&fscache_addremove_sem);
-
- /* the cache does not exist - create a candidate */
- candidate = fscache_alloc_cache(name);
- if (!candidate)
- return ERR_PTR(-ENOMEM);
-
- /* write lock, search again and add if still not present */
- down_write(&fscache_addremove_sem);
-
- list_for_each_entry(cache, &fscache_caches, cache_link) {
- if (cache->name && name && strcmp(cache->name, name) == 0 &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_w;
- if (!cache->name) {
- unnamed = cache;
- if (!name &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_w;
- }
- }
-
- if (unnamed && is_cache &&
- fscache_get_cache_maybe(unnamed, fscache_cache_get_acquire))
- goto use_unnamed_cache;
-
- if (!name) {
- list_for_each_entry(cache, &fscache_caches, cache_link) {
- if (cache->name &&
- fscache_get_cache_maybe(cache, fscache_cache_get_acquire))
- goto got_cache_w;
- }
- }
-
- list_add_tail(&candidate->cache_link, &fscache_caches);
- trace_fscache_cache(candidate->debug_id,
- refcount_read(&candidate->ref),
- fscache_cache_new_acquire);
- up_write(&fscache_addremove_sem);
- return candidate;
-
-got_cache_r:
- up_read(&fscache_addremove_sem);
- return cache;
-use_unnamed_cache:
- cache = unnamed;
- cache->name = candidate->name;
- candidate->name = NULL;
-got_cache_w:
- up_write(&fscache_addremove_sem);
- kfree(candidate->name);
- kfree(candidate);
- return cache;
-}
-
-/**
- * fscache_acquire_cache - Acquire a cache-level cookie.
- * @name: The name of the cache.
- *
- * Get a cookie to represent an actual cache. If a name is given and there is
- * a nameless cache record available, this will acquire that and set its name,
- * directing all the volumes using it to this cache.
- *
- * The cache will be switched over to the preparing state if not currently in
- * use, otherwise -EBUSY will be returned.
- */
-struct fscache_cache *fscache_acquire_cache(const char *name)
-{
- struct fscache_cache *cache;
-
- ASSERT(name);
- cache = fscache_lookup_cache(name, true);
- if (IS_ERR(cache))
- return cache;
-
- if (!fscache_set_cache_state_maybe(cache,
- FSCACHE_CACHE_IS_NOT_PRESENT,
- FSCACHE_CACHE_IS_PREPARING)) {
- pr_warn("Cache tag %s in use\n", name);
- fscache_put_cache(cache, fscache_cache_put_cache);
- return ERR_PTR(-EBUSY);
- }
-
- return cache;
-}
-EXPORT_SYMBOL(fscache_acquire_cache);
-
-/**
- * fscache_put_cache - Release a cache-level cookie.
- * @cache: The cache cookie to be released
- * @where: An indication of where the release happened
- *
- * Release the caller's reference on a cache-level cookie. The @where
- * indication should give information about the circumstances in which the call
- * occurs and will be logged through a tracepoint.
- */
-void fscache_put_cache(struct fscache_cache *cache,
- enum fscache_cache_trace where)
-{
- unsigned int debug_id;
- bool zero;
- int ref;
-
- if (IS_ERR_OR_NULL(cache))
- return;
-
- debug_id = cache->debug_id;
- zero = __refcount_dec_and_test(&cache->ref, &ref);
- trace_fscache_cache(debug_id, ref - 1, where);
-
- if (zero) {
- down_write(&fscache_addremove_sem);
- list_del_init(&cache->cache_link);
- up_write(&fscache_addremove_sem);
- kfree(cache->name);
- kfree(cache);
- }
-}
-
-/**
- * fscache_relinquish_cache - Reset cache state and release cookie
- * @cache: The cache cookie to be released
- *
- * Reset the state of a cache and release the caller's reference on a cache
- * cookie.
- */
-void fscache_relinquish_cache(struct fscache_cache *cache)
-{
- enum fscache_cache_trace where =
- (cache->state == FSCACHE_CACHE_IS_PREPARING) ?
- fscache_cache_put_prep_failed :
- fscache_cache_put_relinquish;
-
- cache->ops = NULL;
- cache->cache_priv = NULL;
- fscache_set_cache_state(cache, FSCACHE_CACHE_IS_NOT_PRESENT);
- fscache_put_cache(cache, where);
-}
-EXPORT_SYMBOL(fscache_relinquish_cache);
-
-/**
- * fscache_add_cache - Declare a cache as being open for business
- * @cache: The cache-level cookie representing the cache
- * @ops: Table of cache operations to use
- * @cache_priv: Private data for the cache record
- *
- * Add a cache to the system, making it available for netfs's to use.
- *
- * See Documentation/filesystems/caching/backend-api.rst for a complete
- * description.
- */
-int fscache_add_cache(struct fscache_cache *cache,
- const struct fscache_cache_ops *ops,
- void *cache_priv)
-{
- int n_accesses;
-
- _enter("{%s,%s}", ops->name, cache->name);
-
- BUG_ON(fscache_cache_state(cache) != FSCACHE_CACHE_IS_PREPARING);
-
- /* Get a ref on the cache cookie and keep its n_accesses counter raised
- * by 1 to prevent wakeups from transitioning it to 0 until we're
- * withdrawing caching services from it.
- */
- n_accesses = atomic_inc_return(&cache->n_accesses);
- trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
- n_accesses, fscache_access_cache_pin);
-
- down_write(&fscache_addremove_sem);
-
- cache->ops = ops;
- cache->cache_priv = cache_priv;
- fscache_set_cache_state(cache, FSCACHE_CACHE_IS_ACTIVE);
-
- up_write(&fscache_addremove_sem);
- pr_notice("Cache \"%s\" added (type %s)\n", cache->name, ops->name);
- _leave(" = 0 [%s]", cache->name);
- return 0;
-}
-EXPORT_SYMBOL(fscache_add_cache);
-
-/**
- * fscache_begin_cache_access - Pin a cache so it can be accessed
- * @cache: The cache-level cookie
- * @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 it 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 n_accesses count and
- * then recheck the liveness, ending the access if it ceased to be live.
- *
- * (3) When we end the access, we decrement n_accesses and wake up the any
- * waiters if it reaches 0.
- *
- * (4) Whilst the cache is caching, 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, n_accesses is decremented and we wait for n_accesses to
- * become 0.
- */
-bool fscache_begin_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
-{
- int n_accesses;
-
- if (!fscache_cache_is_live(cache))
- return false;
-
- n_accesses = atomic_inc_return(&cache->n_accesses);
- smp_mb__after_atomic(); /* Reread live flag after n_accesses */
- trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
- n_accesses, why);
- if (!fscache_cache_is_live(cache)) {
- fscache_end_cache_access(cache, fscache_access_unlive);
- return false;
- }
- return true;
-}
-
-/**
- * fscache_end_cache_access - Unpin a cache at the end of an access.
- * @cache: The cache-level cookie
- * @why: An indication of the circumstances of the access for tracing
- *
- * Unpin a cache after we've accessed it. The @why indicator is merely
- * provided for tracing purposes.
- */
-void fscache_end_cache_access(struct fscache_cache *cache, enum fscache_access_trace why)
-{
- int n_accesses;
-
- smp_mb__before_atomic();
- n_accesses = atomic_dec_return(&cache->n_accesses);
- trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
- n_accesses, why);
- if (n_accesses == 0)
- wake_up_var(&cache->n_accesses);
-}
-
-/**
- * fscache_io_error - Note a cache I/O error
- * @cache: The record describing the cache
- *
- * Note that an I/O error occurred in a cache and that it should no longer be
- * used for anything. This also reports the error into the kernel log.
- *
- * See Documentation/filesystems/caching/backend-api.rst for a complete
- * description.
- */
-void fscache_io_error(struct fscache_cache *cache)
-{
- if (fscache_set_cache_state_maybe(cache,
- FSCACHE_CACHE_IS_ACTIVE,
- FSCACHE_CACHE_GOT_IOERROR))
- pr_err("Cache '%s' stopped due to I/O error\n",
- cache->name);
-}
-EXPORT_SYMBOL(fscache_io_error);
-
-/**
- * fscache_withdraw_cache - Withdraw a cache from the active service
- * @cache: The cache cookie
- *
- * Begin the process of withdrawing a cache from service. This stops new
- * cache-level and volume-level accesses from taking place and waits for
- * currently ongoing cache-level accesses to end.
- */
-void fscache_withdraw_cache(struct fscache_cache *cache)
-{
- int n_accesses;
-
- pr_notice("Withdrawing cache \"%s\" (%u objs)\n",
- cache->name, atomic_read(&cache->object_count));
-
- fscache_set_cache_state(cache, FSCACHE_CACHE_IS_WITHDRAWN);
-
- /* Allow wakeups on dec-to-0 */
- n_accesses = atomic_dec_return(&cache->n_accesses);
- trace_fscache_access_cache(cache->debug_id, refcount_read(&cache->ref),
- n_accesses, fscache_access_cache_unpin);
-
- wait_var_event(&cache->n_accesses,
- atomic_read(&cache->n_accesses) == 0);
-}
-EXPORT_SYMBOL(fscache_withdraw_cache);
-
-#ifdef CONFIG_PROC_FS
-static const char fscache_cache_states[NR__FSCACHE_CACHE_STATE] = "-PAEW";
-
-/*
- * Generate a list of caches in /proc/fs/fscache/caches
- */
-static int fscache_caches_seq_show(struct seq_file *m, void *v)
-{
- struct fscache_cache *cache;
-
- if (v == &fscache_caches) {
- seq_puts(m,
- "CACHE REF VOLS OBJS ACCES S NAME\n"
- "======== ===== ===== ===== ===== = ===============\n"
- );
- return 0;
- }
-
- cache = list_entry(v, struct fscache_cache, cache_link);
- seq_printf(m,
- "%08x %5d %5d %5d %5d %c %s\n",
- cache->debug_id,
- refcount_read(&cache->ref),
- atomic_read(&cache->n_volumes),
- atomic_read(&cache->object_count),
- atomic_read(&cache->n_accesses),
- fscache_cache_states[cache->state],
- cache->name ?: "-");
- return 0;
-}
-
-static void *fscache_caches_seq_start(struct seq_file *m, loff_t *_pos)
- __acquires(fscache_addremove_sem)
-{
- down_read(&fscache_addremove_sem);
- return seq_list_start_head(&fscache_caches, *_pos);
-}
-
-static void *fscache_caches_seq_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- return seq_list_next(v, &fscache_caches, _pos);
-}
-
-static void fscache_caches_seq_stop(struct seq_file *m, void *v)
- __releases(fscache_addremove_sem)
-{
- up_read(&fscache_addremove_sem);
-}
-
-const struct seq_operations fscache_caches_seq_ops = {
- .start = fscache_caches_seq_start,
- .next = fscache_caches_seq_next,
- .stop = fscache_caches_seq_stop,
- .show = fscache_caches_seq_show,
-};
-#endif /* CONFIG_PROC_FS */