1/* FS-Cache cache handling
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#define FSCACHE_DEBUG_LEVEL CACHE
13#include <linux/module.h>
14#include <linux/slab.h>
15#include "internal.h"
16
17LIST_HEAD(fscache_cache_list);
18DECLARE_RWSEM(fscache_addremove_sem);
19DECLARE_WAIT_QUEUE_HEAD(fscache_cache_cleared_wq);
20EXPORT_SYMBOL(fscache_cache_cleared_wq);
21
22static LIST_HEAD(fscache_cache_tag_list);
23
24/*
25 * look up a cache tag
26 */
27struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *name)
28{
29	struct fscache_cache_tag *tag, *xtag;
30
31	/* firstly check for the existence of the tag under read lock */
32	down_read(&fscache_addremove_sem);
33
34	list_for_each_entry(tag, &fscache_cache_tag_list, link) {
35		if (strcmp(tag->name, name) == 0) {
36			atomic_inc(&tag->usage);
37			up_read(&fscache_addremove_sem);
38			return tag;
39		}
40	}
41
42	up_read(&fscache_addremove_sem);
43
44	/* the tag does not exist - create a candidate */
45	xtag = kzalloc(sizeof(*xtag) + strlen(name) + 1, GFP_KERNEL);
46	if (!xtag)
47		/* return a dummy tag if out of memory */
48		return ERR_PTR(-ENOMEM);
49
50	atomic_set(&xtag->usage, 1);
51	strcpy(xtag->name, name);
52
53	/* write lock, search again and add if still not present */
54	down_write(&fscache_addremove_sem);
55
56	list_for_each_entry(tag, &fscache_cache_tag_list, link) {
57		if (strcmp(tag->name, name) == 0) {
58			atomic_inc(&tag->usage);
59			up_write(&fscache_addremove_sem);
60			kfree(xtag);
61			return tag;
62		}
63	}
64
65	list_add_tail(&xtag->link, &fscache_cache_tag_list);
66	up_write(&fscache_addremove_sem);
67	return xtag;
68}
69
70/*
71 * release a reference to a cache tag
72 */
73void __fscache_release_cache_tag(struct fscache_cache_tag *tag)
74{
75	if (tag != ERR_PTR(-ENOMEM)) {
76		down_write(&fscache_addremove_sem);
77
78		if (atomic_dec_and_test(&tag->usage))
79			list_del_init(&tag->link);
80		else
81			tag = NULL;
82
83		up_write(&fscache_addremove_sem);
84
85		kfree(tag);
86	}
87}
88
89/*
90 * select a cache in which to store an object
91 * - the cache addremove semaphore must be at least read-locked by the caller
92 * - the object will never be an index
93 */
94struct fscache_cache *fscache_select_cache_for_object(
95	struct fscache_cookie *cookie)
96{
97	struct fscache_cache_tag *tag;
98	struct fscache_object *object;
99	struct fscache_cache *cache;
100
101	_enter("");
102
103	if (list_empty(&fscache_cache_list)) {
104		_leave(" = NULL [no cache]");
105		return NULL;
106	}
107
108	/* we check the parent to determine the cache to use */
109	spin_lock(&cookie->lock);
110
111	/* the first in the parent's backing list should be the preferred
112	 * cache */
113	if (!hlist_empty(&cookie->backing_objects)) {
114		object = hlist_entry(cookie->backing_objects.first,
115				     struct fscache_object, cookie_link);
116
117		cache = object->cache;
118		if (object->state >= FSCACHE_OBJECT_DYING ||
119		    test_bit(FSCACHE_IOERROR, &cache->flags))
120			cache = NULL;
121
122		spin_unlock(&cookie->lock);
123		_leave(" = %p [parent]", cache);
124		return cache;
125	}
126
127	/* the parent is unbacked */
128	if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) {
129		/* cookie not an index and is unbacked */
130		spin_unlock(&cookie->lock);
131		_leave(" = NULL [cookie ub,ni]");
132		return NULL;
133	}
134
135	spin_unlock(&cookie->lock);
136
137	if (!cookie->def->select_cache)
138		goto no_preference;
139
140	/* ask the netfs for its preference */
141	tag = cookie->def->select_cache(cookie->parent->netfs_data,
142					cookie->netfs_data);
143	if (!tag)
144		goto no_preference;
145
146	if (tag == ERR_PTR(-ENOMEM)) {
147		_leave(" = NULL [nomem tag]");
148		return NULL;
149	}
150
151	if (!tag->cache) {
152		_leave(" = NULL [unbacked tag]");
153		return NULL;
154	}
155
156	if (test_bit(FSCACHE_IOERROR, &tag->cache->flags))
157		return NULL;
158
159	_leave(" = %p [specific]", tag->cache);
160	return tag->cache;
161
162no_preference:
163	/* netfs has no preference - just select first cache */
164	cache = list_entry(fscache_cache_list.next,
165			   struct fscache_cache, link);
166	_leave(" = %p [first]", cache);
167	return cache;
168}
169
170/**
171 * fscache_init_cache - Initialise a cache record
172 * @cache: The cache record to be initialised
173 * @ops: The cache operations to be installed in that record
174 * @idfmt: Format string to define identifier
175 * @...: sprintf-style arguments
176 *
177 * Initialise a record of a cache and fill in the name.
178 *
179 * See Documentation/filesystems/caching/backend-api.txt for a complete
180 * description.
181 */
182void fscache_init_cache(struct fscache_cache *cache,
183			const struct fscache_cache_ops *ops,
184			const char *idfmt,
185			...)
186{
187	va_list va;
188
189	memset(cache, 0, sizeof(*cache));
190
191	cache->ops = ops;
192
193	va_start(va, idfmt);
194	vsnprintf(cache->identifier, sizeof(cache->identifier), idfmt, va);
195	va_end(va);
196
197	INIT_WORK(&cache->op_gc, fscache_operation_gc);
198	INIT_LIST_HEAD(&cache->link);
199	INIT_LIST_HEAD(&cache->object_list);
200	INIT_LIST_HEAD(&cache->op_gc_list);
201	spin_lock_init(&cache->object_list_lock);
202	spin_lock_init(&cache->op_gc_list_lock);
203}
204EXPORT_SYMBOL(fscache_init_cache);
205
206/**
207 * fscache_add_cache - Declare a cache as being open for business
208 * @cache: The record describing the cache
209 * @ifsdef: The record of the cache object describing the top-level index
210 * @tagname: The tag describing this cache
211 *
212 * Add a cache to the system, making it available for netfs's to use.
213 *
214 * See Documentation/filesystems/caching/backend-api.txt for a complete
215 * description.
216 */
217int fscache_add_cache(struct fscache_cache *cache,
218		      struct fscache_object *ifsdef,
219		      const char *tagname)
220{
221	struct fscache_cache_tag *tag;
222
223	BUG_ON(!cache->ops);
224	BUG_ON(!ifsdef);
225
226	cache->flags = 0;
227	ifsdef->event_mask = ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED);
228	ifsdef->state = FSCACHE_OBJECT_ACTIVE;
229
230	if (!tagname)
231		tagname = cache->identifier;
232
233	BUG_ON(!tagname[0]);
234
235	_enter("{%s.%s},,%s", cache->ops->name, cache->identifier, tagname);
236
237	/* we use the cache tag to uniquely identify caches */
238	tag = __fscache_lookup_cache_tag(tagname);
239	if (IS_ERR(tag))
240		goto nomem;
241
242	if (test_and_set_bit(FSCACHE_TAG_RESERVED, &tag->flags))
243		goto tag_in_use;
244
245	cache->kobj = kobject_create_and_add(tagname, fscache_root);
246	if (!cache->kobj)
247		goto error;
248
249	ifsdef->cookie = &fscache_fsdef_index;
250	ifsdef->cache = cache;
251	cache->fsdef = ifsdef;
252
253	down_write(&fscache_addremove_sem);
254
255	tag->cache = cache;
256	cache->tag = tag;
257
258	/* add the cache to the list */
259	list_add(&cache->link, &fscache_cache_list);
260
261	/* add the cache's netfs definition index object to the cache's
262	 * list */
263	spin_lock(&cache->object_list_lock);
264	list_add_tail(&ifsdef->cache_link, &cache->object_list);
265	spin_unlock(&cache->object_list_lock);
266	fscache_objlist_add(ifsdef);
267
268	/* add the cache's netfs definition index object to the top level index
269	 * cookie as a known backing object */
270	spin_lock(&fscache_fsdef_index.lock);
271
272	hlist_add_head(&ifsdef->cookie_link,
273		       &fscache_fsdef_index.backing_objects);
274
275	atomic_inc(&fscache_fsdef_index.usage);
276
277	/* done */
278	spin_unlock(&fscache_fsdef_index.lock);
279	up_write(&fscache_addremove_sem);
280
281	printk(KERN_NOTICE "FS-Cache: Cache \"%s\" added (type %s)\n",
282	       cache->tag->name, cache->ops->name);
283	kobject_uevent(cache->kobj, KOBJ_ADD);
284
285	_leave(" = 0 [%s]", cache->identifier);
286	return 0;
287
288tag_in_use:
289	printk(KERN_ERR "FS-Cache: Cache tag '%s' already in use\n", tagname);
290	__fscache_release_cache_tag(tag);
291	_leave(" = -EXIST");
292	return -EEXIST;
293
294error:
295	__fscache_release_cache_tag(tag);
296	_leave(" = -EINVAL");
297	return -EINVAL;
298
299nomem:
300	_leave(" = -ENOMEM");
301	return -ENOMEM;
302}
303EXPORT_SYMBOL(fscache_add_cache);
304
305/**
306 * fscache_io_error - Note a cache I/O error
307 * @cache: The record describing the cache
308 *
309 * Note that an I/O error occurred in a cache and that it should no longer be
310 * used for anything.  This also reports the error into the kernel log.
311 *
312 * See Documentation/filesystems/caching/backend-api.txt for a complete
313 * description.
314 */
315void fscache_io_error(struct fscache_cache *cache)
316{
317	set_bit(FSCACHE_IOERROR, &cache->flags);
318
319	printk(KERN_ERR "FS-Cache: Cache %s stopped due to I/O error\n",
320	       cache->ops->name);
321}
322EXPORT_SYMBOL(fscache_io_error);
323
324/*
325 * request withdrawal of all the objects in a cache
326 * - all the objects being withdrawn are moved onto the supplied list
327 */
328static void fscache_withdraw_all_objects(struct fscache_cache *cache,
329					 struct list_head *dying_objects)
330{
331	struct fscache_object *object;
332
333	spin_lock(&cache->object_list_lock);
334
335	while (!list_empty(&cache->object_list)) {
336		object = list_entry(cache->object_list.next,
337				    struct fscache_object, cache_link);
338		list_move_tail(&object->cache_link, dying_objects);
339
340		_debug("withdraw %p", object->cookie);
341
342		spin_lock(&object->lock);
343		spin_unlock(&cache->object_list_lock);
344		fscache_raise_event(object, FSCACHE_OBJECT_EV_WITHDRAW);
345		spin_unlock(&object->lock);
346
347		cond_resched();
348		spin_lock(&cache->object_list_lock);
349	}
350
351	spin_unlock(&cache->object_list_lock);
352}
353
354/**
355 * fscache_withdraw_cache - Withdraw a cache from the active service
356 * @cache: The record describing the cache
357 *
358 * Withdraw a cache from service, unbinding all its cache objects from the
359 * netfs cookies they're currently representing.
360 *
361 * See Documentation/filesystems/caching/backend-api.txt for a complete
362 * description.
363 */
364void fscache_withdraw_cache(struct fscache_cache *cache)
365{
366	LIST_HEAD(dying_objects);
367
368	_enter("");
369
370	printk(KERN_NOTICE "FS-Cache: Withdrawing cache \"%s\"\n",
371	       cache->tag->name);
372
373	/* make the cache unavailable for cookie acquisition */
374	if (test_and_set_bit(FSCACHE_CACHE_WITHDRAWN, &cache->flags))
375		BUG();
376
377	down_write(&fscache_addremove_sem);
378	list_del_init(&cache->link);
379	cache->tag->cache = NULL;
380	up_write(&fscache_addremove_sem);
381
382	/* make sure all pages pinned by operations on behalf of the netfs are
383	 * written to disk */
384	fscache_stat(&fscache_n_cop_sync_cache);
385	cache->ops->sync_cache(cache);
386	fscache_stat_d(&fscache_n_cop_sync_cache);
387
388	/* dissociate all the netfs pages backed by this cache from the block
389	 * mappings in the cache */
390	fscache_stat(&fscache_n_cop_dissociate_pages);
391	cache->ops->dissociate_pages(cache);
392	fscache_stat_d(&fscache_n_cop_dissociate_pages);
393
394	/* we now have to destroy all the active objects pertaining to this
395	 * cache - which we do by passing them off to thread pool to be
396	 * disposed of */
397	_debug("destroy");
398
399	fscache_withdraw_all_objects(cache, &dying_objects);
400
401	/* wait for all extant objects to finish their outstanding operations
402	 * and go away */
403	_debug("wait for finish");
404	wait_event(fscache_cache_cleared_wq,
405		   atomic_read(&cache->object_count) == 0);
406	_debug("wait for clearance");
407	wait_event(fscache_cache_cleared_wq,
408		   list_empty(&cache->object_list));
409	_debug("cleared");
410	ASSERT(list_empty(&dying_objects));
411
412	kobject_put(cache->kobj);
413
414	clear_bit(FSCACHE_TAG_RESERVED, &cache->tag->flags);
415	fscache_release_cache_tag(cache->tag);
416	cache->tag = NULL;
417
418	_leave("");
419}
420EXPORT_SYMBOL(fscache_withdraw_cache);
421