18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* FS-Cache interface to CacheFiles 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/mount.h> 108c2ecf20Sopenharmony_ci#include "internal.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct cachefiles_lookup_data { 138c2ecf20Sopenharmony_ci struct cachefiles_xattr *auxdata; /* auxiliary data */ 148c2ecf20Sopenharmony_ci char *key; /* key path */ 158c2ecf20Sopenharmony_ci}; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int cachefiles_attr_changed(struct fscache_object *_object); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * allocate an object record for a cookie lookup and prepare the lookup data 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_cistatic struct fscache_object *cachefiles_alloc_object( 238c2ecf20Sopenharmony_ci struct fscache_cache *_cache, 248c2ecf20Sopenharmony_ci struct fscache_cookie *cookie) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct cachefiles_lookup_data *lookup_data; 278c2ecf20Sopenharmony_ci struct cachefiles_object *object; 288c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 298c2ecf20Sopenharmony_ci struct cachefiles_xattr *auxdata; 308c2ecf20Sopenharmony_ci unsigned keylen, auxlen; 318c2ecf20Sopenharmony_ci void *buffer, *p; 328c2ecf20Sopenharmony_ci char *key; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci cache = container_of(_cache, struct cachefiles_cache, cache); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci _enter("{%s},%p,", cache->cache.identifier, cookie); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp); 398c2ecf20Sopenharmony_ci if (!lookup_data) 408c2ecf20Sopenharmony_ci goto nomem_lookup_data; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* create a new object record and a temporary leaf image */ 438c2ecf20Sopenharmony_ci object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp); 448c2ecf20Sopenharmony_ci if (!object) 458c2ecf20Sopenharmony_ci goto nomem_object; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ASSERTCMP(object->backer, ==, NULL); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); 508c2ecf20Sopenharmony_ci atomic_set(&object->usage, 1); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci fscache_object_init(&object->fscache, cookie, &cache->cache); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci object->type = cookie->def->type; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* get hold of the raw key 578c2ecf20Sopenharmony_ci * - stick the length on the front and leave space on the back for the 588c2ecf20Sopenharmony_ci * encoder 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci buffer = kmalloc((2 + 512) + 3, cachefiles_gfp); 618c2ecf20Sopenharmony_ci if (!buffer) 628c2ecf20Sopenharmony_ci goto nomem_buffer; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci keylen = cookie->key_len; 658c2ecf20Sopenharmony_ci if (keylen <= sizeof(cookie->inline_key)) 668c2ecf20Sopenharmony_ci p = cookie->inline_key; 678c2ecf20Sopenharmony_ci else 688c2ecf20Sopenharmony_ci p = cookie->key; 698c2ecf20Sopenharmony_ci memcpy(buffer + 2, p, keylen); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci *(uint16_t *)buffer = keylen; 728c2ecf20Sopenharmony_ci ((char *)buffer)[keylen + 2] = 0; 738c2ecf20Sopenharmony_ci ((char *)buffer)[keylen + 3] = 0; 748c2ecf20Sopenharmony_ci ((char *)buffer)[keylen + 4] = 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* turn the raw key into something that can work with as a filename */ 778c2ecf20Sopenharmony_ci key = cachefiles_cook_key(buffer, keylen + 2, object->type); 788c2ecf20Sopenharmony_ci if (!key) 798c2ecf20Sopenharmony_ci goto nomem_key; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* get hold of the auxiliary data and prepend the object type */ 828c2ecf20Sopenharmony_ci auxdata = buffer; 838c2ecf20Sopenharmony_ci auxlen = cookie->aux_len; 848c2ecf20Sopenharmony_ci if (auxlen) { 858c2ecf20Sopenharmony_ci if (auxlen <= sizeof(cookie->inline_aux)) 868c2ecf20Sopenharmony_ci p = cookie->inline_aux; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci p = cookie->aux; 898c2ecf20Sopenharmony_ci memcpy(auxdata->data, p, auxlen); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci auxdata->len = auxlen + 1; 938c2ecf20Sopenharmony_ci auxdata->type = cookie->type; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci lookup_data->auxdata = auxdata; 968c2ecf20Sopenharmony_ci lookup_data->key = key; 978c2ecf20Sopenharmony_ci object->lookup_data = lookup_data; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci _leave(" = %p [%p]", &object->fscache, lookup_data); 1008c2ecf20Sopenharmony_ci return &object->fscache; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cinomem_key: 1038c2ecf20Sopenharmony_ci kfree(buffer); 1048c2ecf20Sopenharmony_cinomem_buffer: 1058c2ecf20Sopenharmony_ci BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); 1068c2ecf20Sopenharmony_ci kmem_cache_free(cachefiles_object_jar, object); 1078c2ecf20Sopenharmony_ci fscache_object_destroyed(&cache->cache); 1088c2ecf20Sopenharmony_cinomem_object: 1098c2ecf20Sopenharmony_ci kfree(lookup_data); 1108c2ecf20Sopenharmony_cinomem_lookup_data: 1118c2ecf20Sopenharmony_ci _leave(" = -ENOMEM"); 1128c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * attempt to look up the nominated node in this cache 1178c2ecf20Sopenharmony_ci * - return -ETIMEDOUT to be scheduled again 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int cachefiles_lookup_object(struct fscache_object *_object) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct cachefiles_lookup_data *lookup_data; 1228c2ecf20Sopenharmony_ci struct cachefiles_object *parent, *object; 1238c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 1248c2ecf20Sopenharmony_ci const struct cred *saved_cred; 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci _enter("{OBJ%x}", _object->debug_id); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci cache = container_of(_object->cache, struct cachefiles_cache, cache); 1308c2ecf20Sopenharmony_ci parent = container_of(_object->parent, 1318c2ecf20Sopenharmony_ci struct cachefiles_object, fscache); 1328c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 1338c2ecf20Sopenharmony_ci lookup_data = object->lookup_data; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ASSERTCMP(lookup_data, !=, NULL); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* look up the key, creating any missing bits */ 1388c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 1398c2ecf20Sopenharmony_ci ret = cachefiles_walk_to_object(parent, object, 1408c2ecf20Sopenharmony_ci lookup_data->key, 1418c2ecf20Sopenharmony_ci lookup_data->auxdata); 1428c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* polish off by setting the attributes of non-index files */ 1458c2ecf20Sopenharmony_ci if (ret == 0 && 1468c2ecf20Sopenharmony_ci object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) 1478c2ecf20Sopenharmony_ci cachefiles_attr_changed(&object->fscache); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ETIMEDOUT) { 1508c2ecf20Sopenharmony_ci if (ret != -ENOBUFS) 1518c2ecf20Sopenharmony_ci pr_warn("Lookup failed error %d\n", ret); 1528c2ecf20Sopenharmony_ci fscache_object_lookup_error(&object->fscache); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci _leave(" [%d]", ret); 1568c2ecf20Sopenharmony_ci return ret; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* 1608c2ecf20Sopenharmony_ci * indication of lookup completion 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_cistatic void cachefiles_lookup_complete(struct fscache_object *_object) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct cachefiles_object *object; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (object->lookup_data) { 1718c2ecf20Sopenharmony_ci kfree(object->lookup_data->key); 1728c2ecf20Sopenharmony_ci kfree(object->lookup_data->auxdata); 1738c2ecf20Sopenharmony_ci kfree(object->lookup_data); 1748c2ecf20Sopenharmony_ci object->lookup_data = NULL; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* 1798c2ecf20Sopenharmony_ci * increment the usage count on an inode object (may fail if unmounting) 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic 1828c2ecf20Sopenharmony_cistruct fscache_object *cachefiles_grab_object(struct fscache_object *_object, 1838c2ecf20Sopenharmony_ci enum fscache_obj_ref_trace why) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct cachefiles_object *object = 1868c2ecf20Sopenharmony_ci container_of(_object, struct cachefiles_object, fscache); 1878c2ecf20Sopenharmony_ci int u; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage)); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#ifdef CACHEFILES_DEBUG_SLAB 1928c2ecf20Sopenharmony_ci ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci u = atomic_inc_return(&object->usage); 1968c2ecf20Sopenharmony_ci trace_cachefiles_ref(object, _object->cookie, 1978c2ecf20Sopenharmony_ci (enum cachefiles_obj_ref_trace)why, u); 1988c2ecf20Sopenharmony_ci return &object->fscache; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* 2028c2ecf20Sopenharmony_ci * update the auxiliary data for an object object on disk 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic void cachefiles_update_object(struct fscache_object *_object) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct cachefiles_object *object; 2078c2ecf20Sopenharmony_ci struct cachefiles_xattr *auxdata; 2088c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 2098c2ecf20Sopenharmony_ci struct fscache_cookie *cookie; 2108c2ecf20Sopenharmony_ci const struct cred *saved_cred; 2118c2ecf20Sopenharmony_ci const void *aux; 2128c2ecf20Sopenharmony_ci unsigned auxlen; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci _enter("{OBJ%x}", _object->debug_id); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 2178c2ecf20Sopenharmony_ci cache = container_of(object->fscache.cache, struct cachefiles_cache, 2188c2ecf20Sopenharmony_ci cache); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!fscache_use_cookie(_object)) { 2218c2ecf20Sopenharmony_ci _leave(" [relinq]"); 2228c2ecf20Sopenharmony_ci return; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci cookie = object->fscache.cookie; 2268c2ecf20Sopenharmony_ci auxlen = cookie->aux_len; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (!auxlen) { 2298c2ecf20Sopenharmony_ci fscache_unuse_cookie(_object); 2308c2ecf20Sopenharmony_ci _leave(" [no aux]"); 2318c2ecf20Sopenharmony_ci return; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci auxdata = kmalloc(2 + auxlen + 3, cachefiles_gfp); 2358c2ecf20Sopenharmony_ci if (!auxdata) { 2368c2ecf20Sopenharmony_ci fscache_unuse_cookie(_object); 2378c2ecf20Sopenharmony_ci _leave(" [nomem]"); 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci aux = (auxlen <= sizeof(cookie->inline_aux)) ? 2428c2ecf20Sopenharmony_ci cookie->inline_aux : cookie->aux; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci memcpy(auxdata->data, aux, auxlen); 2458c2ecf20Sopenharmony_ci fscache_unuse_cookie(_object); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci auxdata->len = auxlen + 1; 2488c2ecf20Sopenharmony_ci auxdata->type = cookie->type; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 2518c2ecf20Sopenharmony_ci cachefiles_update_object_xattr(object, auxdata); 2528c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 2538c2ecf20Sopenharmony_ci kfree(auxdata); 2548c2ecf20Sopenharmony_ci _leave(""); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * discard the resources pinned by an object and effect retirement if 2598c2ecf20Sopenharmony_ci * requested 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic void cachefiles_drop_object(struct fscache_object *_object) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct cachefiles_object *object; 2648c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 2658c2ecf20Sopenharmony_ci const struct cred *saved_cred; 2668c2ecf20Sopenharmony_ci struct inode *inode; 2678c2ecf20Sopenharmony_ci blkcnt_t i_blocks = 0; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ASSERT(_object); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci _enter("{OBJ%x,%d}", 2748c2ecf20Sopenharmony_ci object->fscache.debug_id, atomic_read(&object->usage)); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci cache = container_of(object->fscache.cache, 2778c2ecf20Sopenharmony_ci struct cachefiles_cache, cache); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#ifdef CACHEFILES_DEBUG_SLAB 2808c2ecf20Sopenharmony_ci ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); 2818c2ecf20Sopenharmony_ci#endif 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* We need to tidy the object up if we did in fact manage to open it. 2848c2ecf20Sopenharmony_ci * It's possible for us to get here before the object is fully 2858c2ecf20Sopenharmony_ci * initialised if the parent goes away or the object gets retired 2868c2ecf20Sopenharmony_ci * before we set it up. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci if (object->dentry) { 2898c2ecf20Sopenharmony_ci /* delete retired objects */ 2908c2ecf20Sopenharmony_ci if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) && 2918c2ecf20Sopenharmony_ci _object != cache->cache.fsdef 2928c2ecf20Sopenharmony_ci ) { 2938c2ecf20Sopenharmony_ci _debug("- retire object OBJ%x", object->fscache.debug_id); 2948c2ecf20Sopenharmony_ci inode = d_backing_inode(object->dentry); 2958c2ecf20Sopenharmony_ci if (inode) 2968c2ecf20Sopenharmony_ci i_blocks = inode->i_blocks; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 2998c2ecf20Sopenharmony_ci cachefiles_delete_object(cache, object); 3008c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* close the filesystem stuff attached to the object */ 3048c2ecf20Sopenharmony_ci if (object->backer != object->dentry) 3058c2ecf20Sopenharmony_ci dput(object->backer); 3068c2ecf20Sopenharmony_ci object->backer = NULL; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* note that the object is now inactive */ 3108c2ecf20Sopenharmony_ci if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) 3118c2ecf20Sopenharmony_ci cachefiles_mark_object_inactive(cache, object, i_blocks); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci dput(object->dentry); 3148c2ecf20Sopenharmony_ci object->dentry = NULL; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci _leave(""); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* 3208c2ecf20Sopenharmony_ci * dispose of a reference to an object 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic void cachefiles_put_object(struct fscache_object *_object, 3238c2ecf20Sopenharmony_ci enum fscache_obj_ref_trace why) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct cachefiles_object *object; 3268c2ecf20Sopenharmony_ci struct fscache_cache *cache; 3278c2ecf20Sopenharmony_ci int u; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ASSERT(_object); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci _enter("{OBJ%x,%d}", 3348c2ecf20Sopenharmony_ci object->fscache.debug_id, atomic_read(&object->usage)); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci#ifdef CACHEFILES_DEBUG_SLAB 3378c2ecf20Sopenharmony_ci ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000); 3388c2ecf20Sopenharmony_ci#endif 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ASSERTIFCMP(object->fscache.parent, 3418c2ecf20Sopenharmony_ci object->fscache.parent->n_children, >, 0); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci u = atomic_dec_return(&object->usage); 3448c2ecf20Sopenharmony_ci trace_cachefiles_ref(object, _object->cookie, 3458c2ecf20Sopenharmony_ci (enum cachefiles_obj_ref_trace)why, u); 3468c2ecf20Sopenharmony_ci ASSERTCMP(u, !=, -1); 3478c2ecf20Sopenharmony_ci if (u == 0) { 3488c2ecf20Sopenharmony_ci _debug("- kill object OBJ%x", object->fscache.debug_id); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)); 3518c2ecf20Sopenharmony_ci ASSERTCMP(object->fscache.parent, ==, NULL); 3528c2ecf20Sopenharmony_ci ASSERTCMP(object->backer, ==, NULL); 3538c2ecf20Sopenharmony_ci ASSERTCMP(object->dentry, ==, NULL); 3548c2ecf20Sopenharmony_ci ASSERTCMP(object->fscache.n_ops, ==, 0); 3558c2ecf20Sopenharmony_ci ASSERTCMP(object->fscache.n_children, ==, 0); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (object->lookup_data) { 3588c2ecf20Sopenharmony_ci kfree(object->lookup_data->key); 3598c2ecf20Sopenharmony_ci kfree(object->lookup_data->auxdata); 3608c2ecf20Sopenharmony_ci kfree(object->lookup_data); 3618c2ecf20Sopenharmony_ci object->lookup_data = NULL; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci cache = object->fscache.cache; 3658c2ecf20Sopenharmony_ci fscache_object_destroy(&object->fscache); 3668c2ecf20Sopenharmony_ci kmem_cache_free(cachefiles_object_jar, object); 3678c2ecf20Sopenharmony_ci fscache_object_destroyed(cache); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci _leave(""); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/* 3748c2ecf20Sopenharmony_ci * sync a cache 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_cistatic void cachefiles_sync_cache(struct fscache_cache *_cache) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 3798c2ecf20Sopenharmony_ci const struct cred *saved_cred; 3808c2ecf20Sopenharmony_ci int ret; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci _enter("%p", _cache); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci cache = container_of(_cache, struct cachefiles_cache, cache); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* make sure all pages pinned by operations on behalf of the netfs are 3878c2ecf20Sopenharmony_ci * written to disc */ 3888c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 3898c2ecf20Sopenharmony_ci down_read(&cache->mnt->mnt_sb->s_umount); 3908c2ecf20Sopenharmony_ci ret = sync_filesystem(cache->mnt->mnt_sb); 3918c2ecf20Sopenharmony_ci up_read(&cache->mnt->mnt_sb->s_umount); 3928c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (ret == -EIO) 3958c2ecf20Sopenharmony_ci cachefiles_io_error(cache, 3968c2ecf20Sopenharmony_ci "Attempt to sync backing fs superblock" 3978c2ecf20Sopenharmony_ci " returned error %d", 3988c2ecf20Sopenharmony_ci ret); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* 4028c2ecf20Sopenharmony_ci * check if the backing cache is updated to FS-Cache 4038c2ecf20Sopenharmony_ci * - called by FS-Cache when evaluates if need to invalidate the cache 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_cistatic int cachefiles_check_consistency(struct fscache_operation *op) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct cachefiles_object *object; 4088c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 4098c2ecf20Sopenharmony_ci const struct cred *saved_cred; 4108c2ecf20Sopenharmony_ci int ret; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci _enter("{OBJ%x}", op->object->debug_id); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci object = container_of(op->object, struct cachefiles_object, fscache); 4158c2ecf20Sopenharmony_ci cache = container_of(object->fscache.cache, 4168c2ecf20Sopenharmony_ci struct cachefiles_cache, cache); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 4198c2ecf20Sopenharmony_ci ret = cachefiles_check_auxdata(object); 4208c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci _leave(" = %d", ret); 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* 4278c2ecf20Sopenharmony_ci * notification the attributes on an object have changed 4288c2ecf20Sopenharmony_ci * - called with reads/writes excluded by FS-Cache 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic int cachefiles_attr_changed(struct fscache_object *_object) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct cachefiles_object *object; 4338c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 4348c2ecf20Sopenharmony_ci const struct cred *saved_cred; 4358c2ecf20Sopenharmony_ci struct iattr newattrs; 4368c2ecf20Sopenharmony_ci uint64_t ni_size; 4378c2ecf20Sopenharmony_ci loff_t oi_size; 4388c2ecf20Sopenharmony_ci int ret; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ni_size = _object->store_limit_l; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci _enter("{OBJ%x},[%llu]", 4438c2ecf20Sopenharmony_ci _object->debug_id, (unsigned long long) ni_size); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci object = container_of(_object, struct cachefiles_object, fscache); 4468c2ecf20Sopenharmony_ci cache = container_of(object->fscache.cache, 4478c2ecf20Sopenharmony_ci struct cachefiles_cache, cache); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (ni_size == object->i_size) 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!object->backer) 4538c2ecf20Sopenharmony_ci return -ENOBUFS; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci ASSERT(d_is_reg(object->backer)); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci fscache_set_store_limit(&object->fscache, ni_size); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci oi_size = i_size_read(d_backing_inode(object->backer)); 4608c2ecf20Sopenharmony_ci if (oi_size == ni_size) 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 4648c2ecf20Sopenharmony_ci inode_lock(d_inode(object->backer)); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* if there's an extension to a partial page at the end of the backing 4678c2ecf20Sopenharmony_ci * file, we need to discard the partial page so that we pick up new 4688c2ecf20Sopenharmony_ci * data after it */ 4698c2ecf20Sopenharmony_ci if (oi_size & ~PAGE_MASK && ni_size > oi_size) { 4708c2ecf20Sopenharmony_ci _debug("discard tail %llx", oi_size); 4718c2ecf20Sopenharmony_ci newattrs.ia_valid = ATTR_SIZE; 4728c2ecf20Sopenharmony_ci newattrs.ia_size = oi_size & PAGE_MASK; 4738c2ecf20Sopenharmony_ci ret = notify_change(object->backer, &newattrs, NULL); 4748c2ecf20Sopenharmony_ci if (ret < 0) 4758c2ecf20Sopenharmony_ci goto truncate_failed; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci newattrs.ia_valid = ATTR_SIZE; 4798c2ecf20Sopenharmony_ci newattrs.ia_size = ni_size; 4808c2ecf20Sopenharmony_ci ret = notify_change(object->backer, &newattrs, NULL); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_citruncate_failed: 4838c2ecf20Sopenharmony_ci inode_unlock(d_inode(object->backer)); 4848c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (ret == -EIO) { 4878c2ecf20Sopenharmony_ci fscache_set_store_limit(&object->fscache, 0); 4888c2ecf20Sopenharmony_ci cachefiles_io_error_obj(object, "Size set failed"); 4898c2ecf20Sopenharmony_ci ret = -ENOBUFS; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci _leave(" = %d", ret); 4938c2ecf20Sopenharmony_ci return ret; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci/* 4978c2ecf20Sopenharmony_ci * Invalidate an object 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_cistatic void cachefiles_invalidate_object(struct fscache_operation *op) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct cachefiles_object *object; 5028c2ecf20Sopenharmony_ci struct cachefiles_cache *cache; 5038c2ecf20Sopenharmony_ci const struct cred *saved_cred; 5048c2ecf20Sopenharmony_ci struct path path; 5058c2ecf20Sopenharmony_ci uint64_t ni_size; 5068c2ecf20Sopenharmony_ci int ret; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci object = container_of(op->object, struct cachefiles_object, fscache); 5098c2ecf20Sopenharmony_ci cache = container_of(object->fscache.cache, 5108c2ecf20Sopenharmony_ci struct cachefiles_cache, cache); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ni_size = op->object->store_limit_l; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci _enter("{OBJ%x},[%llu]", 5158c2ecf20Sopenharmony_ci op->object->debug_id, (unsigned long long)ni_size); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (object->backer) { 5188c2ecf20Sopenharmony_ci ASSERT(d_is_reg(object->backer)); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci fscache_set_store_limit(&object->fscache, ni_size); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci path.dentry = object->backer; 5238c2ecf20Sopenharmony_ci path.mnt = cache->mnt; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci cachefiles_begin_secure(cache, &saved_cred); 5268c2ecf20Sopenharmony_ci ret = vfs_truncate(&path, 0); 5278c2ecf20Sopenharmony_ci if (ret == 0) 5288c2ecf20Sopenharmony_ci ret = vfs_truncate(&path, ni_size); 5298c2ecf20Sopenharmony_ci cachefiles_end_secure(cache, saved_cred); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (ret != 0) { 5328c2ecf20Sopenharmony_ci fscache_set_store_limit(&object->fscache, 0); 5338c2ecf20Sopenharmony_ci if (ret == -EIO) 5348c2ecf20Sopenharmony_ci cachefiles_io_error_obj(object, 5358c2ecf20Sopenharmony_ci "Invalidate failed"); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci fscache_op_complete(op, true); 5408c2ecf20Sopenharmony_ci _leave(""); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* 5448c2ecf20Sopenharmony_ci * dissociate a cache from all the pages it was backing 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_cistatic void cachefiles_dissociate_pages(struct fscache_cache *cache) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci _enter(""); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ciconst struct fscache_cache_ops cachefiles_cache_ops = { 5528c2ecf20Sopenharmony_ci .name = "cachefiles", 5538c2ecf20Sopenharmony_ci .alloc_object = cachefiles_alloc_object, 5548c2ecf20Sopenharmony_ci .lookup_object = cachefiles_lookup_object, 5558c2ecf20Sopenharmony_ci .lookup_complete = cachefiles_lookup_complete, 5568c2ecf20Sopenharmony_ci .grab_object = cachefiles_grab_object, 5578c2ecf20Sopenharmony_ci .update_object = cachefiles_update_object, 5588c2ecf20Sopenharmony_ci .invalidate_object = cachefiles_invalidate_object, 5598c2ecf20Sopenharmony_ci .drop_object = cachefiles_drop_object, 5608c2ecf20Sopenharmony_ci .put_object = cachefiles_put_object, 5618c2ecf20Sopenharmony_ci .sync_cache = cachefiles_sync_cache, 5628c2ecf20Sopenharmony_ci .attr_changed = cachefiles_attr_changed, 5638c2ecf20Sopenharmony_ci .read_or_alloc_page = cachefiles_read_or_alloc_page, 5648c2ecf20Sopenharmony_ci .read_or_alloc_pages = cachefiles_read_or_alloc_pages, 5658c2ecf20Sopenharmony_ci .allocate_page = cachefiles_allocate_page, 5668c2ecf20Sopenharmony_ci .allocate_pages = cachefiles_allocate_pages, 5678c2ecf20Sopenharmony_ci .write_page = cachefiles_write_page, 5688c2ecf20Sopenharmony_ci .uncache_page = cachefiles_uncache_page, 5698c2ecf20Sopenharmony_ci .dissociate_pages = cachefiles_dissociate_pages, 5708c2ecf20Sopenharmony_ci .check_consistency = cachefiles_check_consistency, 5718c2ecf20Sopenharmony_ci}; 572