1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* General filesystem local caching manager 3 * 4 * Copyright (C) 2021 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/init.h> 11 #define CREATE_TRACE_POINTS 12 #include "internal.h" 13 14 MODULE_DESCRIPTION("FS Cache Manager"); 15 MODULE_AUTHOR("Red Hat, Inc."); 16 MODULE_LICENSE("GPL"); 17 18 unsigned fscache_debug; 19 module_param_named(debug, fscache_debug, uint, 20 S_IWUSR | S_IRUGO); 21 MODULE_PARM_DESC(fscache_debug, 22 "FS-Cache debugging mask"); 23 24 EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache); 25 EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume); 26 EXPORT_TRACEPOINT_SYMBOL(fscache_access); 27 28 struct workqueue_struct *fscache_wq; 29 EXPORT_SYMBOL(fscache_wq); 30 31 /* 32 * Mixing scores (in bits) for (7,20): 33 * Input delta: 1-bit 2-bit 34 * 1 round: 330.3 9201.6 35 * 2 rounds: 1246.4 25475.4 36 * 3 rounds: 1907.1 31295.1 37 * 4 rounds: 2042.3 31718.6 38 * Perfect: 2048 31744 39 * (32*64) (32*31/2 * 64) 40 */ 41 #define HASH_MIX(x, y, a) \ 42 ( x ^= (a), \ 43 y ^= x, x = rol32(x, 7),\ 44 x += y, y = rol32(y,20),\ 45 y *= 9 ) 46 47 static inline unsigned int fold_hash(unsigned long x, unsigned long y) 48 { 49 /* Use arch-optimized multiply if one exists */ 50 return __hash_32(y ^ __hash_32(x)); 51 } 52 53 /* 54 * Generate a hash. This is derived from full_name_hash(), but we want to be 55 * sure it is arch independent and that it doesn't change as bits of the 56 * computed hash value might appear on disk. The caller must guarantee that 57 * the source data is a multiple of four bytes in size. 58 */ 59 unsigned int fscache_hash(unsigned int salt, const void *data, size_t len) 60 { 61 const __le32 *p = data; 62 unsigned int a, x = 0, y = salt, n = len / sizeof(__le32); 63 64 for (; n; n--) { 65 a = le32_to_cpu(*p++); 66 HASH_MIX(x, y, a); 67 } 68 return fold_hash(x, y); 69 } 70 71 /* 72 * initialise the fs caching module 73 */ 74 static int __init fscache_init(void) 75 { 76 int ret = -ENOMEM; 77 78 fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0); 79 if (!fscache_wq) 80 goto error_wq; 81 82 ret = fscache_proc_init(); 83 if (ret < 0) 84 goto error_proc; 85 86 fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", 87 sizeof(struct fscache_cookie), 88 0, 0, NULL); 89 if (!fscache_cookie_jar) { 90 pr_notice("Failed to allocate a cookie jar\n"); 91 ret = -ENOMEM; 92 goto error_cookie_jar; 93 } 94 95 pr_notice("Loaded\n"); 96 return 0; 97 98 error_cookie_jar: 99 fscache_proc_cleanup(); 100 error_proc: 101 destroy_workqueue(fscache_wq); 102 error_wq: 103 return ret; 104 } 105 106 fs_initcall(fscache_init); 107 108 /* 109 * clean up on module removal 110 */ 111 static void __exit fscache_exit(void) 112 { 113 _enter(""); 114 115 kmem_cache_destroy(fscache_cookie_jar); 116 fscache_proc_cleanup(); 117 timer_shutdown_sync(&fscache_cookie_lru_timer); 118 destroy_workqueue(fscache_wq); 119 pr_notice("Unloaded\n"); 120 } 121 122 module_exit(fscache_exit); 123