1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * include/linux/sunrpc/cache.h |
4 | * |
5 | * Generic code for various authentication-related caches |
6 | * used by sunrpc clients and servers. |
7 | * |
8 | * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au> |
9 | */ |
10 | |
11 | #ifndef _LINUX_SUNRPC_CACHE_H_ |
12 | #define _LINUX_SUNRPC_CACHE_H_ |
13 | |
14 | #include <linux/kref.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/atomic.h> |
17 | #include <linux/kstrtox.h> |
18 | #include <linux/proc_fs.h> |
19 | |
20 | /* |
21 | * Each cache requires: |
22 | * - A 'struct cache_detail' which contains information specific to the cache |
23 | * for common code to use. |
24 | * - An item structure that must contain a "struct cache_head" |
25 | * - A lookup function defined using DefineCacheLookup |
26 | * - A 'put' function that can release a cache item. It will only |
27 | * be called after cache_put has succeed, so there are guarantee |
28 | * to be no references. |
29 | * - A function to calculate a hash of an item's key. |
30 | * |
31 | * as well as assorted code fragments (e.g. compare keys) and numbers |
32 | * (e.g. hash size, goal_age, etc). |
33 | * |
34 | * Each cache must be registered so that it can be cleaned regularly. |
35 | * When the cache is unregistered, it is flushed completely. |
36 | * |
37 | * Entries have a ref count and a 'hashed' flag which counts the existence |
38 | * in the hash table. |
39 | * We only expire entries when refcount is zero. |
40 | * Existence in the cache is counted the refcount. |
41 | */ |
42 | |
43 | /* Every cache item has a common header that is used |
44 | * for expiring and refreshing entries. |
45 | * |
46 | */ |
47 | struct cache_head { |
48 | struct hlist_node cache_list; |
49 | time64_t expiry_time; /* After time expiry_time, don't use |
50 | * the data */ |
51 | time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was |
52 | * sent, else this is when update was |
53 | * received, though it is alway set to |
54 | * be *after* ->flush_time. |
55 | */ |
56 | struct kref ref; |
57 | unsigned long flags; |
58 | }; |
59 | |
60 | /* cache_head.flags */ |
61 | enum { |
62 | CACHE_VALID, /* Entry contains valid data */ |
63 | CACHE_NEGATIVE, /* Negative entry - there is no match for the key */ |
64 | CACHE_PENDING, /* An upcall has been sent but no reply received yet*/ |
65 | CACHE_CLEANED, /* Entry has been cleaned from cache */ |
66 | }; |
67 | |
68 | #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */ |
69 | |
70 | struct cache_detail { |
71 | struct module * owner; |
72 | int hash_size; |
73 | struct hlist_head * hash_table; |
74 | spinlock_t hash_lock; |
75 | |
76 | char *name; |
77 | void (*cache_put)(struct kref *); |
78 | |
79 | int (*cache_upcall)(struct cache_detail *, |
80 | struct cache_head *); |
81 | |
82 | void (*cache_request)(struct cache_detail *cd, |
83 | struct cache_head *ch, |
84 | char **bpp, int *blen); |
85 | |
86 | int (*cache_parse)(struct cache_detail *, |
87 | char *buf, int len); |
88 | |
89 | int (*cache_show)(struct seq_file *m, |
90 | struct cache_detail *cd, |
91 | struct cache_head *h); |
92 | void (*warn_no_listener)(struct cache_detail *cd, |
93 | int has_died); |
94 | |
95 | struct cache_head * (*alloc)(void); |
96 | void (*flush)(void); |
97 | int (*match)(struct cache_head *orig, struct cache_head *new); |
98 | void (*init)(struct cache_head *orig, struct cache_head *new); |
99 | void (*update)(struct cache_head *orig, struct cache_head *new); |
100 | |
101 | /* fields below this comment are for internal use |
102 | * and should not be touched by cache owners |
103 | */ |
104 | time64_t flush_time; /* flush all cache items with |
105 | * last_refresh at or earlier |
106 | * than this. last_refresh |
107 | * is never set at or earlier |
108 | * than this. |
109 | */ |
110 | struct list_head others; |
111 | time64_t nextcheck; |
112 | int entries; |
113 | |
114 | /* fields for communication over channel */ |
115 | struct list_head queue; |
116 | |
117 | atomic_t writers; /* how many time is /channel open */ |
118 | time64_t last_close; /* if no writers, when did last close */ |
119 | time64_t last_warn; /* when we last warned about no writers */ |
120 | |
121 | union { |
122 | struct proc_dir_entry *procfs; |
123 | struct dentry *pipefs; |
124 | }; |
125 | struct net *net; |
126 | }; |
127 | |
128 | /* this must be embedded in any request structure that |
129 | * identifies an object that will want a callback on |
130 | * a cache fill |
131 | */ |
132 | struct cache_req { |
133 | struct cache_deferred_req *(*defer)(struct cache_req *req); |
134 | unsigned long thread_wait; /* How long (jiffies) we can block the |
135 | * current thread to wait for updates. |
136 | */ |
137 | }; |
138 | |
139 | /* this must be embedded in a deferred_request that is being |
140 | * delayed awaiting cache-fill |
141 | */ |
142 | struct cache_deferred_req { |
143 | struct hlist_node hash; /* on hash chain */ |
144 | struct list_head recent; /* on fifo */ |
145 | struct cache_head *item; /* cache item we wait on */ |
146 | void *owner; /* we might need to discard all defered requests |
147 | * owned by someone */ |
148 | void (*revisit)(struct cache_deferred_req *req, |
149 | int too_many); |
150 | }; |
151 | |
152 | /* |
153 | * timestamps kept in the cache are expressed in seconds |
154 | * since boot. This is the best for measuring differences in |
155 | * real time. |
156 | * This reimplemnts ktime_get_boottime_seconds() in a slightly |
157 | * faster but less accurate way. When we end up converting |
158 | * back to wallclock (CLOCK_REALTIME), that error often |
159 | * cancels out during the reverse operation. |
160 | */ |
161 | static inline time64_t seconds_since_boot(void) |
162 | { |
163 | struct timespec64 boot; |
164 | getboottime64(ts: &boot); |
165 | return ktime_get_real_seconds() - boot.tv_sec; |
166 | } |
167 | |
168 | static inline time64_t convert_to_wallclock(time64_t sinceboot) |
169 | { |
170 | struct timespec64 boot; |
171 | getboottime64(ts: &boot); |
172 | return boot.tv_sec + sinceboot; |
173 | } |
174 | |
175 | extern const struct file_operations cache_file_operations_pipefs; |
176 | extern const struct file_operations content_file_operations_pipefs; |
177 | extern const struct file_operations cache_flush_operations_pipefs; |
178 | |
179 | extern struct cache_head * |
180 | sunrpc_cache_lookup_rcu(struct cache_detail *detail, |
181 | struct cache_head *key, int hash); |
182 | extern struct cache_head * |
183 | sunrpc_cache_update(struct cache_detail *detail, |
184 | struct cache_head *new, struct cache_head *old, int hash); |
185 | |
186 | extern int |
187 | sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h); |
188 | extern int |
189 | sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail, |
190 | struct cache_head *h); |
191 | |
192 | |
193 | extern void cache_clean_deferred(void *owner); |
194 | |
195 | static inline struct cache_head *cache_get(struct cache_head *h) |
196 | { |
197 | kref_get(kref: &h->ref); |
198 | return h; |
199 | } |
200 | |
201 | static inline struct cache_head *cache_get_rcu(struct cache_head *h) |
202 | { |
203 | if (kref_get_unless_zero(kref: &h->ref)) |
204 | return h; |
205 | return NULL; |
206 | } |
207 | |
208 | static inline void cache_put(struct cache_head *h, struct cache_detail *cd) |
209 | { |
210 | if (kref_read(kref: &h->ref) <= 2 && |
211 | h->expiry_time < cd->nextcheck) |
212 | cd->nextcheck = h->expiry_time; |
213 | kref_put(kref: &h->ref, release: cd->cache_put); |
214 | } |
215 | |
216 | static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h) |
217 | { |
218 | if (h->expiry_time < seconds_since_boot()) |
219 | return true; |
220 | if (!test_bit(CACHE_VALID, &h->flags)) |
221 | return false; |
222 | return detail->flush_time >= h->last_refresh; |
223 | } |
224 | |
225 | extern int cache_check(struct cache_detail *detail, |
226 | struct cache_head *h, struct cache_req *rqstp); |
227 | extern void cache_flush(void); |
228 | extern void cache_purge(struct cache_detail *detail); |
229 | #define NEVER (0x7FFFFFFF) |
230 | extern void __init cache_initialize(void); |
231 | extern int cache_register_net(struct cache_detail *cd, struct net *net); |
232 | extern void cache_unregister_net(struct cache_detail *cd, struct net *net); |
233 | |
234 | extern struct cache_detail *cache_create_net(const struct cache_detail *tmpl, struct net *net); |
235 | extern void cache_destroy_net(struct cache_detail *cd, struct net *net); |
236 | |
237 | extern void sunrpc_init_cache_detail(struct cache_detail *cd); |
238 | extern void sunrpc_destroy_cache_detail(struct cache_detail *cd); |
239 | extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *, |
240 | umode_t, struct cache_detail *); |
241 | extern void sunrpc_cache_unregister_pipefs(struct cache_detail *); |
242 | extern void sunrpc_cache_unhash(struct cache_detail *, struct cache_head *); |
243 | |
244 | /* Must store cache_detail in seq_file->private if using next three functions */ |
245 | extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos); |
246 | extern void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos); |
247 | extern void cache_seq_stop_rcu(struct seq_file *file, void *p); |
248 | |
249 | extern void qword_add(char **bpp, int *lp, char *str); |
250 | extern void qword_addhex(char **bpp, int *lp, char *buf, int blen); |
251 | extern int qword_get(char **bpp, char *dest, int bufsize); |
252 | |
253 | static inline int get_int(char **bpp, int *anint) |
254 | { |
255 | char buf[50]; |
256 | char *ep; |
257 | int rv; |
258 | int len = qword_get(bpp, dest: buf, bufsize: sizeof(buf)); |
259 | |
260 | if (len < 0) |
261 | return -EINVAL; |
262 | if (len == 0) |
263 | return -ENOENT; |
264 | |
265 | rv = simple_strtol(buf, &ep, 0); |
266 | if (*ep) |
267 | return -EINVAL; |
268 | |
269 | *anint = rv; |
270 | return 0; |
271 | } |
272 | |
273 | static inline int get_uint(char **bpp, unsigned int *anint) |
274 | { |
275 | char buf[50]; |
276 | int len = qword_get(bpp, dest: buf, bufsize: sizeof(buf)); |
277 | |
278 | if (len < 0) |
279 | return -EINVAL; |
280 | if (len == 0) |
281 | return -ENOENT; |
282 | |
283 | if (kstrtouint(s: buf, base: 0, res: anint)) |
284 | return -EINVAL; |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static inline int get_time(char **bpp, time64_t *time) |
290 | { |
291 | char buf[50]; |
292 | long long ll; |
293 | int len = qword_get(bpp, dest: buf, bufsize: sizeof(buf)); |
294 | |
295 | if (len < 0) |
296 | return -EINVAL; |
297 | if (len == 0) |
298 | return -ENOENT; |
299 | |
300 | if (kstrtoll(s: buf, base: 0, res: &ll)) |
301 | return -EINVAL; |
302 | |
303 | *time = ll; |
304 | return 0; |
305 | } |
306 | |
307 | static inline int get_expiry(char **bpp, time64_t *rvp) |
308 | { |
309 | int error; |
310 | struct timespec64 boot; |
311 | |
312 | error = get_time(bpp, time: rvp); |
313 | if (error) |
314 | return error; |
315 | |
316 | getboottime64(ts: &boot); |
317 | (*rvp) -= boot.tv_sec; |
318 | return 0; |
319 | } |
320 | |
321 | #endif /* _LINUX_SUNRPC_CACHE_H_ */ |
322 | |