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