xref: /openbmc/linux/fs/fscache/main.c (revision 7f3283aba39a0f395700c3b5defa4ec49d9914b3)
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 
241e1236b8SDavid Howells struct workqueue_struct *fscache_wq;
251e1236b8SDavid Howells EXPORT_SYMBOL(fscache_wq);
261e1236b8SDavid Howells 
271e1236b8SDavid Howells /*
28e8a07c9dSDavid Howells  * Mixing scores (in bits) for (7,20):
29e8a07c9dSDavid Howells  * Input delta: 1-bit      2-bit
30e8a07c9dSDavid Howells  * 1 round:     330.3     9201.6
31e8a07c9dSDavid Howells  * 2 rounds:   1246.4    25475.4
32e8a07c9dSDavid Howells  * 3 rounds:   1907.1    31295.1
33e8a07c9dSDavid Howells  * 4 rounds:   2042.3    31718.6
34e8a07c9dSDavid Howells  * Perfect:    2048      31744
35e8a07c9dSDavid Howells  *            (32*64)   (32*31/2 * 64)
36e8a07c9dSDavid Howells  */
37e8a07c9dSDavid Howells #define HASH_MIX(x, y, a)	\
38e8a07c9dSDavid Howells 	(	x ^= (a),	\
39e8a07c9dSDavid Howells 	y ^= x,	x = rol32(x, 7),\
40e8a07c9dSDavid Howells 	x += y,	y = rol32(y,20),\
41e8a07c9dSDavid Howells 	y *= 9			)
42e8a07c9dSDavid Howells 
43e8a07c9dSDavid Howells static inline unsigned int fold_hash(unsigned long x, unsigned long y)
44e8a07c9dSDavid Howells {
45e8a07c9dSDavid Howells 	/* Use arch-optimized multiply if one exists */
46e8a07c9dSDavid Howells 	return __hash_32(y ^ __hash_32(x));
47e8a07c9dSDavid Howells }
48e8a07c9dSDavid Howells 
49e8a07c9dSDavid Howells /*
50e8a07c9dSDavid Howells  * Generate a hash.  This is derived from full_name_hash(), but we want to be
51e8a07c9dSDavid Howells  * sure it is arch independent and that it doesn't change as bits of the
52e8a07c9dSDavid Howells  * computed hash value might appear on disk.  The caller must guarantee that
53e8a07c9dSDavid Howells  * the source data is a multiple of four bytes in size.
54e8a07c9dSDavid Howells  */
55e8a07c9dSDavid Howells unsigned int fscache_hash(unsigned int salt, const void *data, size_t len)
56e8a07c9dSDavid Howells {
57e8a07c9dSDavid Howells 	const __le32 *p = data;
58e8a07c9dSDavid Howells 	unsigned int a, x = 0, y = salt, n = len / sizeof(__le32);
59e8a07c9dSDavid Howells 
60e8a07c9dSDavid Howells 	for (; n; n--) {
61e8a07c9dSDavid Howells 		a = le32_to_cpu(*p++);
62e8a07c9dSDavid Howells 		HASH_MIX(x, y, a);
63e8a07c9dSDavid Howells 	}
64e8a07c9dSDavid Howells 	return fold_hash(x, y);
65e8a07c9dSDavid Howells }
66e8a07c9dSDavid Howells 
67e8a07c9dSDavid Howells /*
681e1236b8SDavid Howells  * initialise the fs caching module
691e1236b8SDavid Howells  */
701e1236b8SDavid Howells static int __init fscache_init(void)
711e1236b8SDavid Howells {
721e1236b8SDavid Howells 	int ret = -ENOMEM;
731e1236b8SDavid Howells 
741e1236b8SDavid Howells 	fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0);
751e1236b8SDavid Howells 	if (!fscache_wq)
761e1236b8SDavid Howells 		goto error_wq;
771e1236b8SDavid Howells 
781e1236b8SDavid Howells 	ret = fscache_proc_init();
791e1236b8SDavid Howells 	if (ret < 0)
801e1236b8SDavid Howells 		goto error_proc;
811e1236b8SDavid Howells 
82*7f3283abSDavid Howells 	fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
83*7f3283abSDavid Howells 					       sizeof(struct fscache_cookie),
84*7f3283abSDavid Howells 					       0, 0, NULL);
85*7f3283abSDavid Howells 	if (!fscache_cookie_jar) {
86*7f3283abSDavid Howells 		pr_notice("Failed to allocate a cookie jar\n");
87*7f3283abSDavid Howells 		ret = -ENOMEM;
88*7f3283abSDavid Howells 		goto error_cookie_jar;
89*7f3283abSDavid Howells 	}
90*7f3283abSDavid Howells 
911e1236b8SDavid Howells 	pr_notice("Loaded\n");
921e1236b8SDavid Howells 	return 0;
931e1236b8SDavid Howells 
94*7f3283abSDavid Howells error_cookie_jar:
95*7f3283abSDavid Howells 	fscache_proc_cleanup();
961e1236b8SDavid Howells error_proc:
971e1236b8SDavid Howells 	destroy_workqueue(fscache_wq);
981e1236b8SDavid Howells error_wq:
991e1236b8SDavid Howells 	return ret;
1001e1236b8SDavid Howells }
1011e1236b8SDavid Howells 
1021e1236b8SDavid Howells fs_initcall(fscache_init);
1031e1236b8SDavid Howells 
1041e1236b8SDavid Howells /*
1051e1236b8SDavid Howells  * clean up on module removal
1061e1236b8SDavid Howells  */
1071e1236b8SDavid Howells static void __exit fscache_exit(void)
1081e1236b8SDavid Howells {
1091e1236b8SDavid Howells 	_enter("");
1101e1236b8SDavid Howells 
111*7f3283abSDavid Howells 	kmem_cache_destroy(fscache_cookie_jar);
1121e1236b8SDavid Howells 	fscache_proc_cleanup();
1131e1236b8SDavid Howells 	destroy_workqueue(fscache_wq);
1141e1236b8SDavid Howells 	pr_notice("Unloaded\n");
1151e1236b8SDavid Howells }
1161e1236b8SDavid Howells 
1171e1236b8SDavid Howells module_exit(fscache_exit);
118