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 | |
15 | EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache); |
16 | EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume); |
17 | EXPORT_TRACEPOINT_SYMBOL(fscache_access); |
18 | |
19 | struct workqueue_struct *fscache_wq; |
20 | EXPORT_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 | |
38 | static inline unsigned int fold_hash(unsigned long x, unsigned long y) |
39 | { |
40 | /* Use arch-optimized multiply if one exists */ |
41 | return __hash_32(val: y ^ __hash_32(val: 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 | */ |
50 | unsigned 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 | */ |
65 | int __init fscache_init(void) |
66 | { |
67 | int ret = -ENOMEM; |
68 | |
69 | fscache_wq = alloc_workqueue(fmt: "fscache" , flags: WQ_UNBOUND | WQ_FREEZABLE, max_active: 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(name: "fscache_cookie_jar" , |
78 | size: sizeof(struct fscache_cookie), |
79 | align: 0, flags: 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 | |
89 | error_cookie_jar: |
90 | fscache_proc_cleanup(); |
91 | error_proc: |
92 | destroy_workqueue(wq: fscache_wq); |
93 | error_wq: |
94 | return ret; |
95 | } |
96 | |
97 | /* |
98 | * clean up on module removal |
99 | */ |
100 | void __exit fscache_exit(void) |
101 | { |
102 | _enter("" ); |
103 | |
104 | kmem_cache_destroy(s: fscache_cookie_jar); |
105 | fscache_proc_cleanup(); |
106 | destroy_workqueue(wq: fscache_wq); |
107 | pr_notice("FS-Cache unloaded\n" ); |
108 | } |
109 | |