2874c5fd28426 (Thomas Gleixner 2019-05-27 08:55:01 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 2) /* FS-Cache cache handling
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 3) *
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 4) * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 5) * Written by David Howells (dhowells@redhat.com)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 6) */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 7)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 8) #define FSCACHE_DEBUG_LEVEL CACHE
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 9) #include <linux/module.h>
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 10) #include <linux/slab.h>
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 11) #include "internal.h"
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 12)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 13) LIST_HEAD(fscache_cache_list);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 14) DECLARE_RWSEM(fscache_addremove_sem);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 15) DECLARE_WAIT_QUEUE_HEAD(fscache_cache_cleared_wq);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 16) EXPORT_SYMBOL(fscache_cache_cleared_wq);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 17)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 18) static LIST_HEAD(fscache_cache_tag_list);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 19)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 20) /*
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 21) * look up a cache tag
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 22) */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 23) struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 24) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 25) struct fscache_cache_tag *tag, *xtag;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 26)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 27) /* firstly check for the existence of the tag under read lock */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 28) down_read(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 29)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 30) list_for_each_entry(tag, &fscache_cache_tag_list, link) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 31) if (strcmp(tag->name, name) == 0) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 32) atomic_inc(&tag->usage);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 33) up_read(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 34) return tag;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 35) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 36) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 37)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 38) up_read(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 39)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 40) /* the tag does not exist - create a candidate */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 41) xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 42) if (!xtag)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 43) /* return a dummy tag if out of memory */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 44) return ERR_PTR(-ENOMEM);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 45)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 46) atomic_set(&xtag->usage, 1);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 47) strcpy(xtag->name, name);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 48)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 49) /* write lock, search again and add if still not present */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 50) down_write(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 51)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 52) list_for_each_entry(tag, &fscache_cache_tag_list, link) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 53) if (strcmp(tag->name, name) == 0) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 54) atomic_inc(&tag->usage);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 55) up_write(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 56) kfree(xtag);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 57) return tag;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 58) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 59) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 60)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 61) list_add_tail(&xtag->link, &fscache_cache_tag_list);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 62) up_write(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 63) return xtag;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 64) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 65)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 66) /*
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 67) * release a reference to a cache tag
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 68) */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 69) void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 70) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 71) if (tag != ERR_PTR(-ENOMEM)) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 72) down_write(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 73)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 74) if (atomic_dec_and_test(&tag->usage))
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 75) list_del_init(&tag->link);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 76) else
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 77) tag = NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 78)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 79) up_write(&fscache_addremove_sem);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 80)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 81) kfree(tag);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 82) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 83) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 84)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 85) /*
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 86) * select a cache in which to store an object
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 87) * - the cache addremove semaphore must be at least read-locked by the caller
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 88) * - the object will never be an index
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 89) */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 90) struct fscache_cache *fscache_select_cache_for_object(
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 91) struct fscache_cookie *cookie)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 92) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 93) struct fscache_cache_tag *tag;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 94) struct fscache_object *object;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 95) struct fscache_cache *cache;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 96)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 97) _enter("");
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 98)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 99) if (list_empty(&fscache_cache_list)) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 100) _leave(" = NULL [no cache]");
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 101) return NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 102) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 103)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 104) /* we check the parent to determine the cache to use */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 105) spin_lock(&cookie->lock);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 106)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 107) /* the first in the parent's backing list should be the preferred
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 108) * cache */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 109) if (!hlist_empty(&cookie->backing_objects)) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 110) object = hlist_entry(cookie->backing_objects.first,
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 111) struct fscache_object, cookie_link);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 112)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 113) cache = object->cache;
493f7bc11457b (David Howells 2013-05-10 19:50:26 +0100 114) if (fscache_object_is_dying(object) ||
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 115) test_bit(FSCACHE_IOERROR, &cache->flags))
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 116) cache = NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 117)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 118) spin_unlock(&cookie->lock);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 119) _leave(" = %p [parent]", cache);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 120) return cache;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 121) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 122)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 123) /* the parent is unbacked */
402cb8dda949d (David Howells 2018-04-04 13:41:28 +0100 124) if (cookie->type != FSCACHE_COOKIE_TYPE_INDEX) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 125) /* cookie not an index and is unbacked */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 126) spin_unlock(&cookie->lock);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 127) _leave(" = NULL [cookie ub,ni]");
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 128) return NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 129) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 130)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 131) spin_unlock(&cookie->lock);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 132)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 133) if (!cookie->def->select_cache)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 134) goto no_preference;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 135)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 136) /* ask the netfs for its preference */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 137) tag = cookie->def->select_cache(cookie->parent->netfs_data,
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 138) cookie->netfs_data);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 139) if (!tag)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 140) goto no_preference;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 141)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 142) if (tag == ERR_PTR(-ENOMEM)) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 143) _leave(" = NULL [nomem tag]");
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 144) return NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 145) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 146)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 147) if (!tag->cache) {
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 148) _leave(" = NULL [unbacked tag]");
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 149) return NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 150) }
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 151)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 152) if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 153) return NULL;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 154)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 155) _leave(" = %p [specific]", tag->cache);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 156) return tag->cache;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 157)
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 158) no_preference:
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 159) /* netfs has no preference - just select first cache */
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 160) cache = list_entry(fscache_cache_list.next,
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 161) struct fscache_cache, link);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 162) _leave(" = %p [first]", cache);
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 163) return cache;
0e04d4cefcf4d (David Howells 2009-04-03 16:42:37 +0100 164) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 165)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 166) /**
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 167) * fscache_init_cache - Initialise a cache record
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 168) * @cache: The cache record to be initialised
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 169) * @ops: The cache operations to be installed in that record
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 170) * @idfmt: Format string to define identifier
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 171) * @...: sprintf-style arguments
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 172) *
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 173) * Initialise a record of a cache and fill in the name.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 174) *
0e822145b5642 (Mauro Carvalho Chehab 2020-04-27 23:16:58 +0200 175) * See Documentation/filesystems/caching/backend-api.rst for a complete
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 176) * description.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 177) */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 178) void fscache_init_cache(struct fscache_cache *cache,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 179) const struct fscache_cache_ops *ops,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 180) const char *idfmt,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 181) ...)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 182) {
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 183) va_list va;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 184)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 185) memset(cache, 0, sizeof(*cache));
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 186)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 187) cache->ops = ops;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 188)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 189) va_start(va, idfmt);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 190) vsnprintf(cache->identifier, sizeof(cache->identifier), idfmt, va);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 191) va_end(va);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 192)
952efe7b7840e (David Howells 2009-04-03 16:42:39 +0100 193) INIT_WORK(&cache->op_gc, fscache_operation_gc);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 194) INIT_LIST_HEAD(&cache->link);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 195) INIT_LIST_HEAD(&cache->object_list);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 196) INIT_LIST_HEAD(&cache->op_gc_list);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 197) spin_lock_init(&cache->object_list_lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 198) spin_lock_init(&cache->op_gc_list_lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 199) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 200) EXPORT_SYMBOL(fscache_init_cache);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 201)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 202) /**
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 203) * fscache_add_cache - Declare a cache as being open for business
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 204) * @cache: The record describing the cache
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 205) * @ifsdef: The record of the cache object describing the top-level index
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 206) * @tagname: The tag describing this cache
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 207) *
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 208) * Add a cache to the system, making it available for netfs's to use.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 209) *
0e822145b5642 (Mauro Carvalho Chehab 2020-04-27 23:16:58 +0200 210) * See Documentation/filesystems/caching/backend-api.rst for a complete
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 211) * description.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 212) */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 213) int fscache_add_cache(struct fscache_cache *cache,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 214) struct fscache_object *ifsdef,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 215) const char *tagname)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 216) {
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 217) struct fscache_cache_tag *tag;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 218)
f29507ce66701 (Kiran Kumar Modukuri 2018-06-21 13:31:44 -0700 219) ASSERTCMP(ifsdef->cookie, ==, &fscache_fsdef_index);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 220) BUG_ON(!cache->ops);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 221) BUG_ON(!ifsdef);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 222)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 223) cache->flags = 0;
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 224) ifsdef->event_mask =
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 225) ((1 << NR_FSCACHE_OBJECT_EVENTS) - 1) &
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 226) ~(1 << FSCACHE_OBJECT_EV_CLEARED);
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 227) __set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &ifsdef->flags);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 228)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 229) if (!tagname)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 230) tagname = cache->identifier;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 231)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 232) BUG_ON(!tagname[0]);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 233)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 234) _enter("{%s.%s},,%s", cache->ops->name, cache->identifier, tagname);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 235)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 236) /* we use the cache tag to uniquely identify caches */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 237) tag = __fscache_lookup_cache_tag(tagname);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 238) if (IS_ERR(tag))
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 239) goto nomem;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 240)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 241) if (test_and_set_bit(FSCACHE_TAG_RESERVED, &tag->flags))
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 242) goto tag_in_use;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 243)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 244) cache->kobj = kobject_create_and_add(tagname, fscache_root);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 245) if (!cache->kobj)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 246) goto error;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 247)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 248) ifsdef->cache = cache;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 249) cache->fsdef = ifsdef;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 250)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 251) down_write(&fscache_addremove_sem);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 252)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 253) tag->cache = cache;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 254) cache->tag = tag;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 255)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 256) /* add the cache to the list */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 257) list_add(&cache->link, &fscache_cache_list);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 258)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 259) /* add the cache's netfs definition index object to the cache's
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 260) * list */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 261) spin_lock(&cache->object_list_lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 262) list_add_tail(&ifsdef->cache_link, &cache->object_list);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 263) spin_unlock(&cache->object_list_lock);
4fbf4291aa159 (David Howells 2009-11-19 18:11:04 +0000 264) fscache_objlist_add(ifsdef);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 265)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 266) /* add the cache's netfs definition index object to the top level index
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 267) * cookie as a known backing object */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 268) spin_lock(&fscache_fsdef_index.lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 269)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 270) hlist_add_head(&ifsdef->cookie_link,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 271) &fscache_fsdef_index.backing_objects);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 272)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 273) atomic_inc(&fscache_fsdef_index.usage);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 274)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 275) /* done */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 276) spin_unlock(&fscache_fsdef_index.lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 277) up_write(&fscache_addremove_sem);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 278)
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 279) pr_notice("Cache \"%s\" added (type %s)\n",
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 280) cache->tag->name, cache->ops->name);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 281) kobject_uevent(cache->kobj, KOBJ_ADD);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 282)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 283) _leave(" = 0 [%s]", cache->identifier);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 284) return 0;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 285)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 286) tag_in_use:
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 287) pr_err("Cache tag '%s' already in use\n", tagname);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 288) __fscache_release_cache_tag(tag);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 289) _leave(" = -EXIST");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 290) return -EEXIST;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 291)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 292) error:
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 293) __fscache_release_cache_tag(tag);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 294) _leave(" = -EINVAL");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 295) return -EINVAL;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 296)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 297) nomem:
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 298) _leave(" = -ENOMEM");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 299) return -ENOMEM;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 300) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 301) EXPORT_SYMBOL(fscache_add_cache);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 302)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 303) /**
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 304) * fscache_io_error - Note a cache I/O error
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 305) * @cache: The record describing the cache
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 306) *
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 307) * Note that an I/O error occurred in a cache and that it should no longer be
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 308) * used for anything. This also reports the error into the kernel log.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 309) *
0e822145b5642 (Mauro Carvalho Chehab 2020-04-27 23:16:58 +0200 310) * See Documentation/filesystems/caching/backend-api.rst for a complete
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 311) * description.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 312) */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 313) void fscache_io_error(struct fscache_cache *cache)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 314) {
75bc411388f4a (David Howells 2012-12-05 13:34:48 +0000 315) if (!test_and_set_bit(FSCACHE_IOERROR, &cache->flags))
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 316) pr_err("Cache '%s' stopped due to I/O error\n",
75bc411388f4a (David Howells 2012-12-05 13:34:48 +0000 317) cache->ops->name);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 318) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 319) EXPORT_SYMBOL(fscache_io_error);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 320)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 321) /*
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 322) * request withdrawal of all the objects in a cache
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 323) * - all the objects being withdrawn are moved onto the supplied list
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 324) */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 325) static void fscache_withdraw_all_objects(struct fscache_cache *cache,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 326) struct list_head *dying_objects)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 327) {
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 328) struct fscache_object *object;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 329)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 330) while (!list_empty(&cache->object_list)) {
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 331) spin_lock(&cache->object_list_lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 332)
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 333) if (!list_empty(&cache->object_list)) {
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 334) object = list_entry(cache->object_list.next,
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 335) struct fscache_object, cache_link);
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 336) list_move_tail(&object->cache_link, dying_objects);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 337)
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 338) _debug("withdraw %p", object->cookie);
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 339)
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 340) /* This must be done under object_list_lock to prevent
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 341) * a race with fscache_drop_object().
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 342) */
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 343) fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 344) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 345)
caaef6900befb (David Howells 2013-05-10 19:50:26 +0100 346) spin_unlock(&cache->object_list_lock);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 347) cond_resched();
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 348) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 349) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 350)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 351) /**
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 352) * fscache_withdraw_cache - Withdraw a cache from the active service
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 353) * @cache: The record describing the cache
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 354) *
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 355) * Withdraw a cache from service, unbinding all its cache objects from the
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 356) * netfs cookies they're currently representing.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 357) *
0e822145b5642 (Mauro Carvalho Chehab 2020-04-27 23:16:58 +0200 358) * See Documentation/filesystems/caching/backend-api.rst for a complete
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 359) * description.
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 360) */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 361) void fscache_withdraw_cache(struct fscache_cache *cache)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 362) {
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 363) LIST_HEAD(dying_objects);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 364)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 365) _enter("");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 366)
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 367) pr_notice("Withdrawing cache \"%s\"\n",
36dfd116edd48 (Fabian Frederick 2014-06-04 16:05:38 -0700 368) cache->tag->name);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 369)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 370) /* make the cache unavailable for cookie acquisition */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 371) if (test_and_set_bit(FSCACHE_CACHE_WITHDRAWN, &cache->flags))
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 372) BUG();
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 373)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 374) down_write(&fscache_addremove_sem);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 375) list_del_init(&cache->link);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 376) cache->tag->cache = NULL;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 377) up_write(&fscache_addremove_sem);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 378)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 379) /* make sure all pages pinned by operations on behalf of the netfs are
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 380) * written to disk */
52bd75fdb135d (David Howells 2009-11-19 18:11:08 +0000 381) fscache_stat(&fscache_n_cop_sync_cache);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 382) cache->ops->sync_cache(cache);
52bd75fdb135d (David Howells 2009-11-19 18:11:08 +0000 383) fscache_stat_d(&fscache_n_cop_sync_cache);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 384)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 385) /* dissociate all the netfs pages backed by this cache from the block
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 386) * mappings in the cache */
52bd75fdb135d (David Howells 2009-11-19 18:11:08 +0000 387) fscache_stat(&fscache_n_cop_dissociate_pages);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 388) cache->ops->dissociate_pages(cache);
52bd75fdb135d (David Howells 2009-11-19 18:11:08 +0000 389) fscache_stat_d(&fscache_n_cop_dissociate_pages);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 390)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 391) /* we now have to destroy all the active objects pertaining to this
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 392) * cache - which we do by passing them off to thread pool to be
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 393) * disposed of */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 394) _debug("destroy");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 395)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 396) fscache_withdraw_all_objects(cache, &dying_objects);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 397)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 398) /* wait for all extant objects to finish their outstanding operations
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 399) * and go away */
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 400) _debug("wait for finish");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 401) wait_event(fscache_cache_cleared_wq,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 402) atomic_read(&cache->object_count) == 0);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 403) _debug("wait for clearance");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 404) wait_event(fscache_cache_cleared_wq,
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 405) list_empty(&cache->object_list));
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 406) _debug("cleared");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 407) ASSERT(list_empty(&dying_objects));
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 408)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 409) kobject_put(cache->kobj);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 410)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 411) clear_bit(FSCACHE_TAG_RESERVED, &cache->tag->flags);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 412) fscache_release_cache_tag(cache->tag);
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 413) cache->tag = NULL;
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 414)
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 415) _leave("");
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 416) }
4c515dd47ab41 (David Howells 2009-04-03 16:42:37 +0100 417) EXPORT_SYMBOL(fscache_withdraw_cache);