162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* General filesystem local caching manager 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define FSCACHE_DEBUG_LEVEL CACHE 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1262306a36Sopenharmony_ci#include "internal.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciMODULE_DESCRIPTION("FS Cache Manager"); 1562306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc."); 1662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciunsigned fscache_debug; 1962306a36Sopenharmony_cimodule_param_named(debug, fscache_debug, uint, 2062306a36Sopenharmony_ci S_IWUSR | S_IRUGO); 2162306a36Sopenharmony_ciMODULE_PARM_DESC(fscache_debug, 2262306a36Sopenharmony_ci "FS-Cache debugging mask"); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(fscache_access_cache); 2562306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(fscache_access_volume); 2662306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(fscache_access); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct workqueue_struct *fscache_wq; 2962306a36Sopenharmony_ciEXPORT_SYMBOL(fscache_wq); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Mixing scores (in bits) for (7,20): 3362306a36Sopenharmony_ci * Input delta: 1-bit 2-bit 3462306a36Sopenharmony_ci * 1 round: 330.3 9201.6 3562306a36Sopenharmony_ci * 2 rounds: 1246.4 25475.4 3662306a36Sopenharmony_ci * 3 rounds: 1907.1 31295.1 3762306a36Sopenharmony_ci * 4 rounds: 2042.3 31718.6 3862306a36Sopenharmony_ci * Perfect: 2048 31744 3962306a36Sopenharmony_ci * (32*64) (32*31/2 * 64) 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci#define HASH_MIX(x, y, a) \ 4262306a36Sopenharmony_ci ( x ^= (a), \ 4362306a36Sopenharmony_ci y ^= x, x = rol32(x, 7),\ 4462306a36Sopenharmony_ci x += y, y = rol32(y,20),\ 4562306a36Sopenharmony_ci y *= 9 ) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline unsigned int fold_hash(unsigned long x, unsigned long y) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci /* Use arch-optimized multiply if one exists */ 5062306a36Sopenharmony_ci return __hash_32(y ^ __hash_32(x)); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Generate a hash. This is derived from full_name_hash(), but we want to be 5562306a36Sopenharmony_ci * sure it is arch independent and that it doesn't change as bits of the 5662306a36Sopenharmony_ci * computed hash value might appear on disk. The caller must guarantee that 5762306a36Sopenharmony_ci * the source data is a multiple of four bytes in size. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ciunsigned int fscache_hash(unsigned int salt, const void *data, size_t len) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci const __le32 *p = data; 6262306a36Sopenharmony_ci unsigned int a, x = 0, y = salt, n = len / sizeof(__le32); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (; n; n--) { 6562306a36Sopenharmony_ci a = le32_to_cpu(*p++); 6662306a36Sopenharmony_ci HASH_MIX(x, y, a); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci return fold_hash(x, y); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * initialise the fs caching module 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistatic int __init fscache_init(void) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int ret = -ENOMEM; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0); 7962306a36Sopenharmony_ci if (!fscache_wq) 8062306a36Sopenharmony_ci goto error_wq; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ret = fscache_proc_init(); 8362306a36Sopenharmony_ci if (ret < 0) 8462306a36Sopenharmony_ci goto error_proc; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar", 8762306a36Sopenharmony_ci sizeof(struct fscache_cookie), 8862306a36Sopenharmony_ci 0, 0, NULL); 8962306a36Sopenharmony_ci if (!fscache_cookie_jar) { 9062306a36Sopenharmony_ci pr_notice("Failed to allocate a cookie jar\n"); 9162306a36Sopenharmony_ci ret = -ENOMEM; 9262306a36Sopenharmony_ci goto error_cookie_jar; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci pr_notice("Loaded\n"); 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cierror_cookie_jar: 9962306a36Sopenharmony_ci fscache_proc_cleanup(); 10062306a36Sopenharmony_cierror_proc: 10162306a36Sopenharmony_ci destroy_workqueue(fscache_wq); 10262306a36Sopenharmony_cierror_wq: 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cifs_initcall(fscache_init); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * clean up on module removal 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistatic void __exit fscache_exit(void) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci _enter(""); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci kmem_cache_destroy(fscache_cookie_jar); 11662306a36Sopenharmony_ci fscache_proc_cleanup(); 11762306a36Sopenharmony_ci destroy_workqueue(fscache_wq); 11862306a36Sopenharmony_ci pr_notice("Unloaded\n"); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cimodule_exit(fscache_exit); 122