vfs: add helpers to get root and pwd
[linux-2.6.git] / fs / cachefiles / interface.c
1 /* FS-Cache interface to CacheFiles
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 Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11
12 #include <linux/slab.h>
13 #include <linux/mount.h>
14 #include <linux/buffer_head.h>
15 #include "internal.h"
16
17 #define list_to_page(head) (list_entry((head)->prev, struct page, lru))
18
19 struct cachefiles_lookup_data {
20         struct cachefiles_xattr *auxdata;       /* auxiliary data */
21         char                    *key;           /* key path */
22 };
23
24 static int cachefiles_attr_changed(struct fscache_object *_object);
25
26 /*
27  * allocate an object record for a cookie lookup and prepare the lookup data
28  */
29 static struct fscache_object *cachefiles_alloc_object(
30         struct fscache_cache *_cache,
31         struct fscache_cookie *cookie)
32 {
33         struct cachefiles_lookup_data *lookup_data;
34         struct cachefiles_object *object;
35         struct cachefiles_cache *cache;
36         struct cachefiles_xattr *auxdata;
37         unsigned keylen, auxlen;
38         void *buffer;
39         char *key;
40
41         cache = container_of(_cache, struct cachefiles_cache, cache);
42
43         _enter("{%s},%p,", cache->cache.identifier, cookie);
44
45         lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL);
46         if (!lookup_data)
47                 goto nomem_lookup_data;
48
49         /* create a new object record and a temporary leaf image */
50         object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
51         if (!object)
52                 goto nomem_object;
53
54         ASSERTCMP(object->backer, ==, NULL);
55
56         BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
57         atomic_set(&object->usage, 1);
58
59         fscache_object_init(&object->fscache, cookie, &cache->cache);
60
61         object->type = cookie->def->type;
62
63         /* get hold of the raw key
64          * - stick the length on the front and leave space on the back for the
65          *   encoder
66          */
67         buffer = kmalloc((2 + 512) + 3, GFP_KERNEL);
68         if (!buffer)
69                 goto nomem_buffer;
70
71         keylen = cookie->def->get_key(cookie->netfs_data, buffer + 2, 512);
72         ASSERTCMP(keylen, <, 512);
73
74         *(uint16_t *)buffer = keylen;
75         ((char *)buffer)[keylen + 2] = 0;
76         ((char *)buffer)[keylen + 3] = 0;
77         ((char *)buffer)[keylen + 4] = 0;
78
79         /* turn the raw key into something that can work with as a filename */
80         key = cachefiles_cook_key(buffer, keylen + 2, object->type);
81         if (!key)
82                 goto nomem_key;
83
84         /* get hold of the auxiliary data and prepend the object type */
85         auxdata = buffer;
86         auxlen = 0;
87         if (cookie->def->get_aux) {
88                 auxlen = cookie->def->get_aux(cookie->netfs_data,
89                                               auxdata->data, 511);
90                 ASSERTCMP(auxlen, <, 511);
91         }
92
93         auxdata->len = auxlen + 1;
94         auxdata->type = cookie->def->type;
95
96         lookup_data->auxdata = auxdata;
97         lookup_data->key = key;
98         object->lookup_data = lookup_data;
99
100         _leave(" = %p [%p]", &object->fscache, lookup_data);
101         return &object->fscache;
102
103 nomem_key:
104         kfree(buffer);
105 nomem_buffer:
106         BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
107         kmem_cache_free(cachefiles_object_jar, object);
108         fscache_object_destroyed(&cache->cache);
109 nomem_object:
110         kfree(lookup_data);
111 nomem_lookup_data:
112         _leave(" = -ENOMEM");
113         return ERR_PTR(-ENOMEM);
114 }
115
116 /*
117  * attempt to look up the nominated node in this cache
118  * - return -ETIMEDOUT to be scheduled again
119  */
120 static int cachefiles_lookup_object(struct fscache_object *_object)
121 {
122         struct cachefiles_lookup_data *lookup_data;
123         struct cachefiles_object *parent, *object;
124         struct cachefiles_cache *cache;
125         const struct cred *saved_cred;
126         int ret;
127
128         _enter("{OBJ%x}", _object->debug_id);
129
130         cache = container_of(_object->cache, struct cachefiles_cache, cache);
131         parent = container_of(_object->parent,
132                               struct cachefiles_object, fscache);
133         object = container_of(_object, struct cachefiles_object, fscache);
134         lookup_data = object->lookup_data;
135
136         ASSERTCMP(lookup_data, !=, NULL);
137
138         /* look up the key, creating any missing bits */
139         cachefiles_begin_secure(cache, &saved_cred);
140         ret = cachefiles_walk_to_object(parent, object,
141                                         lookup_data->key,
142                                         lookup_data->auxdata);
143         cachefiles_end_secure(cache, saved_cred);
144
145         /* polish off by setting the attributes of non-index files */
146         if (ret == 0 &&
147             object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
148                 cachefiles_attr_changed(&object->fscache);
149
150         if (ret < 0 && ret != -ETIMEDOUT) {
151                 if (ret != -ENOBUFS)
152                         printk(KERN_WARNING
153                                "CacheFiles: Lookup failed error %d\n", ret);
154                 fscache_object_lookup_error(&object->fscache);
155         }
156
157         _leave(" [%d]", ret);
158         return ret;
159 }
160
161 /*
162  * indication of lookup completion
163  */
164 static void cachefiles_lookup_complete(struct fscache_object *_object)
165 {
166         struct cachefiles_object *object;
167
168         object = container_of(_object, struct cachefiles_object, fscache);
169
170         _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data);
171
172         if (object->lookup_data) {
173                 kfree(object->lookup_data->key);
174                 kfree(object->lookup_data->auxdata);
175                 kfree(object->lookup_data);
176                 object->lookup_data = NULL;
177         }
178 }
179
180 /*
181  * increment the usage count on an inode object (may fail if unmounting)
182  */
183 static
184 struct fscache_object *cachefiles_grab_object(struct fscache_object *_object)
185 {
186         struct cachefiles_object *object =
187                 container_of(_object, struct cachefiles_object, fscache);
188
189         _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage));
190
191 #ifdef CACHEFILES_DEBUG_SLAB
192         ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
193 #endif
194
195         atomic_inc(&object->usage);
196         return &object->fscache;
197 }
198
199 /*
200  * update the auxilliary data for an object object on disk
201  */
202 static void cachefiles_update_object(struct fscache_object *_object)
203 {
204         struct cachefiles_object *object;
205         struct cachefiles_xattr *auxdata;
206         struct cachefiles_cache *cache;
207         struct fscache_cookie *cookie;
208         const struct cred *saved_cred;
209         unsigned auxlen;
210
211         _enter("{OBJ%x}", _object->debug_id);
212
213         object = container_of(_object, struct cachefiles_object, fscache);
214         cache = container_of(object->fscache.cache, struct cachefiles_cache,
215                              cache);
216         cookie = object->fscache.cookie;
217
218         if (!cookie->def->get_aux) {
219                 _leave(" [no aux]");
220                 return;
221         }
222
223         auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL);
224         if (!auxdata) {
225                 _leave(" [nomem]");
226                 return;
227         }
228
229         auxlen = cookie->def->get_aux(cookie->netfs_data, auxdata->data, 511);
230         ASSERTCMP(auxlen, <, 511);
231
232         auxdata->len = auxlen + 1;
233         auxdata->type = cookie->def->type;
234
235         cachefiles_begin_secure(cache, &saved_cred);
236         cachefiles_update_object_xattr(object, auxdata);
237         cachefiles_end_secure(cache, saved_cred);
238         kfree(auxdata);
239         _leave("");
240 }
241
242 /*
243  * discard the resources pinned by an object and effect retirement if
244  * requested
245  */
246 static void cachefiles_drop_object(struct fscache_object *_object)
247 {
248         struct cachefiles_object *object;
249         struct cachefiles_cache *cache;
250         const struct cred *saved_cred;
251
252         ASSERT(_object);
253
254         object = container_of(_object, struct cachefiles_object, fscache);
255
256         _enter("{OBJ%x,%d}",
257                object->fscache.debug_id, atomic_read(&object->usage));
258
259         cache = container_of(object->fscache.cache,
260                              struct cachefiles_cache, cache);
261
262 #ifdef CACHEFILES_DEBUG_SLAB
263         ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
264 #endif
265
266         /* delete retired objects */
267         if (object->fscache.state == FSCACHE_OBJECT_RECYCLING &&
268             _object != cache->cache.fsdef
269             ) {
270                 _debug("- retire object OBJ%x", object->fscache.debug_id);
271                 cachefiles_begin_secure(cache, &saved_cred);
272                 cachefiles_delete_object(cache, object);
273                 cachefiles_end_secure(cache, saved_cred);
274         }
275
276         /* close the filesystem stuff attached to the object */
277         if (object->backer != object->dentry)
278                 dput(object->backer);
279         object->backer = NULL;
280
281         /* note that the object is now inactive */
282         if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {
283                 write_lock(&cache->active_lock);
284                 if (!test_and_clear_bit(CACHEFILES_OBJECT_ACTIVE,
285                                         &object->flags))
286                         BUG();
287                 rb_erase(&object->active_node, &cache->active_nodes);
288                 wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
289                 write_unlock(&cache->active_lock);
290         }
291
292         dput(object->dentry);
293         object->dentry = NULL;
294
295         _leave("");
296 }
297
298 /*
299  * dispose of a reference to an object
300  */
301 static void cachefiles_put_object(struct fscache_object *_object)
302 {
303         struct cachefiles_object *object;
304         struct fscache_cache *cache;
305
306         ASSERT(_object);
307
308         object = container_of(_object, struct cachefiles_object, fscache);
309
310         _enter("{OBJ%x,%d}",
311                object->fscache.debug_id, atomic_read(&object->usage));
312
313 #ifdef CACHEFILES_DEBUG_SLAB
314         ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
315 #endif
316
317         ASSERTIFCMP(object->fscache.parent,
318                     object->fscache.parent->n_children, >, 0);
319
320         if (atomic_dec_and_test(&object->usage)) {
321                 _debug("- kill object OBJ%x", object->fscache.debug_id);
322
323                 ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
324                 ASSERTCMP(object->fscache.parent, ==, NULL);
325                 ASSERTCMP(object->backer, ==, NULL);
326                 ASSERTCMP(object->dentry, ==, NULL);
327                 ASSERTCMP(object->fscache.n_ops, ==, 0);
328                 ASSERTCMP(object->fscache.n_children, ==, 0);
329
330                 if (object->lookup_data) {
331                         kfree(object->lookup_data->key);
332                         kfree(object->lookup_data->auxdata);
333                         kfree(object->lookup_data);
334                         object->lookup_data = NULL;
335                 }
336
337                 cache = object->fscache.cache;
338                 fscache_object_destroy(&object->fscache);
339                 kmem_cache_free(cachefiles_object_jar, object);
340                 fscache_object_destroyed(cache);
341         }
342
343         _leave("");
344 }
345
346 /*
347  * sync a cache
348  */
349 static void cachefiles_sync_cache(struct fscache_cache *_cache)
350 {
351         struct cachefiles_cache *cache;
352         const struct cred *saved_cred;
353         int ret;
354
355         _enter("%p", _cache);
356
357         cache = container_of(_cache, struct cachefiles_cache, cache);
358
359         /* make sure all pages pinned by operations on behalf of the netfs are
360          * written to disc */
361         cachefiles_begin_secure(cache, &saved_cred);
362         down_read(&cache->mnt->mnt_sb->s_umount);
363         ret = sync_filesystem(cache->mnt->mnt_sb);
364         up_read(&cache->mnt->mnt_sb->s_umount);
365         cachefiles_end_secure(cache, saved_cred);
366
367         if (ret == -EIO)
368                 cachefiles_io_error(cache,
369                                     "Attempt to sync backing fs superblock"
370                                     " returned error %d",
371                                     ret);
372 }
373
374 /*
375  * notification the attributes on an object have changed
376  * - called with reads/writes excluded by FS-Cache
377  */
378 static int cachefiles_attr_changed(struct fscache_object *_object)
379 {
380         struct cachefiles_object *object;
381         struct cachefiles_cache *cache;
382         const struct cred *saved_cred;
383         struct iattr newattrs;
384         uint64_t ni_size;
385         loff_t oi_size;
386         int ret;
387
388         _object->cookie->def->get_attr(_object->cookie->netfs_data, &ni_size);
389
390         _enter("{OBJ%x},[%llu]",
391                _object->debug_id, (unsigned long long) ni_size);
392
393         object = container_of(_object, struct cachefiles_object, fscache);
394         cache = container_of(object->fscache.cache,
395                              struct cachefiles_cache, cache);
396
397         if (ni_size == object->i_size)
398                 return 0;
399
400         if (!object->backer)
401                 return -ENOBUFS;
402
403         ASSERT(S_ISREG(object->backer->d_inode->i_mode));
404
405         fscache_set_store_limit(&object->fscache, ni_size);
406
407         oi_size = i_size_read(object->backer->d_inode);
408         if (oi_size == ni_size)
409                 return 0;
410
411         cachefiles_begin_secure(cache, &saved_cred);
412         mutex_lock(&object->backer->d_inode->i_mutex);
413
414         /* if there's an extension to a partial page at the end of the backing
415          * file, we need to discard the partial page so that we pick up new
416          * data after it */
417         if (oi_size & ~PAGE_MASK && ni_size > oi_size) {
418                 _debug("discard tail %llx", oi_size);
419                 newattrs.ia_valid = ATTR_SIZE;
420                 newattrs.ia_size = oi_size & PAGE_MASK;
421                 ret = notify_change(object->backer, &newattrs);
422                 if (ret < 0)
423                         goto truncate_failed;
424         }
425
426         newattrs.ia_valid = ATTR_SIZE;
427         newattrs.ia_size = ni_size;
428         ret = notify_change(object->backer, &newattrs);
429
430 truncate_failed:
431         mutex_unlock(&object->backer->d_inode->i_mutex);
432         cachefiles_end_secure(cache, saved_cred);
433
434         if (ret == -EIO) {
435                 fscache_set_store_limit(&object->fscache, 0);
436                 cachefiles_io_error_obj(object, "Size set failed");
437                 ret = -ENOBUFS;
438         }
439
440         _leave(" = %d", ret);
441         return ret;
442 }
443
444 /*
445  * dissociate a cache from all the pages it was backing
446  */
447 static void cachefiles_dissociate_pages(struct fscache_cache *cache)
448 {
449         _enter("");
450 }
451
452 const struct fscache_cache_ops cachefiles_cache_ops = {
453         .name                   = "cachefiles",
454         .alloc_object           = cachefiles_alloc_object,
455         .lookup_object          = cachefiles_lookup_object,
456         .lookup_complete        = cachefiles_lookup_complete,
457         .grab_object            = cachefiles_grab_object,
458         .update_object          = cachefiles_update_object,
459         .drop_object            = cachefiles_drop_object,
460         .put_object             = cachefiles_put_object,
461         .sync_cache             = cachefiles_sync_cache,
462         .attr_changed           = cachefiles_attr_changed,
463         .read_or_alloc_page     = cachefiles_read_or_alloc_page,
464         .read_or_alloc_pages    = cachefiles_read_or_alloc_pages,
465         .allocate_page          = cachefiles_allocate_page,
466         .allocate_pages         = cachefiles_allocate_pages,
467         .write_page             = cachefiles_write_page,
468         .uncache_page           = cachefiles_uncache_page,
469         .dissociate_pages       = cachefiles_dissociate_pages,
470 };