xref: /OK3568_Linux_fs/kernel/fs/cachefiles/interface.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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