blob: 432482edc738b9717711c100ecd3f1ccf9e34282 [file] [log] [blame]
David Howells955d00912009-04-03 16:42:38 +01001/* netfs cookie management
2 *
3 * Copyright (C) 2004-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.
David Howellsccc4fc32009-04-03 16:42:38 +010010 *
11 * See Documentation/filesystems/caching/netfs-api.txt for more information on
12 * the netfs API.
David Howells955d00912009-04-03 16:42:38 +010013 */
14
15#define FSCACHE_DEBUG_LEVEL COOKIE
16#include <linux/module.h>
17#include <linux/slab.h>
18#include "internal.h"
19
20struct kmem_cache *fscache_cookie_jar;
21
David Howellsccc4fc32009-04-03 16:42:38 +010022static atomic_t fscache_object_debug_id = ATOMIC_INIT(0);
23
24static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie);
25static int fscache_alloc_object(struct fscache_cache *cache,
26 struct fscache_cookie *cookie);
27static int fscache_attach_object(struct fscache_cookie *cookie,
28 struct fscache_object *object);
29
David Howells955d00912009-04-03 16:42:38 +010030/*
31 * initialise an cookie jar slab element prior to any use
32 */
33void fscache_cookie_init_once(void *_cookie)
34{
35 struct fscache_cookie *cookie = _cookie;
36
37 memset(cookie, 0, sizeof(*cookie));
38 spin_lock_init(&cookie->lock);
39 INIT_HLIST_HEAD(&cookie->backing_objects);
40}
41
42/*
David Howellsccc4fc32009-04-03 16:42:38 +010043 * request a cookie to represent an object (index, datafile, xattr, etc)
44 * - parent specifies the parent object
45 * - the top level index cookie for each netfs is stored in the fscache_netfs
46 * struct upon registration
47 * - def points to the definition
48 * - the netfs_data will be passed to the functions pointed to in *def
49 * - all attached caches will be searched to see if they contain this object
50 * - index objects aren't stored on disk until there's a dependent file that
51 * needs storing
52 * - other objects are stored in a selected cache immediately, and all the
53 * indices forming the path to it are instantiated if necessary
54 * - we never let on to the netfs about errors
55 * - we may set a negative cookie pointer, but that's okay
56 */
57struct fscache_cookie *__fscache_acquire_cookie(
58 struct fscache_cookie *parent,
59 const struct fscache_cookie_def *def,
60 void *netfs_data)
61{
62 struct fscache_cookie *cookie;
63
64 BUG_ON(!def);
65
66 _enter("{%s},{%s},%p",
67 parent ? (char *) parent->def->name : "<no-parent>",
68 def->name, netfs_data);
69
70 fscache_stat(&fscache_n_acquires);
71
72 /* if there's no parent cookie, then we don't create one here either */
73 if (!parent) {
74 fscache_stat(&fscache_n_acquires_null);
75 _leave(" [no parent]");
76 return NULL;
77 }
78
79 /* validate the definition */
80 BUG_ON(!def->get_key);
81 BUG_ON(!def->name[0]);
82
83 BUG_ON(def->type == FSCACHE_COOKIE_TYPE_INDEX &&
84 parent->def->type != FSCACHE_COOKIE_TYPE_INDEX);
85
86 /* allocate and initialise a cookie */
87 cookie = kmem_cache_alloc(fscache_cookie_jar, GFP_KERNEL);
88 if (!cookie) {
89 fscache_stat(&fscache_n_acquires_oom);
90 _leave(" [ENOMEM]");
91 return NULL;
92 }
93
94 atomic_set(&cookie->usage, 1);
95 atomic_set(&cookie->n_children, 0);
96
97 atomic_inc(&parent->usage);
98 atomic_inc(&parent->n_children);
99
100 cookie->def = def;
101 cookie->parent = parent;
102 cookie->netfs_data = netfs_data;
103 cookie->flags = 0;
104
105 INIT_RADIX_TREE(&cookie->stores, GFP_NOFS);
106
107 switch (cookie->def->type) {
108 case FSCACHE_COOKIE_TYPE_INDEX:
109 fscache_stat(&fscache_n_cookie_index);
110 break;
111 case FSCACHE_COOKIE_TYPE_DATAFILE:
112 fscache_stat(&fscache_n_cookie_data);
113 break;
114 default:
115 fscache_stat(&fscache_n_cookie_special);
116 break;
117 }
118
119 /* if the object is an index then we need do nothing more here - we
120 * create indices on disk when we need them as an index may exist in
121 * multiple caches */
122 if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
123 if (fscache_acquire_non_index_cookie(cookie) < 0) {
124 atomic_dec(&parent->n_children);
125 __fscache_cookie_put(cookie);
126 fscache_stat(&fscache_n_acquires_nobufs);
127 _leave(" = NULL");
128 return NULL;
129 }
130 }
131
132 fscache_stat(&fscache_n_acquires_ok);
133 _leave(" = %p", cookie);
134 return cookie;
135}
136EXPORT_SYMBOL(__fscache_acquire_cookie);
137
138/*
139 * acquire a non-index cookie
140 * - this must make sure the index chain is instantiated and instantiate the
141 * object representation too
142 */
143static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie)
144{
145 struct fscache_object *object;
146 struct fscache_cache *cache;
147 uint64_t i_size;
148 int ret;
149
150 _enter("");
151
152 cookie->flags = 1 << FSCACHE_COOKIE_UNAVAILABLE;
153
154 /* now we need to see whether the backing objects for this cookie yet
155 * exist, if not there'll be nothing to search */
156 down_read(&fscache_addremove_sem);
157
158 if (list_empty(&fscache_cache_list)) {
159 up_read(&fscache_addremove_sem);
160 _leave(" = 0 [no caches]");
161 return 0;
162 }
163
164 /* select a cache in which to store the object */
165 cache = fscache_select_cache_for_object(cookie->parent);
166 if (!cache) {
167 up_read(&fscache_addremove_sem);
168 fscache_stat(&fscache_n_acquires_no_cache);
169 _leave(" = -ENOMEDIUM [no cache]");
170 return -ENOMEDIUM;
171 }
172
173 _debug("cache %s", cache->tag->name);
174
175 cookie->flags =
176 (1 << FSCACHE_COOKIE_LOOKING_UP) |
177 (1 << FSCACHE_COOKIE_CREATING) |
178 (1 << FSCACHE_COOKIE_NO_DATA_YET);
179
180 /* ask the cache to allocate objects for this cookie and its parent
181 * chain */
182 ret = fscache_alloc_object(cache, cookie);
183 if (ret < 0) {
184 up_read(&fscache_addremove_sem);
185 _leave(" = %d", ret);
186 return ret;
187 }
188
189 /* pass on how big the object we're caching is supposed to be */
190 cookie->def->get_attr(cookie->netfs_data, &i_size);
191
192 spin_lock(&cookie->lock);
193 if (hlist_empty(&cookie->backing_objects)) {
194 spin_unlock(&cookie->lock);
195 goto unavailable;
196 }
197
198 object = hlist_entry(cookie->backing_objects.first,
199 struct fscache_object, cookie_link);
200
201 fscache_set_store_limit(object, i_size);
202
203 /* initiate the process of looking up all the objects in the chain
204 * (done by fscache_initialise_object()) */
205 fscache_enqueue_object(object);
206
207 spin_unlock(&cookie->lock);
208
209 /* we may be required to wait for lookup to complete at this point */
210 if (!fscache_defer_lookup) {
211 _debug("non-deferred lookup %p", &cookie->flags);
212 wait_on_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP,
213 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
214 _debug("complete");
215 if (test_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags))
216 goto unavailable;
217 }
218
219 up_read(&fscache_addremove_sem);
220 _leave(" = 0 [deferred]");
221 return 0;
222
223unavailable:
224 up_read(&fscache_addremove_sem);
225 _leave(" = -ENOBUFS");
226 return -ENOBUFS;
227}
228
229/*
230 * recursively allocate cache object records for a cookie/cache combination
231 * - caller must be holding the addremove sem
232 */
233static int fscache_alloc_object(struct fscache_cache *cache,
234 struct fscache_cookie *cookie)
235{
236 struct fscache_object *object;
237 struct hlist_node *_n;
238 int ret;
239
240 _enter("%p,%p{%s}", cache, cookie, cookie->def->name);
241
242 spin_lock(&cookie->lock);
243 hlist_for_each_entry(object, _n, &cookie->backing_objects,
244 cookie_link) {
245 if (object->cache == cache)
246 goto object_already_extant;
247 }
248 spin_unlock(&cookie->lock);
249
250 /* ask the cache to allocate an object (we may end up with duplicate
251 * objects at this stage, but we sort that out later) */
David Howells52bd75f2009-11-19 18:11:08 +0000252 fscache_stat(&fscache_n_cop_alloc_object);
David Howellsccc4fc32009-04-03 16:42:38 +0100253 object = cache->ops->alloc_object(cache, cookie);
David Howells52bd75f2009-11-19 18:11:08 +0000254 fscache_stat_d(&fscache_n_cop_alloc_object);
David Howellsccc4fc32009-04-03 16:42:38 +0100255 if (IS_ERR(object)) {
256 fscache_stat(&fscache_n_object_no_alloc);
257 ret = PTR_ERR(object);
258 goto error;
259 }
260
261 fscache_stat(&fscache_n_object_alloc);
262
263 object->debug_id = atomic_inc_return(&fscache_object_debug_id);
264
265 _debug("ALLOC OBJ%x: %s {%lx}",
266 object->debug_id, cookie->def->name, object->events);
267
268 ret = fscache_alloc_object(cache, cookie->parent);
269 if (ret < 0)
270 goto error_put;
271
272 /* only attach if we managed to allocate all we needed, otherwise
273 * discard the object we just allocated and instead use the one
274 * attached to the cookie */
David Howells52bd75f2009-11-19 18:11:08 +0000275 if (fscache_attach_object(cookie, object) < 0) {
276 fscache_stat(&fscache_n_cop_put_object);
David Howellsccc4fc32009-04-03 16:42:38 +0100277 cache->ops->put_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000278 fscache_stat_d(&fscache_n_cop_put_object);
279 }
David Howellsccc4fc32009-04-03 16:42:38 +0100280
281 _leave(" = 0");
282 return 0;
283
284object_already_extant:
285 ret = -ENOBUFS;
286 if (object->state >= FSCACHE_OBJECT_DYING) {
287 spin_unlock(&cookie->lock);
288 goto error;
289 }
290 spin_unlock(&cookie->lock);
291 _leave(" = 0 [found]");
292 return 0;
293
294error_put:
David Howells52bd75f2009-11-19 18:11:08 +0000295 fscache_stat(&fscache_n_cop_put_object);
David Howellsccc4fc32009-04-03 16:42:38 +0100296 cache->ops->put_object(object);
David Howells52bd75f2009-11-19 18:11:08 +0000297 fscache_stat_d(&fscache_n_cop_put_object);
David Howellsccc4fc32009-04-03 16:42:38 +0100298error:
299 _leave(" = %d", ret);
300 return ret;
301}
302
303/*
304 * attach a cache object to a cookie
305 */
306static int fscache_attach_object(struct fscache_cookie *cookie,
307 struct fscache_object *object)
308{
309 struct fscache_object *p;
310 struct fscache_cache *cache = object->cache;
311 struct hlist_node *_n;
312 int ret;
313
314 _enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id);
315
316 spin_lock(&cookie->lock);
317
318 /* there may be multiple initial creations of this object, but we only
319 * want one */
320 ret = -EEXIST;
321 hlist_for_each_entry(p, _n, &cookie->backing_objects, cookie_link) {
322 if (p->cache == object->cache) {
323 if (p->state >= FSCACHE_OBJECT_DYING)
324 ret = -ENOBUFS;
325 goto cant_attach_object;
326 }
327 }
328
329 /* pin the parent object */
330 spin_lock_nested(&cookie->parent->lock, 1);
331 hlist_for_each_entry(p, _n, &cookie->parent->backing_objects,
332 cookie_link) {
333 if (p->cache == object->cache) {
334 if (p->state >= FSCACHE_OBJECT_DYING) {
335 ret = -ENOBUFS;
336 spin_unlock(&cookie->parent->lock);
337 goto cant_attach_object;
338 }
339 object->parent = p;
340 spin_lock(&p->lock);
341 p->n_children++;
342 spin_unlock(&p->lock);
343 break;
344 }
345 }
346 spin_unlock(&cookie->parent->lock);
347
348 /* attach to the cache's object list */
349 if (list_empty(&object->cache_link)) {
350 spin_lock(&cache->object_list_lock);
351 list_add(&object->cache_link, &cache->object_list);
352 spin_unlock(&cache->object_list_lock);
353 }
354
355 /* attach to the cookie */
356 object->cookie = cookie;
357 atomic_inc(&cookie->usage);
358 hlist_add_head(&object->cookie_link, &cookie->backing_objects);
David Howells4fbf4292009-11-19 18:11:04 +0000359
360 fscache_objlist_add(object);
David Howellsccc4fc32009-04-03 16:42:38 +0100361 ret = 0;
362
363cant_attach_object:
364 spin_unlock(&cookie->lock);
365 _leave(" = %d", ret);
366 return ret;
367}
368
369/*
370 * update the index entries backing a cookie
371 */
372void __fscache_update_cookie(struct fscache_cookie *cookie)
373{
374 struct fscache_object *object;
375 struct hlist_node *_p;
376
377 fscache_stat(&fscache_n_updates);
378
379 if (!cookie) {
380 fscache_stat(&fscache_n_updates_null);
381 _leave(" [no cookie]");
382 return;
383 }
384
385 _enter("{%s}", cookie->def->name);
386
387 BUG_ON(!cookie->def->get_aux);
388
389 spin_lock(&cookie->lock);
390
391 /* update the index entry on disk in each cache backing this cookie */
392 hlist_for_each_entry(object, _p,
393 &cookie->backing_objects, cookie_link) {
394 fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
395 }
396
397 spin_unlock(&cookie->lock);
398 _leave("");
399}
400EXPORT_SYMBOL(__fscache_update_cookie);
401
402/*
403 * release a cookie back to the cache
404 * - the object will be marked as recyclable on disk if retire is true
405 * - all dependents of this cookie must have already been unregistered
406 * (indices/files/pages)
407 */
408void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
409{
410 struct fscache_cache *cache;
411 struct fscache_object *object;
412 unsigned long event;
413
414 fscache_stat(&fscache_n_relinquishes);
415
416 if (!cookie) {
417 fscache_stat(&fscache_n_relinquishes_null);
418 _leave(" [no cookie]");
419 return;
420 }
421
422 _enter("%p{%s,%p},%d",
423 cookie, cookie->def->name, cookie->netfs_data, retire);
424
425 if (atomic_read(&cookie->n_children) != 0) {
426 printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n",
427 cookie->def->name);
428 BUG();
429 }
430
431 /* wait for the cookie to finish being instantiated (or to fail) */
432 if (test_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) {
433 fscache_stat(&fscache_n_relinquishes_waitcrt);
434 wait_on_bit(&cookie->flags, FSCACHE_COOKIE_CREATING,
435 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
436 }
437
438 event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE;
439
440 /* detach pointers back to the netfs */
441 spin_lock(&cookie->lock);
442
443 cookie->netfs_data = NULL;
444 cookie->def = NULL;
445
446 /* break links with all the active objects */
447 while (!hlist_empty(&cookie->backing_objects)) {
448 object = hlist_entry(cookie->backing_objects.first,
449 struct fscache_object,
450 cookie_link);
451
452 _debug("RELEASE OBJ%x", object->debug_id);
453
454 /* detach each cache object from the object cookie */
455 spin_lock(&object->lock);
456 hlist_del_init(&object->cookie_link);
457
458 cache = object->cache;
459 object->cookie = NULL;
460 fscache_raise_event(object, event);
461 spin_unlock(&object->lock);
462
463 if (atomic_dec_and_test(&cookie->usage))
464 /* the cookie refcount shouldn't be reduced to 0 yet */
465 BUG();
466 }
467
468 spin_unlock(&cookie->lock);
469
470 if (cookie->parent) {
471 ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0);
472 ASSERTCMP(atomic_read(&cookie->parent->n_children), >, 0);
473 atomic_dec(&cookie->parent->n_children);
474 }
475
476 /* finally dispose of the cookie */
477 ASSERTCMP(atomic_read(&cookie->usage), >, 0);
478 fscache_cookie_put(cookie);
479
480 _leave("");
481}
482EXPORT_SYMBOL(__fscache_relinquish_cookie);
483
484/*
David Howells955d00912009-04-03 16:42:38 +0100485 * destroy a cookie
486 */
487void __fscache_cookie_put(struct fscache_cookie *cookie)
488{
489 struct fscache_cookie *parent;
490
491 _enter("%p", cookie);
492
493 for (;;) {
494 _debug("FREE COOKIE %p", cookie);
495 parent = cookie->parent;
496 BUG_ON(!hlist_empty(&cookie->backing_objects));
497 kmem_cache_free(fscache_cookie_jar, cookie);
498
499 if (!parent)
500 break;
501
502 cookie = parent;
503 BUG_ON(atomic_read(&cookie->usage) <= 0);
504 if (!atomic_dec_and_test(&cookie->usage))
505 break;
506 }
507
508 _leave("");
509}