Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /* FS-Cache interface to CacheFiles
3 : : *
4 : : * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 : : * Written by David Howells (dhowells@redhat.com)
6 : : */
7 : :
8 : : #include <linux/slab.h>
9 : : #include <linux/mount.h>
10 : : #include "internal.h"
11 : :
12 : : struct cachefiles_lookup_data {
13 : : struct cachefiles_xattr *auxdata; /* auxiliary data */
14 : : char *key; /* key path */
15 : : };
16 : :
17 : : static int cachefiles_attr_changed(struct fscache_object *_object);
18 : :
19 : : /*
20 : : * allocate an object record for a cookie lookup and prepare the lookup data
21 : : */
22 : 0 : static struct fscache_object *cachefiles_alloc_object(
23 : : struct fscache_cache *_cache,
24 : : struct fscache_cookie *cookie)
25 : : {
26 : : struct cachefiles_lookup_data *lookup_data;
27 : : struct cachefiles_object *object;
28 : : struct cachefiles_cache *cache;
29 : : struct cachefiles_xattr *auxdata;
30 : : unsigned keylen, auxlen;
31 : : void *buffer, *p;
32 : : char *key;
33 : :
34 : : cache = container_of(_cache, struct cachefiles_cache, cache);
35 : :
36 : : _enter("{%s},%p,", cache->cache.identifier, cookie);
37 : :
38 : : lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp);
39 [ # # ]: 0 : if (!lookup_data)
40 : : goto nomem_lookup_data;
41 : :
42 : : /* create a new object record and a temporary leaf image */
43 : 0 : object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp);
44 [ # # ]: 0 : if (!object)
45 : : goto nomem_object;
46 : :
47 [ # # ]: 0 : ASSERTCMP(object->backer, ==, NULL);
48 : :
49 [ # # ]: 0 : BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
50 : : atomic_set(&object->usage, 1);
51 : :
52 : 0 : fscache_object_init(&object->fscache, cookie, &cache->cache);
53 : :
54 : 0 : object->type = cookie->def->type;
55 : :
56 : : /* get hold of the raw key
57 : : * - stick the length on the front and leave space on the back for the
58 : : * encoder
59 : : */
60 : : buffer = kmalloc((2 + 512) + 3, cachefiles_gfp);
61 [ # # ]: 0 : if (!buffer)
62 : : goto nomem_buffer;
63 : :
64 : 0 : keylen = cookie->key_len;
65 [ # # ]: 0 : if (keylen <= sizeof(cookie->inline_key))
66 : 0 : p = cookie->inline_key;
67 : : else
68 : 0 : p = cookie->key;
69 : 0 : memcpy(buffer + 2, p, keylen);
70 : :
71 : 0 : *(uint16_t *)buffer = keylen;
72 : 0 : ((char *)buffer)[keylen + 2] = 0;
73 : 0 : ((char *)buffer)[keylen + 3] = 0;
74 : 0 : ((char *)buffer)[keylen + 4] = 0;
75 : :
76 : : /* turn the raw key into something that can work with as a filename */
77 : 0 : key = cachefiles_cook_key(buffer, keylen + 2, object->type);
78 [ # # ]: 0 : if (!key)
79 : : goto nomem_key;
80 : :
81 : : /* get hold of the auxiliary data and prepend the object type */
82 : : auxdata = buffer;
83 : 0 : auxlen = cookie->aux_len;
84 [ # # ]: 0 : if (auxlen) {
85 [ # # ]: 0 : if (auxlen <= sizeof(cookie->inline_aux))
86 : 0 : p = cookie->inline_aux;
87 : : else
88 : 0 : p = cookie->aux;
89 : 0 : memcpy(auxdata->data, p, auxlen);
90 : : }
91 : :
92 : 0 : auxdata->len = auxlen + 1;
93 : 0 : auxdata->type = cookie->type;
94 : :
95 : 0 : lookup_data->auxdata = auxdata;
96 : 0 : lookup_data->key = key;
97 : 0 : object->lookup_data = lookup_data;
98 : :
99 : : _leave(" = %p [%p]", &object->fscache, lookup_data);
100 : 0 : return &object->fscache;
101 : :
102 : : nomem_key:
103 : 0 : kfree(buffer);
104 : : nomem_buffer:
105 [ # # ]: 0 : BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
106 : 0 : kmem_cache_free(cachefiles_object_jar, object);
107 : 0 : fscache_object_destroyed(&cache->cache);
108 : : nomem_object:
109 : 0 : kfree(lookup_data);
110 : : nomem_lookup_data:
111 : : _leave(" = -ENOMEM");
112 : : return ERR_PTR(-ENOMEM);
113 : : }
114 : :
115 : : /*
116 : : * attempt to look up the nominated node in this cache
117 : : * - return -ETIMEDOUT to be scheduled again
118 : : */
119 : 0 : static int cachefiles_lookup_object(struct fscache_object *_object)
120 : : {
121 : : struct cachefiles_lookup_data *lookup_data;
122 : : struct cachefiles_object *parent, *object;
123 : : struct cachefiles_cache *cache;
124 : : const struct cred *saved_cred;
125 : : int ret;
126 : :
127 : : _enter("{OBJ%x}", _object->debug_id);
128 : :
129 : 0 : cache = container_of(_object->cache, struct cachefiles_cache, cache);
130 : 0 : parent = container_of(_object->parent,
131 : : struct cachefiles_object, fscache);
132 : : object = container_of(_object, struct cachefiles_object, fscache);
133 : 0 : lookup_data = object->lookup_data;
134 : :
135 [ # # ]: 0 : ASSERTCMP(lookup_data, !=, NULL);
136 : :
137 : : /* look up the key, creating any missing bits */
138 : : cachefiles_begin_secure(cache, &saved_cred);
139 : 0 : ret = cachefiles_walk_to_object(parent, object,
140 : 0 : lookup_data->key,
141 : : lookup_data->auxdata);
142 : : cachefiles_end_secure(cache, saved_cred);
143 : :
144 : : /* polish off by setting the attributes of non-index files */
145 [ # # # # ]: 0 : if (ret == 0 &&
146 : 0 : object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
147 : 0 : cachefiles_attr_changed(&object->fscache);
148 : :
149 [ # # ]: 0 : if (ret < 0 && ret != -ETIMEDOUT) {
150 [ # # ]: 0 : if (ret != -ENOBUFS)
151 : 0 : pr_warn("Lookup failed error %d\n", ret);
152 : : fscache_object_lookup_error(&object->fscache);
153 : : }
154 : :
155 : : _leave(" [%d]", ret);
156 : 0 : return ret;
157 : : }
158 : :
159 : : /*
160 : : * indication of lookup completion
161 : : */
162 : 0 : static void cachefiles_lookup_complete(struct fscache_object *_object)
163 : : {
164 : : struct cachefiles_object *object;
165 : :
166 : : object = container_of(_object, struct cachefiles_object, fscache);
167 : :
168 : : _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data);
169 : :
170 [ # # ]: 0 : if (object->lookup_data) {
171 : 0 : kfree(object->lookup_data->key);
172 : 0 : kfree(object->lookup_data->auxdata);
173 : 0 : kfree(object->lookup_data);
174 : 0 : object->lookup_data = NULL;
175 : : }
176 : 0 : }
177 : :
178 : : /*
179 : : * increment the usage count on an inode object (may fail if unmounting)
180 : : */
181 : : static
182 : 0 : struct fscache_object *cachefiles_grab_object(struct fscache_object *_object,
183 : : enum fscache_obj_ref_trace why)
184 : : {
185 : : struct cachefiles_object *object =
186 : : container_of(_object, struct cachefiles_object, fscache);
187 : : int u;
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 : 0 : u = atomic_inc_return(&object->usage);
196 : 0 : trace_cachefiles_ref(object, _object->cookie,
197 : : (enum cachefiles_obj_ref_trace)why, u);
198 : 0 : return &object->fscache;
199 : : }
200 : :
201 : : /*
202 : : * update the auxiliary data for an object object on disk
203 : : */
204 : 0 : static void cachefiles_update_object(struct fscache_object *_object)
205 : : {
206 : : struct cachefiles_object *object;
207 : : struct cachefiles_xattr *auxdata;
208 : : struct cachefiles_cache *cache;
209 : : struct fscache_cookie *cookie;
210 : : const struct cred *saved_cred;
211 : : const void *aux;
212 : : unsigned auxlen;
213 : :
214 : : _enter("{OBJ%x}", _object->debug_id);
215 : :
216 : : object = container_of(_object, struct cachefiles_object, fscache);
217 : 0 : cache = container_of(object->fscache.cache, struct cachefiles_cache,
218 : : cache);
219 : :
220 [ # # ]: 0 : if (!fscache_use_cookie(_object)) {
221 : : _leave(" [relinq]");
222 : : return;
223 : : }
224 : :
225 : 0 : cookie = object->fscache.cookie;
226 : 0 : auxlen = cookie->aux_len;
227 : :
228 [ # # ]: 0 : if (!auxlen) {
229 : 0 : fscache_unuse_cookie(_object);
230 : : _leave(" [no aux]");
231 : 0 : return;
232 : : }
233 : :
234 : 0 : auxdata = kmalloc(2 + auxlen + 3, cachefiles_gfp);
235 [ # # ]: 0 : if (!auxdata) {
236 : 0 : fscache_unuse_cookie(_object);
237 : : _leave(" [nomem]");
238 : 0 : return;
239 : : }
240 : :
241 : : aux = (auxlen <= sizeof(cookie->inline_aux)) ?
242 [ # # ]: 0 : cookie->inline_aux : cookie->aux;
243 : :
244 : 0 : memcpy(auxdata->data, aux, auxlen);
245 : 0 : fscache_unuse_cookie(_object);
246 : :
247 : 0 : auxdata->len = auxlen + 1;
248 : 0 : auxdata->type = cookie->type;
249 : :
250 : : cachefiles_begin_secure(cache, &saved_cred);
251 : 0 : cachefiles_update_object_xattr(object, auxdata);
252 : : cachefiles_end_secure(cache, saved_cred);
253 : 0 : kfree(auxdata);
254 : : _leave("");
255 : : }
256 : :
257 : : /*
258 : : * discard the resources pinned by an object and effect retirement if
259 : : * requested
260 : : */
261 : 0 : static void cachefiles_drop_object(struct fscache_object *_object)
262 : : {
263 : : struct cachefiles_object *object;
264 : : struct cachefiles_cache *cache;
265 : : const struct cred *saved_cred;
266 : : struct inode *inode;
267 : : blkcnt_t i_blocks = 0;
268 : :
269 [ # # ]: 0 : ASSERT(_object);
270 : :
271 : : object = container_of(_object, struct cachefiles_object, fscache);
272 : :
273 : : _enter("{OBJ%x,%d}",
274 : : object->fscache.debug_id, atomic_read(&object->usage));
275 : :
276 : 0 : cache = container_of(object->fscache.cache,
277 : : struct cachefiles_cache, cache);
278 : :
279 : : #ifdef CACHEFILES_DEBUG_SLAB
280 : : ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
281 : : #endif
282 : :
283 : : /* We need to tidy the object up if we did in fact manage to open it.
284 : : * It's possible for us to get here before the object is fully
285 : : * initialised if the parent goes away or the object gets retired
286 : : * before we set it up.
287 : : */
288 [ # # ]: 0 : if (object->dentry) {
289 : : /* delete retired objects */
290 [ # # # # ]: 0 : if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) &&
291 : 0 : _object != cache->cache.fsdef
292 : : ) {
293 : : _debug("- retire object OBJ%x", object->fscache.debug_id);
294 : : inode = d_backing_inode(object->dentry);
295 [ # # ]: 0 : if (inode)
296 : 0 : i_blocks = inode->i_blocks;
297 : :
298 : : cachefiles_begin_secure(cache, &saved_cred);
299 : 0 : cachefiles_delete_object(cache, object);
300 : : cachefiles_end_secure(cache, saved_cred);
301 : : }
302 : :
303 : : /* close the filesystem stuff attached to the object */
304 [ # # ]: 0 : if (object->backer != object->dentry)
305 : 0 : dput(object->backer);
306 : 0 : object->backer = NULL;
307 : : }
308 : :
309 : : /* note that the object is now inactive */
310 [ # # ]: 0 : if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
311 : 0 : cachefiles_mark_object_inactive(cache, object, i_blocks);
312 : :
313 : 0 : dput(object->dentry);
314 : 0 : object->dentry = NULL;
315 : :
316 : : _leave("");
317 : 0 : }
318 : :
319 : : /*
320 : : * dispose of a reference to an object
321 : : */
322 : 0 : static void cachefiles_put_object(struct fscache_object *_object,
323 : : enum fscache_obj_ref_trace why)
324 : : {
325 : : struct cachefiles_object *object;
326 : : struct fscache_cache *cache;
327 : : int u;
328 : :
329 [ # # ]: 0 : ASSERT(_object);
330 : :
331 : : object = container_of(_object, struct cachefiles_object, fscache);
332 : :
333 : : _enter("{OBJ%x,%d}",
334 : : object->fscache.debug_id, atomic_read(&object->usage));
335 : :
336 : : #ifdef CACHEFILES_DEBUG_SLAB
337 : : ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
338 : : #endif
339 : :
340 [ # # # # ]: 0 : ASSERTIFCMP(object->fscache.parent,
341 : : object->fscache.parent->n_children, >, 0);
342 : :
343 : 0 : u = atomic_dec_return(&object->usage);
344 : 0 : trace_cachefiles_ref(object, _object->cookie,
345 : : (enum cachefiles_obj_ref_trace)why, u);
346 [ # # ]: 0 : ASSERTCMP(u, !=, -1);
347 [ # # ]: 0 : if (u == 0) {
348 : : _debug("- kill object OBJ%x", object->fscache.debug_id);
349 : :
350 [ # # ]: 0 : ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
351 [ # # ]: 0 : ASSERTCMP(object->fscache.parent, ==, NULL);
352 [ # # ]: 0 : ASSERTCMP(object->backer, ==, NULL);
353 [ # # ]: 0 : ASSERTCMP(object->dentry, ==, NULL);
354 [ # # ]: 0 : ASSERTCMP(object->fscache.n_ops, ==, 0);
355 [ # # ]: 0 : ASSERTCMP(object->fscache.n_children, ==, 0);
356 : :
357 [ # # ]: 0 : if (object->lookup_data) {
358 : 0 : kfree(object->lookup_data->key);
359 : 0 : kfree(object->lookup_data->auxdata);
360 : 0 : kfree(object->lookup_data);
361 : 0 : object->lookup_data = NULL;
362 : : }
363 : :
364 : 0 : cache = object->fscache.cache;
365 : 0 : fscache_object_destroy(&object->fscache);
366 : 0 : kmem_cache_free(cachefiles_object_jar, object);
367 : 0 : fscache_object_destroyed(cache);
368 : : }
369 : :
370 : : _leave("");
371 : 0 : }
372 : :
373 : : /*
374 : : * sync a cache
375 : : */
376 : 0 : static void cachefiles_sync_cache(struct fscache_cache *_cache)
377 : : {
378 : : struct cachefiles_cache *cache;
379 : : const struct cred *saved_cred;
380 : : int ret;
381 : :
382 : : _enter("%p", _cache);
383 : :
384 : : cache = container_of(_cache, struct cachefiles_cache, cache);
385 : :
386 : : /* make sure all pages pinned by operations on behalf of the netfs are
387 : : * written to disc */
388 : : cachefiles_begin_secure(cache, &saved_cred);
389 : 0 : down_read(&cache->mnt->mnt_sb->s_umount);
390 : 0 : ret = sync_filesystem(cache->mnt->mnt_sb);
391 : 0 : up_read(&cache->mnt->mnt_sb->s_umount);
392 : : cachefiles_end_secure(cache, saved_cred);
393 : :
394 [ # # ]: 0 : if (ret == -EIO)
395 : 0 : cachefiles_io_error(cache,
396 : : "Attempt to sync backing fs superblock"
397 : : " returned error %d",
398 : : ret);
399 : 0 : }
400 : :
401 : : /*
402 : : * check if the backing cache is updated to FS-Cache
403 : : * - called by FS-Cache when evaluates if need to invalidate the cache
404 : : */
405 : 0 : static int cachefiles_check_consistency(struct fscache_operation *op)
406 : : {
407 : : struct cachefiles_object *object;
408 : : struct cachefiles_cache *cache;
409 : : const struct cred *saved_cred;
410 : : int ret;
411 : :
412 : : _enter("{OBJ%x}", op->object->debug_id);
413 : :
414 : 0 : object = container_of(op->object, struct cachefiles_object, fscache);
415 : 0 : cache = container_of(object->fscache.cache,
416 : : struct cachefiles_cache, cache);
417 : :
418 : : cachefiles_begin_secure(cache, &saved_cred);
419 : 0 : ret = cachefiles_check_auxdata(object);
420 : : cachefiles_end_secure(cache, saved_cred);
421 : :
422 : : _leave(" = %d", ret);
423 : 0 : return ret;
424 : : }
425 : :
426 : : /*
427 : : * notification the attributes on an object have changed
428 : : * - called with reads/writes excluded by FS-Cache
429 : : */
430 : 0 : static int cachefiles_attr_changed(struct fscache_object *_object)
431 : : {
432 : : struct cachefiles_object *object;
433 : : struct cachefiles_cache *cache;
434 : : const struct cred *saved_cred;
435 : : struct iattr newattrs;
436 : : uint64_t ni_size;
437 : : loff_t oi_size;
438 : : int ret;
439 : :
440 : 0 : ni_size = _object->store_limit_l;
441 : :
442 : : _enter("{OBJ%x},[%llu]",
443 : : _object->debug_id, (unsigned long long) ni_size);
444 : :
445 : : object = container_of(_object, struct cachefiles_object, fscache);
446 : 0 : cache = container_of(object->fscache.cache,
447 : : struct cachefiles_cache, cache);
448 : :
449 [ # # ]: 0 : if (ni_size == object->i_size)
450 : : return 0;
451 : :
452 [ # # ]: 0 : if (!object->backer)
453 : : return -ENOBUFS;
454 : :
455 [ # # ]: 0 : ASSERT(d_is_reg(object->backer));
456 : :
457 : : fscache_set_store_limit(&object->fscache, ni_size);
458 : :
459 : 0 : oi_size = i_size_read(d_backing_inode(object->backer));
460 [ # # ]: 0 : if (oi_size == ni_size)
461 : : return 0;
462 : :
463 : : cachefiles_begin_secure(cache, &saved_cred);
464 : 0 : inode_lock(d_inode(object->backer));
465 : :
466 : : /* if there's an extension to a partial page at the end of the backing
467 : : * file, we need to discard the partial page so that we pick up new
468 : : * data after it */
469 [ # # # # ]: 0 : if (oi_size & ~PAGE_MASK && ni_size > oi_size) {
470 : : _debug("discard tail %llx", oi_size);
471 : 0 : newattrs.ia_valid = ATTR_SIZE;
472 : 0 : newattrs.ia_size = oi_size & PAGE_MASK;
473 : 0 : ret = notify_change(object->backer, &newattrs, NULL);
474 [ # # ]: 0 : if (ret < 0)
475 : : goto truncate_failed;
476 : : }
477 : :
478 : 0 : newattrs.ia_valid = ATTR_SIZE;
479 : 0 : newattrs.ia_size = ni_size;
480 : 0 : ret = notify_change(object->backer, &newattrs, NULL);
481 : :
482 : : truncate_failed:
483 : 0 : inode_unlock(d_inode(object->backer));
484 : : cachefiles_end_secure(cache, saved_cred);
485 : :
486 [ # # ]: 0 : if (ret == -EIO) {
487 : : fscache_set_store_limit(&object->fscache, 0);
488 : 0 : cachefiles_io_error_obj(object, "Size set failed");
489 : : ret = -ENOBUFS;
490 : : }
491 : :
492 : : _leave(" = %d", ret);
493 : 0 : return ret;
494 : : }
495 : :
496 : : /*
497 : : * Invalidate an object
498 : : */
499 : 0 : static void cachefiles_invalidate_object(struct fscache_operation *op)
500 : : {
501 : : struct cachefiles_object *object;
502 : : struct cachefiles_cache *cache;
503 : : const struct cred *saved_cred;
504 : : struct path path;
505 : : uint64_t ni_size;
506 : : int ret;
507 : :
508 : 0 : object = container_of(op->object, struct cachefiles_object, fscache);
509 : 0 : cache = container_of(object->fscache.cache,
510 : : struct cachefiles_cache, cache);
511 : :
512 : 0 : ni_size = op->object->store_limit_l;
513 : :
514 : : _enter("{OBJ%x},[%llu]",
515 : : op->object->debug_id, (unsigned long long)ni_size);
516 : :
517 [ # # ]: 0 : if (object->backer) {
518 [ # # ]: 0 : ASSERT(d_is_reg(object->backer));
519 : :
520 : : fscache_set_store_limit(&object->fscache, ni_size);
521 : :
522 : 0 : path.dentry = object->backer;
523 : 0 : path.mnt = cache->mnt;
524 : :
525 : : cachefiles_begin_secure(cache, &saved_cred);
526 : 0 : ret = vfs_truncate(&path, 0);
527 [ # # ]: 0 : if (ret == 0)
528 : 0 : ret = vfs_truncate(&path, ni_size);
529 : : cachefiles_end_secure(cache, saved_cred);
530 : :
531 [ # # ]: 0 : if (ret != 0) {
532 : : fscache_set_store_limit(&object->fscache, 0);
533 [ # # ]: 0 : if (ret == -EIO)
534 : 0 : cachefiles_io_error_obj(object,
535 : : "Invalidate failed");
536 : : }
537 : : }
538 : :
539 : 0 : fscache_op_complete(op, true);
540 : : _leave("");
541 : 0 : }
542 : :
543 : : /*
544 : : * dissociate a cache from all the pages it was backing
545 : : */
546 : 0 : static void cachefiles_dissociate_pages(struct fscache_cache *cache)
547 : : {
548 : : _enter("");
549 : 0 : }
550 : :
551 : : const struct fscache_cache_ops cachefiles_cache_ops = {
552 : : .name = "cachefiles",
553 : : .alloc_object = cachefiles_alloc_object,
554 : : .lookup_object = cachefiles_lookup_object,
555 : : .lookup_complete = cachefiles_lookup_complete,
556 : : .grab_object = cachefiles_grab_object,
557 : : .update_object = cachefiles_update_object,
558 : : .invalidate_object = cachefiles_invalidate_object,
559 : : .drop_object = cachefiles_drop_object,
560 : : .put_object = cachefiles_put_object,
561 : : .sync_cache = cachefiles_sync_cache,
562 : : .attr_changed = cachefiles_attr_changed,
563 : : .read_or_alloc_page = cachefiles_read_or_alloc_page,
564 : : .read_or_alloc_pages = cachefiles_read_or_alloc_pages,
565 : : .allocate_page = cachefiles_allocate_page,
566 : : .allocate_pages = cachefiles_allocate_pages,
567 : : .write_page = cachefiles_write_page,
568 : : .uncache_page = cachefiles_uncache_page,
569 : : .dissociate_pages = cachefiles_dissociate_pages,
570 : : .check_consistency = cachefiles_check_consistency,
571 : : };
|