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