aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fscache/Makefile1
-rw-r--r--fs/fscache/cache.c166
-rw-r--r--fs/fscache/internal.h20
-rw-r--r--include/linux/fscache.h9
4 files changed, 195 insertions, 1 deletions
diff --git a/fs/fscache/Makefile b/fs/fscache/Makefile
index bc1f3b9d811a..556708bb9796 100644
--- a/fs/fscache/Makefile
+++ b/fs/fscache/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5fscache-y := \ 5fscache-y := \
6 cache.o \
6 fsdef.o \ 7 fsdef.o \
7 main.o 8 main.o
8 9
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c
new file mode 100644
index 000000000000..1a28df36dd93
--- /dev/null
+++ b/fs/fscache/cache.c
@@ -0,0 +1,166 @@
1/* FS-Cache cache handling
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
11
12#define FSCACHE_DEBUG_LEVEL CACHE
13#include <linux/module.h>
14#include <linux/slab.h>
15#include "internal.h"
16
17LIST_HEAD(fscache_cache_list);
18DECLARE_RWSEM(fscache_addremove_sem);
19
20static LIST_HEAD(fscache_cache_tag_list);
21
22/*
23 * look up a cache tag
24 */
25struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
26{
27 struct fscache_cache_tag *tag, *xtag;
28
29 /* firstly check for the existence of the tag under read lock */
30 down_read(&fscache_addremove_sem);
31
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);
36 return tag;
37 }
38 }
39
40 up_read(&fscache_addremove_sem);
41
42 /* the tag does not exist - create a candidate */
43 xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
44 if (!xtag)
45 /* return a dummy tag if out of memory */
46 return ERR_PTR(-ENOMEM);
47
48 atomic_set(&xtag->usage, 1);
49 strcpy(xtag->name, name);
50
51 /* write lock, search again and add if still not present */
52 down_write(&fscache_addremove_sem);
53
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);
58 kfree(xtag);
59 return tag;
60 }
61 }
62
63 list_add_tail(&xtag->link, &fscache_cache_tag_list);
64 up_write(&fscache_addremove_sem);
65 return xtag;
66}
67
68/*
69 * release a reference to a cache tag
70 */
71void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
72{
73 if (tag != ERR_PTR(-ENOMEM)) {
74 down_write(&fscache_addremove_sem);
75
76 if (atomic_dec_and_test(&tag->usage))
77 list_del_init(&tag->link);
78 else
79 tag = NULL;
80
81 up_write(&fscache_addremove_sem);
82
83 kfree(tag);
84 }
85}
86
87/*
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
91 */
92struct fscache_cache *fscache_select_cache_for_object(
93 struct fscache_cookie *cookie)
94{
95 struct fscache_cache_tag *tag;
96 struct fscache_object *object;
97 struct fscache_cache *cache;
98
99 _enter("");
100
101 if (list_empty(&fscache_cache_list)) {
102 _leave(" = NULL [no cache]");
103 return NULL;
104 }
105
106 /* we check the parent to determine the cache to use */
107 spin_lock(&cookie->lock);
108
109 /* the first in the parent's backing list should be the preferred
110 * cache */
111 if (!hlist_empty(&cookie->backing_objects)) {
112 object = hlist_entry(cookie->backing_objects.first,
113 struct fscache_object, cookie_link);
114
115 cache = object->cache;
116 if (object->state >= FSCACHE_OBJECT_DYING ||
117 test_bit(FSCACHE_IOERROR, &cache->flags))
118 cache = NULL;
119
120 spin_unlock(&cookie->lock);
121 _leave(" = %p [parent]", cache);
122 return cache;
123 }
124
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]");
130 return NULL;
131 }
132
133 spin_unlock(&cookie->lock);
134
135 if (!cookie->def->select_cache)
136 goto no_preference;
137
138 /* ask the netfs for its preference */
139 tag = cookie->def->select_cache(cookie->parent->netfs_data,
140 cookie->netfs_data);
141 if (!tag)
142 goto no_preference;
143
144 if (tag == ERR_PTR(-ENOMEM)) {
145 _leave(" = NULL [nomem tag]");
146 return NULL;
147 }
148
149 if (!tag->cache) {
150 _leave(" = NULL [unbacked tag]");
151 return NULL;
152 }
153
154 if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
155 return NULL;
156
157 _leave(" = %p [specific]", tag->cache);
158 return tag->cache;
159
160no_preference:
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);
165 return cache;
166}
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index 4113af8d1660..0a2069afa417 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -28,6 +28,15 @@
28#define FSCACHE_MAX_THREADS 32 28#define FSCACHE_MAX_THREADS 32
29 29
30/* 30/*
31 * fsc-cache.c
32 */
33extern struct list_head fscache_cache_list;
34extern struct rw_semaphore fscache_addremove_sem;
35
36extern struct fscache_cache *fscache_select_cache_for_object(
37 struct fscache_cookie *);
38
39/*
31 * fsc-fsdef.c 40 * fsc-fsdef.c
32 */ 41 */
33extern struct fscache_cookie fscache_fsdef_index; 42extern struct fscache_cookie fscache_fsdef_index;
@@ -168,6 +177,17 @@ extern const struct file_operations fscache_stats_fops;
168#define fscache_stat(stat) do {} while (0) 177#define fscache_stat(stat) do {} while (0)
169#endif 178#endif
170 179
180/*
181 * raise an event on an object
182 * - if the event is not masked for that object, then the object is
183 * queued for attention by the thread pool.
184 */
185static inline void fscache_raise_event(struct fscache_object *object,
186 unsigned event)
187{
188 BUG(); // TODO
189}
190
171/*****************************************************************************/ 191/*****************************************************************************/
172/* 192/*
173 * debug tracing 193 * debug tracing
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index feb3b0e0af4d..9584c094d69f 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -173,6 +173,8 @@ struct fscache_netfs {
173 * - these are undefined symbols when FS-Cache is not configured and the 173 * - these are undefined symbols when FS-Cache is not configured and the
174 * optimiser takes care of not using them 174 * optimiser takes care of not using them
175 */ 175 */
176extern struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *);
177extern void __fscache_release_cache_tag(struct fscache_cache_tag *);
176 178
177/** 179/**
178 * fscache_register_netfs - Register a filesystem as desiring caching services 180 * fscache_register_netfs - Register a filesystem as desiring caching services
@@ -218,7 +220,10 @@ void fscache_unregister_netfs(struct fscache_netfs *netfs)
218static inline 220static inline
219struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name) 221struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name)
220{ 222{
221 return NULL; 223 if (fscache_available())
224 return __fscache_lookup_cache_tag(name);
225 else
226 return NULL;
222} 227}
223 228
224/** 229/**
@@ -233,6 +238,8 @@ struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name)
233static inline 238static inline
234void fscache_release_cache_tag(struct fscache_cache_tag *tag) 239void fscache_release_cache_tag(struct fscache_cache_tag *tag)
235{ 240{
241 if (fscache_available())
242 __fscache_release_cache_tag(tag);
236} 243}
237 244
238/** 245/**