Linux Audio

Check our new training course

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