root/fs/fscache/cache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __fscache_lookup_cache_tag
  2. __fscache_release_cache_tag
  3. fscache_select_cache_for_object
  4. fscache_init_cache
  5. fscache_add_cache
  6. fscache_io_error
  7. fscache_withdraw_all_objects
  8. fscache_withdraw_cache

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

/* [<][>][^][v][top][bottom][index][help] */