Linux Audio

Check our new training course

Loading...
v4.6
 
  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 (fscache_object_is_dying(object) ||
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 =
228		((1 << NR_FSCACHE_OBJECT_EVENTS) - 1) &
229		~(1 << FSCACHE_OBJECT_EV_CLEARED);
230	__set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &ifsdef->flags);
231
232	if (!tagname)
233		tagname = cache->identifier;
234
235	BUG_ON(!tagname[0]);
236
237	_enter("{%s.%s},,%s", cache->ops->name, cache->identifier, tagname);
238
239	/* we use the cache tag to uniquely identify caches */
240	tag = __fscache_lookup_cache_tag(tagname);
241	if (IS_ERR(tag))
242		goto nomem;
243
244	if (test_and_set_bit(FSCACHE_TAG_RESERVED, &tag->flags))
245		goto tag_in_use;
246
247	cache->kobj = kobject_create_and_add(tagname, fscache_root);
248	if (!cache->kobj)
249		goto error;
250
251	ifsdef->cookie = &fscache_fsdef_index;
252	ifsdef->cache = cache;
253	cache->fsdef = ifsdef;
254
255	down_write(&fscache_addremove_sem);
256
257	tag->cache = cache;
258	cache->tag = tag;
259
260	/* add the cache to the list */
261	list_add(&cache->link, &fscache_cache_list);
262
263	/* add the cache's netfs definition index object to the cache's
264	 * list */
265	spin_lock(&cache->object_list_lock);
266	list_add_tail(&ifsdef->cache_link, &cache->object_list);
267	spin_unlock(&cache->object_list_lock);
268	fscache_objlist_add(ifsdef);
269
270	/* add the cache's netfs definition index object to the top level index
271	 * cookie as a known backing object */
272	spin_lock(&fscache_fsdef_index.lock);
273
274	hlist_add_head(&ifsdef->cookie_link,
275		       &fscache_fsdef_index.backing_objects);
276
277	atomic_inc(&fscache_fsdef_index.usage);
278
279	/* done */
280	spin_unlock(&fscache_fsdef_index.lock);
281	up_write(&fscache_addremove_sem);
282
283	pr_notice("Cache \"%s\" added (type %s)\n",
284		  cache->tag->name, cache->ops->name);
285	kobject_uevent(cache->kobj, KOBJ_ADD);
286
287	_leave(" = 0 [%s]", cache->identifier);
288	return 0;
289
290tag_in_use:
291	pr_err("Cache tag '%s' already in use\n", tagname);
292	__fscache_release_cache_tag(tag);
293	_leave(" = -EXIST");
294	return -EEXIST;
295
296error:
297	__fscache_release_cache_tag(tag);
298	_leave(" = -EINVAL");
299	return -EINVAL;
300
301nomem:
302	_leave(" = -ENOMEM");
303	return -ENOMEM;
304}
305EXPORT_SYMBOL(fscache_add_cache);
306
307/**
308 * fscache_io_error - Note a cache I/O error
309 * @cache: The record describing the cache
310 *
311 * Note that an I/O error occurred in a cache and that it should no longer be
312 * used for anything.  This also reports the error into the kernel log.
313 *
314 * See Documentation/filesystems/caching/backend-api.txt for a complete
315 * description.
316 */
317void fscache_io_error(struct fscache_cache *cache)
318{
319	if (!test_and_set_bit(FSCACHE_IOERROR, &cache->flags))
320		pr_err("Cache '%s' stopped due to I/O error\n",
321		       cache->ops->name);
322}
323EXPORT_SYMBOL(fscache_io_error);
324
325/*
326 * request withdrawal of all the objects in a cache
327 * - all the objects being withdrawn are moved onto the supplied list
328 */
329static void fscache_withdraw_all_objects(struct fscache_cache *cache,
330					 struct list_head *dying_objects)
331{
332	struct fscache_object *object;
333
334	while (!list_empty(&cache->object_list)) {
335		spin_lock(&cache->object_list_lock);
336
337		if (!list_empty(&cache->object_list)) {
338			object = list_entry(cache->object_list.next,
339					    struct fscache_object, cache_link);
340			list_move_tail(&object->cache_link, dying_objects);
341
342			_debug("withdraw %p", object->cookie);
343
344			/* This must be done under object_list_lock to prevent
345			 * a race with fscache_drop_object().
346			 */
347			fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
348		}
349
350		spin_unlock(&cache->object_list_lock);
351		cond_resched();
352	}
353}
354
355/**
356 * fscache_withdraw_cache - Withdraw a cache from the active service
357 * @cache: The record describing the cache
358 *
359 * Withdraw a cache from service, unbinding all its cache objects from the
360 * netfs cookies they're currently representing.
361 *
362 * See Documentation/filesystems/caching/backend-api.txt for a complete
363 * description.
364 */
365void fscache_withdraw_cache(struct fscache_cache *cache)
366{
367	LIST_HEAD(dying_objects);
368
369	_enter("");
370
371	pr_notice("Withdrawing cache \"%s\"\n",
372		  cache->tag->name);
373
374	/* make the cache unavailable for cookie acquisition */
375	if (test_and_set_bit(FSCACHE_CACHE_WITHDRAWN, &cache->flags))
376		BUG();
377
378	down_write(&fscache_addremove_sem);
379	list_del_init(&cache->link);
380	cache->tag->cache = NULL;
381	up_write(&fscache_addremove_sem);
382
383	/* make sure all pages pinned by operations on behalf of the netfs are
384	 * written to disk */
385	fscache_stat(&fscache_n_cop_sync_cache);
386	cache->ops->sync_cache(cache);
387	fscache_stat_d(&fscache_n_cop_sync_cache);
388
389	/* dissociate all the netfs pages backed by this cache from the block
390	 * mappings in the cache */
391	fscache_stat(&fscache_n_cop_dissociate_pages);
392	cache->ops->dissociate_pages(cache);
393	fscache_stat_d(&fscache_n_cop_dissociate_pages);
394
395	/* we now have to destroy all the active objects pertaining to this
396	 * cache - which we do by passing them off to thread pool to be
397	 * disposed of */
398	_debug("destroy");
399
400	fscache_withdraw_all_objects(cache, &dying_objects);
401
402	/* wait for all extant objects to finish their outstanding operations
403	 * and go away */
404	_debug("wait for finish");
405	wait_event(fscache_cache_cleared_wq,
406		   atomic_read(&cache->object_count) == 0);
407	_debug("wait for clearance");
408	wait_event(fscache_cache_cleared_wq,
409		   list_empty(&cache->object_list));
410	_debug("cleared");
411	ASSERT(list_empty(&dying_objects));
412
413	kobject_put(cache->kobj);
414
415	clear_bit(FSCACHE_TAG_RESERVED, &cache->tag->flags);
416	fscache_release_cache_tag(cache->tag);
417	cache->tag = NULL;
418
419	_leave("");
420}
421EXPORT_SYMBOL(fscache_withdraw_cache);
v5.9
  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);