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); 26*a7733fb6SDavid 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 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 */ 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 */ 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 */ 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(); 1171e1236b8SDavid Howells destroy_workqueue(fscache_wq); 1181e1236b8SDavid Howells pr_notice("Unloaded\n"); 1191e1236b8SDavid Howells } 1201e1236b8SDavid Howells 1211e1236b8SDavid Howells module_exit(fscache_exit); 122