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