162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* Manage high-level VFS aspects of a cache.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2007, 2021 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/statfs.h>
1062306a36Sopenharmony_ci#include <linux/namei.h>
1162306a36Sopenharmony_ci#include "internal.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Bring a cache online.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ciint cachefiles_add_cache(struct cachefiles_cache *cache)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct fscache_cache *cache_cookie;
1962306a36Sopenharmony_ci	struct path path;
2062306a36Sopenharmony_ci	struct kstatfs stats;
2162306a36Sopenharmony_ci	struct dentry *graveyard, *cachedir, *root;
2262306a36Sopenharmony_ci	const struct cred *saved_cred;
2362306a36Sopenharmony_ci	int ret;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	_enter("");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	cache_cookie = fscache_acquire_cache(cache->tag);
2862306a36Sopenharmony_ci	if (IS_ERR(cache_cookie))
2962306a36Sopenharmony_ci		return PTR_ERR(cache_cookie);
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/* we want to work under the module's security ID */
3262306a36Sopenharmony_ci	ret = cachefiles_get_security_ID(cache);
3362306a36Sopenharmony_ci	if (ret < 0)
3462306a36Sopenharmony_ci		goto error_getsec;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	cachefiles_begin_secure(cache, &saved_cred);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* look up the directory at the root of the cache */
3962306a36Sopenharmony_ci	ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path);
4062306a36Sopenharmony_ci	if (ret < 0)
4162306a36Sopenharmony_ci		goto error_open_root;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	cache->mnt = path.mnt;
4462306a36Sopenharmony_ci	root = path.dentry;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ret = -EINVAL;
4762306a36Sopenharmony_ci	if (is_idmapped_mnt(path.mnt)) {
4862306a36Sopenharmony_ci		pr_warn("File cache on idmapped mounts not supported");
4962306a36Sopenharmony_ci		goto error_unsupported;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* Check features of the backing filesystem:
5362306a36Sopenharmony_ci	 * - Directories must support looking up and directory creation
5462306a36Sopenharmony_ci	 * - We create tmpfiles to handle invalidation
5562306a36Sopenharmony_ci	 * - We use xattrs to store metadata
5662306a36Sopenharmony_ci	 * - We need to be able to query the amount of space available
5762306a36Sopenharmony_ci	 * - We want to be able to sync the filesystem when stopping the cache
5862306a36Sopenharmony_ci	 * - We use DIO to/from pages, so the blocksize mustn't be too big.
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	ret = -EOPNOTSUPP;
6162306a36Sopenharmony_ci	if (d_is_negative(root) ||
6262306a36Sopenharmony_ci	    !d_backing_inode(root)->i_op->lookup ||
6362306a36Sopenharmony_ci	    !d_backing_inode(root)->i_op->mkdir ||
6462306a36Sopenharmony_ci	    !d_backing_inode(root)->i_op->tmpfile ||
6562306a36Sopenharmony_ci	    !(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
6662306a36Sopenharmony_ci	    !root->d_sb->s_op->statfs ||
6762306a36Sopenharmony_ci	    !root->d_sb->s_op->sync_fs ||
6862306a36Sopenharmony_ci	    root->d_sb->s_blocksize > PAGE_SIZE)
6962306a36Sopenharmony_ci		goto error_unsupported;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	ret = -EROFS;
7262306a36Sopenharmony_ci	if (sb_rdonly(root->d_sb))
7362306a36Sopenharmony_ci		goto error_unsupported;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* determine the security of the on-disk cache as this governs
7662306a36Sopenharmony_ci	 * security ID of files we create */
7762306a36Sopenharmony_ci	ret = cachefiles_determine_cache_security(cache, root, &saved_cred);
7862306a36Sopenharmony_ci	if (ret < 0)
7962306a36Sopenharmony_ci		goto error_unsupported;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* get the cache size and blocksize */
8262306a36Sopenharmony_ci	ret = vfs_statfs(&path, &stats);
8362306a36Sopenharmony_ci	if (ret < 0)
8462306a36Sopenharmony_ci		goto error_unsupported;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	ret = -ERANGE;
8762306a36Sopenharmony_ci	if (stats.f_bsize <= 0)
8862306a36Sopenharmony_ci		goto error_unsupported;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ret = -EOPNOTSUPP;
9162306a36Sopenharmony_ci	if (stats.f_bsize > PAGE_SIZE)
9262306a36Sopenharmony_ci		goto error_unsupported;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	cache->bsize = stats.f_bsize;
9562306a36Sopenharmony_ci	cache->bshift = ilog2(stats.f_bsize);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	_debug("blksize %u (shift %u)",
9862306a36Sopenharmony_ci	       cache->bsize, cache->bshift);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	_debug("size %llu, avail %llu",
10162306a36Sopenharmony_ci	       (unsigned long long) stats.f_blocks,
10262306a36Sopenharmony_ci	       (unsigned long long) stats.f_bavail);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* set up caching limits */
10562306a36Sopenharmony_ci	do_div(stats.f_files, 100);
10662306a36Sopenharmony_ci	cache->fstop = stats.f_files * cache->fstop_percent;
10762306a36Sopenharmony_ci	cache->fcull = stats.f_files * cache->fcull_percent;
10862306a36Sopenharmony_ci	cache->frun  = stats.f_files * cache->frun_percent;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	_debug("limits {%llu,%llu,%llu} files",
11162306a36Sopenharmony_ci	       (unsigned long long) cache->frun,
11262306a36Sopenharmony_ci	       (unsigned long long) cache->fcull,
11362306a36Sopenharmony_ci	       (unsigned long long) cache->fstop);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	do_div(stats.f_blocks, 100);
11662306a36Sopenharmony_ci	cache->bstop = stats.f_blocks * cache->bstop_percent;
11762306a36Sopenharmony_ci	cache->bcull = stats.f_blocks * cache->bcull_percent;
11862306a36Sopenharmony_ci	cache->brun  = stats.f_blocks * cache->brun_percent;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	_debug("limits {%llu,%llu,%llu} blocks",
12162306a36Sopenharmony_ci	       (unsigned long long) cache->brun,
12262306a36Sopenharmony_ci	       (unsigned long long) cache->bcull,
12362306a36Sopenharmony_ci	       (unsigned long long) cache->bstop);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* get the cache directory and check its type */
12662306a36Sopenharmony_ci	cachedir = cachefiles_get_directory(cache, root, "cache", NULL);
12762306a36Sopenharmony_ci	if (IS_ERR(cachedir)) {
12862306a36Sopenharmony_ci		ret = PTR_ERR(cachedir);
12962306a36Sopenharmony_ci		goto error_unsupported;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	cache->store = cachedir;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* get the graveyard directory */
13562306a36Sopenharmony_ci	graveyard = cachefiles_get_directory(cache, root, "graveyard", NULL);
13662306a36Sopenharmony_ci	if (IS_ERR(graveyard)) {
13762306a36Sopenharmony_ci		ret = PTR_ERR(graveyard);
13862306a36Sopenharmony_ci		goto error_unsupported;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	cache->graveyard = graveyard;
14262306a36Sopenharmony_ci	cache->cache = cache_cookie;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ret = fscache_add_cache(cache_cookie, &cachefiles_cache_ops, cache);
14562306a36Sopenharmony_ci	if (ret < 0)
14662306a36Sopenharmony_ci		goto error_add_cache;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* done */
14962306a36Sopenharmony_ci	set_bit(CACHEFILES_READY, &cache->flags);
15062306a36Sopenharmony_ci	dput(root);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	pr_info("File cache on %s registered\n", cache_cookie->name);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* check how much space the cache has */
15562306a36Sopenharmony_ci	cachefiles_has_space(cache, 0, 0, cachefiles_has_space_check);
15662306a36Sopenharmony_ci	cachefiles_end_secure(cache, saved_cred);
15762306a36Sopenharmony_ci	_leave(" = 0 [%px]", cache->cache);
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cierror_add_cache:
16162306a36Sopenharmony_ci	cachefiles_put_directory(cache->graveyard);
16262306a36Sopenharmony_ci	cache->graveyard = NULL;
16362306a36Sopenharmony_cierror_unsupported:
16462306a36Sopenharmony_ci	cachefiles_put_directory(cache->store);
16562306a36Sopenharmony_ci	cache->store = NULL;
16662306a36Sopenharmony_ci	mntput(cache->mnt);
16762306a36Sopenharmony_ci	cache->mnt = NULL;
16862306a36Sopenharmony_ci	dput(root);
16962306a36Sopenharmony_cierror_open_root:
17062306a36Sopenharmony_ci	cachefiles_end_secure(cache, saved_cred);
17162306a36Sopenharmony_ci	put_cred(cache->cache_cred);
17262306a36Sopenharmony_ci	cache->cache_cred = NULL;
17362306a36Sopenharmony_cierror_getsec:
17462306a36Sopenharmony_ci	fscache_relinquish_cache(cache_cookie);
17562306a36Sopenharmony_ci	cache->cache = NULL;
17662306a36Sopenharmony_ci	pr_err("Failed to register: %d\n", ret);
17762306a36Sopenharmony_ci	return ret;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * See if we have space for a number of pages and/or a number of files in the
18262306a36Sopenharmony_ci * cache
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_ciint cachefiles_has_space(struct cachefiles_cache *cache,
18562306a36Sopenharmony_ci			 unsigned fnr, unsigned bnr,
18662306a36Sopenharmony_ci			 enum cachefiles_has_space_for reason)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct kstatfs stats;
18962306a36Sopenharmony_ci	u64 b_avail, b_writing;
19062306a36Sopenharmony_ci	int ret;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	struct path path = {
19362306a36Sopenharmony_ci		.mnt	= cache->mnt,
19462306a36Sopenharmony_ci		.dentry	= cache->mnt->mnt_root,
19562306a36Sopenharmony_ci	};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	//_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u",
19862306a36Sopenharmony_ci	//       (unsigned long long) cache->frun,
19962306a36Sopenharmony_ci	//       (unsigned long long) cache->fcull,
20062306a36Sopenharmony_ci	//       (unsigned long long) cache->fstop,
20162306a36Sopenharmony_ci	//       (unsigned long long) cache->brun,
20262306a36Sopenharmony_ci	//       (unsigned long long) cache->bcull,
20362306a36Sopenharmony_ci	//       (unsigned long long) cache->bstop,
20462306a36Sopenharmony_ci	//       fnr, bnr);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* find out how many pages of blockdev are available */
20762306a36Sopenharmony_ci	memset(&stats, 0, sizeof(stats));
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ret = vfs_statfs(&path, &stats);
21062306a36Sopenharmony_ci	if (ret < 0) {
21162306a36Sopenharmony_ci		trace_cachefiles_vfs_error(NULL, d_inode(path.dentry), ret,
21262306a36Sopenharmony_ci					   cachefiles_trace_statfs_error);
21362306a36Sopenharmony_ci		if (ret == -EIO)
21462306a36Sopenharmony_ci			cachefiles_io_error(cache, "statfs failed");
21562306a36Sopenharmony_ci		_leave(" = %d", ret);
21662306a36Sopenharmony_ci		return ret;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	b_avail = stats.f_bavail;
22062306a36Sopenharmony_ci	b_writing = atomic_long_read(&cache->b_writing);
22162306a36Sopenharmony_ci	if (b_avail > b_writing)
22262306a36Sopenharmony_ci		b_avail -= b_writing;
22362306a36Sopenharmony_ci	else
22462306a36Sopenharmony_ci		b_avail = 0;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	//_debug("avail %llu,%llu",
22762306a36Sopenharmony_ci	//       (unsigned long long)stats.f_ffree,
22862306a36Sopenharmony_ci	//       (unsigned long long)b_avail);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* see if there is sufficient space */
23162306a36Sopenharmony_ci	if (stats.f_ffree > fnr)
23262306a36Sopenharmony_ci		stats.f_ffree -= fnr;
23362306a36Sopenharmony_ci	else
23462306a36Sopenharmony_ci		stats.f_ffree = 0;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (b_avail > bnr)
23762306a36Sopenharmony_ci		b_avail -= bnr;
23862306a36Sopenharmony_ci	else
23962306a36Sopenharmony_ci		b_avail = 0;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	ret = -ENOBUFS;
24262306a36Sopenharmony_ci	if (stats.f_ffree < cache->fstop ||
24362306a36Sopenharmony_ci	    b_avail < cache->bstop)
24462306a36Sopenharmony_ci		goto stop_and_begin_cull;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	ret = 0;
24762306a36Sopenharmony_ci	if (stats.f_ffree < cache->fcull ||
24862306a36Sopenharmony_ci	    b_avail < cache->bcull)
24962306a36Sopenharmony_ci		goto begin_cull;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (test_bit(CACHEFILES_CULLING, &cache->flags) &&
25262306a36Sopenharmony_ci	    stats.f_ffree >= cache->frun &&
25362306a36Sopenharmony_ci	    b_avail >= cache->brun &&
25462306a36Sopenharmony_ci	    test_and_clear_bit(CACHEFILES_CULLING, &cache->flags)
25562306a36Sopenharmony_ci	    ) {
25662306a36Sopenharmony_ci		_debug("cease culling");
25762306a36Sopenharmony_ci		cachefiles_state_changed(cache);
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	//_leave(" = 0");
26162306a36Sopenharmony_ci	return 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistop_and_begin_cull:
26462306a36Sopenharmony_ci	switch (reason) {
26562306a36Sopenharmony_ci	case cachefiles_has_space_for_write:
26662306a36Sopenharmony_ci		fscache_count_no_write_space();
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	case cachefiles_has_space_for_create:
26962306a36Sopenharmony_ci		fscache_count_no_create_space();
27062306a36Sopenharmony_ci		break;
27162306a36Sopenharmony_ci	default:
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_cibegin_cull:
27562306a36Sopenharmony_ci	if (!test_and_set_bit(CACHEFILES_CULLING, &cache->flags)) {
27662306a36Sopenharmony_ci		_debug("### CULL CACHE ###");
27762306a36Sopenharmony_ci		cachefiles_state_changed(cache);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	_leave(" = %d", ret);
28162306a36Sopenharmony_ci	return ret;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/*
28562306a36Sopenharmony_ci * Mark all the objects as being out of service and queue them all for cleanup.
28662306a36Sopenharmony_ci */
28762306a36Sopenharmony_cistatic void cachefiles_withdraw_objects(struct cachefiles_cache *cache)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct cachefiles_object *object;
29062306a36Sopenharmony_ci	unsigned int count = 0;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	_enter("");
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	spin_lock(&cache->object_list_lock);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	while (!list_empty(&cache->object_list)) {
29762306a36Sopenharmony_ci		object = list_first_entry(&cache->object_list,
29862306a36Sopenharmony_ci					  struct cachefiles_object, cache_link);
29962306a36Sopenharmony_ci		cachefiles_see_object(object, cachefiles_obj_see_withdrawal);
30062306a36Sopenharmony_ci		list_del_init(&object->cache_link);
30162306a36Sopenharmony_ci		fscache_withdraw_cookie(object->cookie);
30262306a36Sopenharmony_ci		count++;
30362306a36Sopenharmony_ci		if ((count & 63) == 0) {
30462306a36Sopenharmony_ci			spin_unlock(&cache->object_list_lock);
30562306a36Sopenharmony_ci			cond_resched();
30662306a36Sopenharmony_ci			spin_lock(&cache->object_list_lock);
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	spin_unlock(&cache->object_list_lock);
31162306a36Sopenharmony_ci	_leave(" [%u objs]", count);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * Withdraw volumes.
31662306a36Sopenharmony_ci */
31762306a36Sopenharmony_cistatic void cachefiles_withdraw_volumes(struct cachefiles_cache *cache)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	_enter("");
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	for (;;) {
32262306a36Sopenharmony_ci		struct cachefiles_volume *volume = NULL;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		spin_lock(&cache->object_list_lock);
32562306a36Sopenharmony_ci		if (!list_empty(&cache->volumes)) {
32662306a36Sopenharmony_ci			volume = list_first_entry(&cache->volumes,
32762306a36Sopenharmony_ci						  struct cachefiles_volume, cache_link);
32862306a36Sopenharmony_ci			list_del_init(&volume->cache_link);
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci		spin_unlock(&cache->object_list_lock);
33162306a36Sopenharmony_ci		if (!volume)
33262306a36Sopenharmony_ci			break;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		cachefiles_withdraw_volume(volume);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	_leave("");
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/*
34162306a36Sopenharmony_ci * Sync a cache to backing disk.
34262306a36Sopenharmony_ci */
34362306a36Sopenharmony_cistatic void cachefiles_sync_cache(struct cachefiles_cache *cache)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	const struct cred *saved_cred;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	_enter("%s", cache->cache->name);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* make sure all pages pinned by operations on behalf of the netfs are
35162306a36Sopenharmony_ci	 * written to disc */
35262306a36Sopenharmony_ci	cachefiles_begin_secure(cache, &saved_cred);
35362306a36Sopenharmony_ci	down_read(&cache->mnt->mnt_sb->s_umount);
35462306a36Sopenharmony_ci	ret = sync_filesystem(cache->mnt->mnt_sb);
35562306a36Sopenharmony_ci	up_read(&cache->mnt->mnt_sb->s_umount);
35662306a36Sopenharmony_ci	cachefiles_end_secure(cache, saved_cred);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (ret == -EIO)
35962306a36Sopenharmony_ci		cachefiles_io_error(cache,
36062306a36Sopenharmony_ci				    "Attempt to sync backing fs superblock returned error %d",
36162306a36Sopenharmony_ci				    ret);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci/*
36562306a36Sopenharmony_ci * Withdraw cache objects.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_civoid cachefiles_withdraw_cache(struct cachefiles_cache *cache)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct fscache_cache *fscache = cache->cache;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	pr_info("File cache on %s unregistering\n", fscache->name);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	fscache_withdraw_cache(fscache);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* we now have to destroy all the active objects pertaining to this
37662306a36Sopenharmony_ci	 * cache - which we do by passing them off to thread pool to be
37762306a36Sopenharmony_ci	 * disposed of */
37862306a36Sopenharmony_ci	cachefiles_withdraw_objects(cache);
37962306a36Sopenharmony_ci	fscache_wait_for_objects(fscache);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	cachefiles_withdraw_volumes(cache);
38262306a36Sopenharmony_ci	cachefiles_sync_cache(cache);
38362306a36Sopenharmony_ci	cache->cache = NULL;
38462306a36Sopenharmony_ci	fscache_relinquish_cache(fscache);
38562306a36Sopenharmony_ci}
386