1 /* FS-Cache cache handling
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define FSCACHE_DEBUG_LEVEL CACHE
13 #include <linux/module.h>
14 #include <linux/slab.h>
17 LIST_HEAD(fscache_cache_list);
18 DECLARE_RWSEM(fscache_addremove_sem);
20 static LIST_HEAD(fscache_cache_tag_list);
25 struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
27 struct fscache_cache_tag *tag, *xtag;
29 /* firstly check for the existence of the tag under read lock */
30 down_read(&fscache_addremove_sem);
32 list_for_each_entry(tag, &fscache_cache_tag_list, link) {
33 if (strcmp(tag->name, name) == 0) {
34 atomic_inc(&tag->usage);
35 up_read(&fscache_addremove_sem);
40 up_read(&fscache_addremove_sem);
42 /* the tag does not exist - create a candidate */
43 xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
45 /* return a dummy tag if out of memory */
46 return ERR_PTR(-ENOMEM);
48 atomic_set(&xtag->usage, 1);
49 strcpy(xtag->name, name);
51 /* write lock, search again and add if still not present */
52 down_write(&fscache_addremove_sem);
54 list_for_each_entry(tag, &fscache_cache_tag_list, link) {
55 if (strcmp(tag->name, name) == 0) {
56 atomic_inc(&tag->usage);
57 up_write(&fscache_addremove_sem);
63 list_add_tail(&xtag->link, &fscache_cache_tag_list);
64 up_write(&fscache_addremove_sem);
69 * release a reference to a cache tag
71 void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
73 if (tag != ERR_PTR(-ENOMEM)) {
74 down_write(&fscache_addremove_sem);
76 if (atomic_dec_and_test(&tag->usage))
77 list_del_init(&tag->link);
81 up_write(&fscache_addremove_sem);
88 * select a cache in which to store an object
89 * - the cache addremove semaphore must be at least read-locked by the caller
90 * - the object will never be an index
92 struct fscache_cache *fscache_select_cache_for_object(
93 struct fscache_cookie *cookie)
95 struct fscache_cache_tag *tag;
96 struct fscache_object *object;
97 struct fscache_cache *cache;
101 if (list_empty(&fscache_cache_list)) {
102 _leave(" = NULL [no cache]");
106 /* we check the parent to determine the cache to use */
107 spin_lock(&cookie->lock);
109 /* the first in the parent's backing list should be the preferred
111 if (!hlist_empty(&cookie->backing_objects)) {
112 object = hlist_entry(cookie->backing_objects.first,
113 struct fscache_object, cookie_link);
115 cache = object->cache;
116 if (object->state >= FSCACHE_OBJECT_DYING ||
117 test_bit(FSCACHE_IOERROR, &cache->flags))
120 spin_unlock(&cookie->lock);
121 _leave(" = %p [parent]", cache);
125 /* the parent is unbacked */
126 if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
127 /* cookie not an index and is unbacked */
128 spin_unlock(&cookie->lock);
129 _leave(" = NULL [cookie ub,ni]");
133 spin_unlock(&cookie->lock);
135 if (!cookie->def->select_cache)
138 /* ask the netfs for its preference */
139 tag = cookie->def->select_cache(cookie->parent->netfs_data,
144 if (tag == ERR_PTR(-ENOMEM)) {
145 _leave(" = NULL [nomem tag]");
150 _leave(" = NULL [unbacked tag]");
154 if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
157 _leave(" = %p [specific]", tag->cache);
161 /* netfs has no preference - just select first cache */
162 cache = list_entry(fscache_cache_list.next,
163 struct fscache_cache, link);
164 _leave(" = %p [first]", cache);