FS-Cache: Implement the cookie management part of the netfs API
[linux-2.6.git] / fs / fscache / cookie.c
1 /* 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.
10  *
11  * See Documentation/filesystems/caching/netfs-api.txt for more information on
12  * the netfs API.
13  */
14
15 #define FSCACHE_DEBUG_LEVEL COOKIE
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include "internal.h"
19
20 struct kmem_cache *fscache_cookie_jar;
21
22 static atomic_t fscache_object_debug_id = ATOMIC_INIT(0);
23
24 static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie);
25 static int fscache_alloc_object(struct fscache_cache *cache,
26                                 struct fscache_cookie *cookie);
27 static int fscache_attach_object(struct fscache_cookie *cookie,
28                                  struct fscache_object *object);
29
30 /*
31  * initialise an cookie jar slab element prior to any use
32  */
33 void 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 /*
43  * 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  */
57 struct 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 }
136 EXPORT_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  */
143 static 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
223 unavailable:
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  */
233 static 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) */
252         object = cache->ops->alloc_object(cache, cookie);
253         if (IS_ERR(object)) {
254                 fscache_stat(&fscache_n_object_no_alloc);
255                 ret = PTR_ERR(object);
256                 goto error;
257         }
258
259         fscache_stat(&fscache_n_object_alloc);
260
261         object->debug_id = atomic_inc_return(&fscache_object_debug_id);
262
263         _debug("ALLOC OBJ%x: %s {%lx}",
264                object->debug_id, cookie->def->name, object->events);
265
266         ret = fscache_alloc_object(cache, cookie->parent);
267         if (ret < 0)
268                 goto error_put;
269
270         /* only attach if we managed to allocate all we needed, otherwise
271          * discard the object we just allocated and instead use the one
272          * attached to the cookie */
273         if (fscache_attach_object(cookie, object) < 0)
274                 cache->ops->put_object(object);
275
276         _leave(" = 0");
277         return 0;
278
279 object_already_extant:
280         ret = -ENOBUFS;
281         if (object->state >= FSCACHE_OBJECT_DYING) {
282                 spin_unlock(&cookie->lock);
283                 goto error;
284         }
285         spin_unlock(&cookie->lock);
286         _leave(" = 0 [found]");
287         return 0;
288
289 error_put:
290         cache->ops->put_object(object);
291 error:
292         _leave(" = %d", ret);
293         return ret;
294 }
295
296 /*
297  * attach a cache object to a cookie
298  */
299 static int fscache_attach_object(struct fscache_cookie *cookie,
300                                  struct fscache_object *object)
301 {
302         struct fscache_object *p;
303         struct fscache_cache *cache = object->cache;
304         struct hlist_node *_n;
305         int ret;
306
307         _enter("{%s},{OBJ%x}", cookie->def->name, object->debug_id);
308
309         spin_lock(&cookie->lock);
310
311         /* there may be multiple initial creations of this object, but we only
312          * want one */
313         ret = -EEXIST;
314         hlist_for_each_entry(p, _n, &cookie->backing_objects, cookie_link) {
315                 if (p->cache == object->cache) {
316                         if (p->state >= FSCACHE_OBJECT_DYING)
317                                 ret = -ENOBUFS;
318                         goto cant_attach_object;
319                 }
320         }
321
322         /* pin the parent object */
323         spin_lock_nested(&cookie->parent->lock, 1);
324         hlist_for_each_entry(p, _n, &cookie->parent->backing_objects,
325                              cookie_link) {
326                 if (p->cache == object->cache) {
327                         if (p->state >= FSCACHE_OBJECT_DYING) {
328                                 ret = -ENOBUFS;
329                                 spin_unlock(&cookie->parent->lock);
330                                 goto cant_attach_object;
331                         }
332                         object->parent = p;
333                         spin_lock(&p->lock);
334                         p->n_children++;
335                         spin_unlock(&p->lock);
336                         break;
337                 }
338         }
339         spin_unlock(&cookie->parent->lock);
340
341         /* attach to the cache's object list */
342         if (list_empty(&object->cache_link)) {
343                 spin_lock(&cache->object_list_lock);
344                 list_add(&object->cache_link, &cache->object_list);
345                 spin_unlock(&cache->object_list_lock);
346         }
347
348         /* attach to the cookie */
349         object->cookie = cookie;
350         atomic_inc(&cookie->usage);
351         hlist_add_head(&object->cookie_link, &cookie->backing_objects);
352         ret = 0;
353
354 cant_attach_object:
355         spin_unlock(&cookie->lock);
356         _leave(" = %d", ret);
357         return ret;
358 }
359
360 /*
361  * update the index entries backing a cookie
362  */
363 void __fscache_update_cookie(struct fscache_cookie *cookie)
364 {
365         struct fscache_object *object;
366         struct hlist_node *_p;
367
368         fscache_stat(&fscache_n_updates);
369
370         if (!cookie) {
371                 fscache_stat(&fscache_n_updates_null);
372                 _leave(" [no cookie]");
373                 return;
374         }
375
376         _enter("{%s}", cookie->def->name);
377
378         BUG_ON(!cookie->def->get_aux);
379
380         spin_lock(&cookie->lock);
381
382         /* update the index entry on disk in each cache backing this cookie */
383         hlist_for_each_entry(object, _p,
384                              &cookie->backing_objects, cookie_link) {
385                 fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
386         }
387
388         spin_unlock(&cookie->lock);
389         _leave("");
390 }
391 EXPORT_SYMBOL(__fscache_update_cookie);
392
393 /*
394  * release a cookie back to the cache
395  * - the object will be marked as recyclable on disk if retire is true
396  * - all dependents of this cookie must have already been unregistered
397  *   (indices/files/pages)
398  */
399 void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
400 {
401         struct fscache_cache *cache;
402         struct fscache_object *object;
403         unsigned long event;
404
405         fscache_stat(&fscache_n_relinquishes);
406
407         if (!cookie) {
408                 fscache_stat(&fscache_n_relinquishes_null);
409                 _leave(" [no cookie]");
410                 return;
411         }
412
413         _enter("%p{%s,%p},%d",
414                cookie, cookie->def->name, cookie->netfs_data, retire);
415
416         if (atomic_read(&cookie->n_children) != 0) {
417                 printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n",
418                        cookie->def->name);
419                 BUG();
420         }
421
422         /* wait for the cookie to finish being instantiated (or to fail) */
423         if (test_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) {
424                 fscache_stat(&fscache_n_relinquishes_waitcrt);
425                 wait_on_bit(&cookie->flags, FSCACHE_COOKIE_CREATING,
426                             fscache_wait_bit, TASK_UNINTERRUPTIBLE);
427         }
428
429         event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE;
430
431         /* detach pointers back to the netfs */
432         spin_lock(&cookie->lock);
433
434         cookie->netfs_data      = NULL;
435         cookie->def             = NULL;
436
437         /* break links with all the active objects */
438         while (!hlist_empty(&cookie->backing_objects)) {
439                 object = hlist_entry(cookie->backing_objects.first,
440                                      struct fscache_object,
441                                      cookie_link);
442
443                 _debug("RELEASE OBJ%x", object->debug_id);
444
445                 /* detach each cache object from the object cookie */
446                 spin_lock(&object->lock);
447                 hlist_del_init(&object->cookie_link);
448
449                 cache = object->cache;
450                 object->cookie = NULL;
451                 fscache_raise_event(object, event);
452                 spin_unlock(&object->lock);
453
454                 if (atomic_dec_and_test(&cookie->usage))
455                         /* the cookie refcount shouldn't be reduced to 0 yet */
456                         BUG();
457         }
458
459         spin_unlock(&cookie->lock);
460
461         if (cookie->parent) {
462                 ASSERTCMP(atomic_read(&cookie->parent->usage), >, 0);
463                 ASSERTCMP(atomic_read(&cookie->parent->n_children), >, 0);
464                 atomic_dec(&cookie->parent->n_children);
465         }
466
467         /* finally dispose of the cookie */
468         ASSERTCMP(atomic_read(&cookie->usage), >, 0);
469         fscache_cookie_put(cookie);
470
471         _leave("");
472 }
473 EXPORT_SYMBOL(__fscache_relinquish_cookie);
474
475 /*
476  * destroy a cookie
477  */
478 void __fscache_cookie_put(struct fscache_cookie *cookie)
479 {
480         struct fscache_cookie *parent;
481
482         _enter("%p", cookie);
483
484         for (;;) {
485                 _debug("FREE COOKIE %p", cookie);
486                 parent = cookie->parent;
487                 BUG_ON(!hlist_empty(&cookie->backing_objects));
488                 kmem_cache_free(fscache_cookie_jar, cookie);
489
490                 if (!parent)
491                         break;
492
493                 cookie = parent;
494                 BUG_ON(atomic_read(&cookie->usage) <= 0);
495                 if (!atomic_dec_and_test(&cookie->usage))
496                         break;
497         }
498
499         _leave("");
500 }