xref: /openbmc/linux/fs/fscache/main.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
11e1236b8SDavid Howells // SPDX-License-Identifier: GPL-2.0-or-later
21e1236b8SDavid Howells /* General filesystem local caching manager
31e1236b8SDavid Howells  *
41e1236b8SDavid Howells  * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
51e1236b8SDavid Howells  * Written by David Howells (dhowells@redhat.com)
61e1236b8SDavid Howells  */
71e1236b8SDavid Howells 
81e1236b8SDavid Howells #define FSCACHE_DEBUG_LEVEL CACHE
91e1236b8SDavid Howells #include <linux/module.h>
101e1236b8SDavid Howells #include <linux/init.h>
111e1236b8SDavid Howells #define CREATE_TRACE_POINTS
121e1236b8SDavid Howells #include "internal.h"
131e1236b8SDavid Howells 
141e1236b8SDavid Howells MODULE_DESCRIPTION("FS Cache Manager");
151e1236b8SDavid Howells MODULE_AUTHOR("Red Hat, Inc.");
161e1236b8SDavid Howells MODULE_LICENSE("GPL");
171e1236b8SDavid Howells 
181e1236b8SDavid Howells unsigned fscache_debug;
191e1236b8SDavid Howells module_param_named(debug, fscache_debug, uint,
201e1236b8SDavid Howells 		   S_IWUSR | S_IRUGO);
211e1236b8SDavid Howells MODULE_PARM_DESC(fscache_debug,
221e1236b8SDavid Howells 		 "FS-Cache debugging mask");
231e1236b8SDavid Howells 
2423e12e28SDavid Howells EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache);
25e6acd329SDavid Howells EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume);
26a7733fb6SDavid Howells EXPORT_TRACEPOINT_SYMBOL(fscache_access);
2723e12e28SDavid Howells 
281e1236b8SDavid Howells struct workqueue_struct *fscache_wq;
291e1236b8SDavid Howells EXPORT_SYMBOL(fscache_wq);
301e1236b8SDavid Howells 
311e1236b8SDavid Howells /*
32e8a07c9dSDavid Howells  * Mixing scores (in bits) for (7,20):
33e8a07c9dSDavid Howells  * Input delta: 1-bit      2-bit
34e8a07c9dSDavid Howells  * 1 round:     330.3     9201.6
35e8a07c9dSDavid Howells  * 2 rounds:   1246.4    25475.4
36e8a07c9dSDavid Howells  * 3 rounds:   1907.1    31295.1
37e8a07c9dSDavid Howells  * 4 rounds:   2042.3    31718.6
38e8a07c9dSDavid Howells  * Perfect:    2048      31744
39e8a07c9dSDavid Howells  *            (32*64)   (32*31/2 * 64)
40e8a07c9dSDavid Howells  */
41e8a07c9dSDavid Howells #define HASH_MIX(x, y, a)	\
42e8a07c9dSDavid Howells 	(	x ^= (a),	\
43e8a07c9dSDavid Howells 	y ^= x,	x = rol32(x, 7),\
44e8a07c9dSDavid Howells 	x += y,	y = rol32(y,20),\
45e8a07c9dSDavid Howells 	y *= 9			)
46e8a07c9dSDavid Howells 
fold_hash(unsigned long x,unsigned long y)47e8a07c9dSDavid Howells static inline unsigned int fold_hash(unsigned long x, unsigned long y)
48e8a07c9dSDavid Howells {
49e8a07c9dSDavid Howells 	/* Use arch-optimized multiply if one exists */
50e8a07c9dSDavid Howells 	return __hash_32(y ^ __hash_32(x));
51e8a07c9dSDavid Howells }
52e8a07c9dSDavid Howells 
53e8a07c9dSDavid Howells /*
54e8a07c9dSDavid Howells  * Generate a hash.  This is derived from full_name_hash(), but we want to be
55e8a07c9dSDavid Howells  * sure it is arch independent and that it doesn't change as bits of the
56e8a07c9dSDavid Howells  * computed hash value might appear on disk.  The caller must guarantee that
57e8a07c9dSDavid Howells  * the source data is a multiple of four bytes in size.
58e8a07c9dSDavid Howells  */
fscache_hash(unsigned int salt,const void * data,size_t len)59e8a07c9dSDavid Howells unsigned int fscache_hash(unsigned int salt, const void *data, size_t len)
60e8a07c9dSDavid Howells {
61e8a07c9dSDavid Howells 	const __le32 *p = data;
62e8a07c9dSDavid Howells 	unsigned int a, x = 0, y = salt, n = len / sizeof(__le32);
63e8a07c9dSDavid Howells 
64e8a07c9dSDavid Howells 	for (; n; n--) {
65e8a07c9dSDavid Howells 		a = le32_to_cpu(*p++);
66e8a07c9dSDavid Howells 		HASH_MIX(x, y, a);
67e8a07c9dSDavid Howells 	}
68e8a07c9dSDavid Howells 	return fold_hash(x, y);
69e8a07c9dSDavid Howells }
70e8a07c9dSDavid Howells 
71e8a07c9dSDavid Howells /*
721e1236b8SDavid Howells  * initialise the fs caching module
731e1236b8SDavid Howells  */
fscache_init(void)741e1236b8SDavid Howells static int __init fscache_init(void)
751e1236b8SDavid Howells {
761e1236b8SDavid Howells 	int ret = -ENOMEM;
771e1236b8SDavid Howells 
781e1236b8SDavid Howells 	fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0);
791e1236b8SDavid Howells 	if (!fscache_wq)
801e1236b8SDavid Howells 		goto error_wq;
811e1236b8SDavid Howells 
821e1236b8SDavid Howells 	ret = fscache_proc_init();
831e1236b8SDavid Howells 	if (ret < 0)
841e1236b8SDavid Howells 		goto error_proc;
851e1236b8SDavid Howells 
867f3283abSDavid Howells 	fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
877f3283abSDavid Howells 					       sizeof(struct fscache_cookie),
887f3283abSDavid Howells 					       0, 0, NULL);
897f3283abSDavid Howells 	if (!fscache_cookie_jar) {
907f3283abSDavid Howells 		pr_notice("Failed to allocate a cookie jar\n");
917f3283abSDavid Howells 		ret = -ENOMEM;
927f3283abSDavid Howells 		goto error_cookie_jar;
937f3283abSDavid Howells 	}
947f3283abSDavid Howells 
951e1236b8SDavid Howells 	pr_notice("Loaded\n");
961e1236b8SDavid Howells 	return 0;
971e1236b8SDavid Howells 
987f3283abSDavid Howells error_cookie_jar:
997f3283abSDavid Howells 	fscache_proc_cleanup();
1001e1236b8SDavid Howells error_proc:
1011e1236b8SDavid Howells 	destroy_workqueue(fscache_wq);
1021e1236b8SDavid Howells error_wq:
1031e1236b8SDavid Howells 	return ret;
1041e1236b8SDavid Howells }
1051e1236b8SDavid Howells 
1061e1236b8SDavid Howells fs_initcall(fscache_init);
1071e1236b8SDavid Howells 
1081e1236b8SDavid Howells /*
1091e1236b8SDavid Howells  * clean up on module removal
1101e1236b8SDavid Howells  */
fscache_exit(void)1111e1236b8SDavid Howells static void __exit fscache_exit(void)
1121e1236b8SDavid Howells {
1131e1236b8SDavid Howells 	_enter("");
1141e1236b8SDavid Howells 
1157f3283abSDavid Howells 	kmem_cache_destroy(fscache_cookie_jar);
1161e1236b8SDavid Howells 	fscache_proc_cleanup();
117*e0d72493SBaokun Li 	timer_shutdown_sync(&fscache_cookie_lru_timer);
1181e1236b8SDavid Howells 	destroy_workqueue(fscache_wq);
1191e1236b8SDavid Howells 	pr_notice("Unloaded\n");
1201e1236b8SDavid Howells }
1211e1236b8SDavid Howells 
1221e1236b8SDavid Howells module_exit(fscache_exit);
123