1ddc64d0aSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * include/linux/sunrpc/cache.h
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Generic code for various authentication-related caches
61da177e4SLinus Torvalds * used by sunrpc clients and servers.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au>
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #ifndef _LINUX_SUNRPC_CACHE_H_
121da177e4SLinus Torvalds #define _LINUX_SUNRPC_CACHE_H_
131da177e4SLinus Torvalds
1457cc7215SAlexey Dobriyan #include <linux/kref.h>
151da177e4SLinus Torvalds #include <linux/slab.h>
1660063497SArun Sharma #include <linux/atomic.h>
174c527293SAndy Shevchenko #include <linux/kstrtox.h>
181da177e4SLinus Torvalds #include <linux/proc_fs.h>
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds /*
211da177e4SLinus Torvalds * Each cache requires:
221da177e4SLinus Torvalds * - A 'struct cache_detail' which contains information specific to the cache
231da177e4SLinus Torvalds * for common code to use.
241da177e4SLinus Torvalds * - An item structure that must contain a "struct cache_head"
251da177e4SLinus Torvalds * - A lookup function defined using DefineCacheLookup
261da177e4SLinus Torvalds * - A 'put' function that can release a cache item. It will only
271da177e4SLinus Torvalds * be called after cache_put has succeed, so there are guarantee
281da177e4SLinus Torvalds * to be no references.
291da177e4SLinus Torvalds * - A function to calculate a hash of an item's key.
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * as well as assorted code fragments (e.g. compare keys) and numbers
321da177e4SLinus Torvalds * (e.g. hash size, goal_age, etc).
331da177e4SLinus Torvalds *
341da177e4SLinus Torvalds * Each cache must be registered so that it can be cleaned regularly.
351da177e4SLinus Torvalds * When the cache is unregistered, it is flushed completely.
361da177e4SLinus Torvalds *
3725985edcSLucas De Marchi * Entries have a ref count and a 'hashed' flag which counts the existence
381da177e4SLinus Torvalds * in the hash table.
391da177e4SLinus Torvalds * We only expire entries when refcount is zero.
4025985edcSLucas De Marchi * Existence in the cache is counted the refcount.
411da177e4SLinus Torvalds */
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds /* Every cache item has a common header that is used
441da177e4SLinus Torvalds * for expiring and refreshing entries.
451da177e4SLinus Torvalds *
461da177e4SLinus Torvalds */
471da177e4SLinus Torvalds struct cache_head {
48129e5824SKinglong Mee struct hlist_node cache_list;
491138ce1cSRandy Dunlap time64_t expiry_time; /* After time expiry_time, don't use
501138ce1cSRandy Dunlap * the data */
51f559935eSArnd Bergmann time64_t last_refresh; /* If CACHE_PENDING, this is when upcall was
5277862036SNeil Brown * sent, else this is when update was
5377862036SNeil Brown * received, though it is alway set to
5477862036SNeil Brown * be *after* ->flush_time.
551da177e4SLinus Torvalds */
56baab935fSNeilBrown struct kref ref;
571da177e4SLinus Torvalds unsigned long flags;
581da177e4SLinus Torvalds };
59*ba4bba6cSNeilBrown
60*ba4bba6cSNeilBrown /* cache_head.flags */
61*ba4bba6cSNeilBrown enum {
62*ba4bba6cSNeilBrown CACHE_VALID, /* Entry contains valid data */
63*ba4bba6cSNeilBrown CACHE_NEGATIVE, /* Negative entry - there is no match for the key */
64*ba4bba6cSNeilBrown CACHE_PENDING, /* An upcall has been sent but no reply received yet*/
65*ba4bba6cSNeilBrown CACHE_CLEANED, /* Entry has been cleaned from cache */
66*ba4bba6cSNeilBrown };
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds #define CACHE_NEW_EXPIRY 120 /* keep new things pending confirmation for 120 seconds */
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds struct cache_detail {
71f35279d3SBruce Allan struct module * owner;
721da177e4SLinus Torvalds int hash_size;
73129e5824SKinglong Mee struct hlist_head * hash_table;
741863d77fSTrond Myklebust spinlock_t hash_lock;
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds char *name;
77baab935fSNeilBrown void (*cache_put)(struct kref *);
781da177e4SLinus Torvalds
79bc74b4f5STrond Myklebust int (*cache_upcall)(struct cache_detail *,
80bc74b4f5STrond Myklebust struct cache_head *);
81bc74b4f5STrond Myklebust
8273fb847aSStanislav Kinsbursky void (*cache_request)(struct cache_detail *cd,
8373fb847aSStanislav Kinsbursky struct cache_head *ch,
8473fb847aSStanislav Kinsbursky char **bpp, int *blen);
8573fb847aSStanislav Kinsbursky
861da177e4SLinus Torvalds int (*cache_parse)(struct cache_detail *,
871da177e4SLinus Torvalds char *buf, int len);
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds int (*cache_show)(struct seq_file *m,
901da177e4SLinus Torvalds struct cache_detail *cd,
911da177e4SLinus Torvalds struct cache_head *h);
922da8ca26STrond Myklebust void (*warn_no_listener)(struct cache_detail *cd,
932da8ca26STrond Myklebust int has_died);
941da177e4SLinus Torvalds
9515a5f6bdSNeilBrown struct cache_head * (*alloc)(void);
96f69d6d8eSJeff Layton void (*flush)(void);
9715a5f6bdSNeilBrown int (*match)(struct cache_head *orig, struct cache_head *new);
9815a5f6bdSNeilBrown void (*init)(struct cache_head *orig, struct cache_head *new);
9915a5f6bdSNeilBrown void (*update)(struct cache_head *orig, struct cache_head *new);
10015a5f6bdSNeilBrown
1011da177e4SLinus Torvalds /* fields below this comment are for internal use
1021da177e4SLinus Torvalds * and should not be touched by cache owners
1031da177e4SLinus Torvalds */
104f559935eSArnd Bergmann time64_t flush_time; /* flush all cache items with
10577862036SNeil Brown * last_refresh at or earlier
10677862036SNeil Brown * than this. last_refresh
10777862036SNeil Brown * is never set at or earlier
10877862036SNeil Brown * than this.
10977862036SNeil Brown */
1101da177e4SLinus Torvalds struct list_head others;
111f559935eSArnd Bergmann time64_t nextcheck;
1121da177e4SLinus Torvalds int entries;
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds /* fields for communication over channel */
1151da177e4SLinus Torvalds struct list_head queue;
1161da177e4SLinus Torvalds
11764a38e84SDave Wysochanski atomic_t writers; /* how many time is /channel open */
118f559935eSArnd Bergmann time64_t last_close; /* if no writers, when did last close */
119f559935eSArnd Bergmann time64_t last_warn; /* when we last warned about no writers */
120173912a6STrond Myklebust
121173912a6STrond Myklebust union {
122863d7d9cSKinglong Mee struct proc_dir_entry *procfs;
123863d7d9cSKinglong Mee struct dentry *pipefs;
124863d7d9cSKinglong Mee };
1250a402d5aSStanislav Kinsbursky struct net *net;
1261da177e4SLinus Torvalds };
1271da177e4SLinus Torvalds
1281da177e4SLinus Torvalds /* this must be embedded in any request structure that
1291da177e4SLinus Torvalds * identifies an object that will want a callback on
1301da177e4SLinus Torvalds * a cache fill
1311da177e4SLinus Torvalds */
1321da177e4SLinus Torvalds struct cache_req {
1331da177e4SLinus Torvalds struct cache_deferred_req *(*defer)(struct cache_req *req);
1340b6c14bdSChuck Lever unsigned long thread_wait; /* How long (jiffies) we can block the
135f16b6e8dSNeilBrown * current thread to wait for updates.
136f16b6e8dSNeilBrown */
1371da177e4SLinus Torvalds };
1380b6c14bdSChuck Lever
1391da177e4SLinus Torvalds /* this must be embedded in a deferred_request that is being
1401da177e4SLinus Torvalds * delayed awaiting cache-fill
1411da177e4SLinus Torvalds */
1421da177e4SLinus Torvalds struct cache_deferred_req {
14311174492SNeilBrown struct hlist_node hash; /* on hash chain */
1441da177e4SLinus Torvalds struct list_head recent; /* on fifo */
1451da177e4SLinus Torvalds struct cache_head *item; /* cache item we wait on */
1461da177e4SLinus Torvalds void *owner; /* we might need to discard all defered requests
1471da177e4SLinus Torvalds * owned by someone */
1481da177e4SLinus Torvalds void (*revisit)(struct cache_deferred_req *req,
1491da177e4SLinus Torvalds int too_many);
1501da177e4SLinus Torvalds };
1511da177e4SLinus Torvalds
1527715cde8SNeilBrown /*
1537715cde8SNeilBrown * timestamps kept in the cache are expressed in seconds
1547715cde8SNeilBrown * since boot. This is the best for measuring differences in
1557715cde8SNeilBrown * real time.
156f559935eSArnd Bergmann * This reimplemnts ktime_get_boottime_seconds() in a slightly
157f559935eSArnd Bergmann * faster but less accurate way. When we end up converting
158f559935eSArnd Bergmann * back to wallclock (CLOCK_REALTIME), that error often
159f559935eSArnd Bergmann * cancels out during the reverse operation.
1607715cde8SNeilBrown */
seconds_since_boot(void)161f559935eSArnd Bergmann static inline time64_t seconds_since_boot(void)
1627715cde8SNeilBrown {
163f559935eSArnd Bergmann struct timespec64 boot;
164f559935eSArnd Bergmann getboottime64(&boot);
165f559935eSArnd Bergmann return ktime_get_real_seconds() - boot.tv_sec;
1667715cde8SNeilBrown }
1677715cde8SNeilBrown
convert_to_wallclock(time64_t sinceboot)168f559935eSArnd Bergmann static inline time64_t convert_to_wallclock(time64_t sinceboot)
1697715cde8SNeilBrown {
170f559935eSArnd Bergmann struct timespec64 boot;
171f559935eSArnd Bergmann getboottime64(&boot);
1727715cde8SNeilBrown return boot.tv_sec + sinceboot;
1737715cde8SNeilBrown }
1747d317f2cSNeilBrown
1758854e82dSTrond Myklebust extern const struct file_operations cache_file_operations_pipefs;
1768854e82dSTrond Myklebust extern const struct file_operations content_file_operations_pipefs;
1778854e82dSTrond Myklebust extern const struct file_operations cache_flush_operations_pipefs;
1788854e82dSTrond Myklebust
17915a5f6bdSNeilBrown extern struct cache_head *
180ae74136bSTrond Myklebust sunrpc_cache_lookup_rcu(struct cache_detail *detail,
181ae74136bSTrond Myklebust struct cache_head *key, int hash);
182ae74136bSTrond Myklebust extern struct cache_head *
18315a5f6bdSNeilBrown sunrpc_cache_update(struct cache_detail *detail,
18415a5f6bdSNeilBrown struct cache_head *new, struct cache_head *old, int hash);
18515a5f6bdSNeilBrown
186bc74b4f5STrond Myklebust extern int
18721cd1254SStanislav Kinsbursky sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h);
18865286b88STrond Myklebust extern int
18965286b88STrond Myklebust sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
19065286b88STrond Myklebust struct cache_head *h);
191bc74b4f5STrond Myklebust
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds extern void cache_clean_deferred(void *owner);
1941da177e4SLinus Torvalds
cache_get(struct cache_head * h)1951da177e4SLinus Torvalds static inline struct cache_head *cache_get(struct cache_head *h)
1961da177e4SLinus Torvalds {
197baab935fSNeilBrown kref_get(&h->ref);
1981da177e4SLinus Torvalds return h;
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds
cache_get_rcu(struct cache_head * h)201ae74136bSTrond Myklebust static inline struct cache_head *cache_get_rcu(struct cache_head *h)
202ae74136bSTrond Myklebust {
203ae74136bSTrond Myklebust if (kref_get_unless_zero(&h->ref))
204ae74136bSTrond Myklebust return h;
205ae74136bSTrond Myklebust return NULL;
206ae74136bSTrond Myklebust }
2071da177e4SLinus Torvalds
cache_put(struct cache_head * h,struct cache_detail * cd)208baab935fSNeilBrown static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
2091da177e4SLinus Torvalds {
2102c935bc5SPeter Zijlstra if (kref_read(&h->ref) <= 2 &&
2111da177e4SLinus Torvalds h->expiry_time < cd->nextcheck)
2121da177e4SLinus Torvalds cd->nextcheck = h->expiry_time;
213baab935fSNeilBrown kref_put(&h->ref, cd->cache_put);
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds
cache_is_expired(struct cache_detail * detail,struct cache_head * h)216d6fc8821SKinglong Mee static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h)
2177b2b1feeSGreg Banks {
2189a81ef42SJ. Bruce Fields if (h->expiry_time < seconds_since_boot())
2199a81ef42SJ. Bruce Fields return true;
2209a81ef42SJ. Bruce Fields if (!test_bit(CACHE_VALID, &h->flags))
2219a81ef42SJ. Bruce Fields return false;
2229a81ef42SJ. Bruce Fields return detail->flush_time >= h->last_refresh;
2237b2b1feeSGreg Banks }
2247b2b1feeSGreg Banks
2251da177e4SLinus Torvalds extern int cache_check(struct cache_detail *detail,
2261da177e4SLinus Torvalds struct cache_head *h, struct cache_req *rqstp);
2271da177e4SLinus Torvalds extern void cache_flush(void);
2281da177e4SLinus Torvalds extern void cache_purge(struct cache_detail *detail);
2291da177e4SLinus Torvalds #define NEVER (0x7FFFFFFF)
2308eab945cSArtem Bityutskiy extern void __init cache_initialize(void);
231593ce16bSPavel Emelyanov extern int cache_register_net(struct cache_detail *cd, struct net *net);
232593ce16bSPavel Emelyanov extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
2331da177e4SLinus Torvalds
234d34971a6SBhumika Goyal extern struct cache_detail *cache_create_net(const struct cache_detail *tmpl, struct net *net);
2350a402d5aSStanislav Kinsbursky extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
2360a402d5aSStanislav Kinsbursky
237820f9442SStanislav Kinsbursky extern void sunrpc_init_cache_detail(struct cache_detail *cd);
238820f9442SStanislav Kinsbursky extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
2398854e82dSTrond Myklebust extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
24064f1426fSAl Viro umode_t, struct cache_detail *);
2418854e82dSTrond Myklebust extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
2422b477c00SNeil Brown extern void sunrpc_cache_unhash(struct cache_detail *, struct cache_head *);
2438854e82dSTrond Myklebust
244c8c081b7SKinglong Mee /* Must store cache_detail in seq_file->private if using next three functions */
245ae74136bSTrond Myklebust extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos);
246ae74136bSTrond Myklebust extern void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos);
247ae74136bSTrond Myklebust extern void cache_seq_stop_rcu(struct seq_file *file, void *p);
248c8c081b7SKinglong Mee
2491da177e4SLinus Torvalds extern void qword_add(char **bpp, int *lp, char *str);
2501da177e4SLinus Torvalds extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
2511da177e4SLinus Torvalds extern int qword_get(char **bpp, char *dest, int bufsize);
2521da177e4SLinus Torvalds
get_int(char ** bpp,int * anint)2531da177e4SLinus Torvalds static inline int get_int(char **bpp, int *anint)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds char buf[50];
256621eb19cSJ. Bruce Fields char *ep;
257621eb19cSJ. Bruce Fields int rv;
258d9c2ede6SEldad Zack int len = qword_get(bpp, buf, sizeof(buf));
259d9c2ede6SEldad Zack
260d9c2ede6SEldad Zack if (len < 0)
261d9c2ede6SEldad Zack return -EINVAL;
262d9c2ede6SEldad Zack if (len == 0)
263d9c2ede6SEldad Zack return -ENOENT;
264d9c2ede6SEldad Zack
265621eb19cSJ. Bruce Fields rv = simple_strtol(buf, &ep, 0);
266621eb19cSJ. Bruce Fields if (*ep)
267d9c2ede6SEldad Zack return -EINVAL;
268d9c2ede6SEldad Zack
269621eb19cSJ. Bruce Fields *anint = rv;
2701da177e4SLinus Torvalds return 0;
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds
get_uint(char ** bpp,unsigned int * anint)273a007c4c3SJ. Bruce Fields static inline int get_uint(char **bpp, unsigned int *anint)
274a007c4c3SJ. Bruce Fields {
275a007c4c3SJ. Bruce Fields char buf[50];
276a007c4c3SJ. Bruce Fields int len = qword_get(bpp, buf, sizeof(buf));
277a007c4c3SJ. Bruce Fields
278a007c4c3SJ. Bruce Fields if (len < 0)
279a007c4c3SJ. Bruce Fields return -EINVAL;
280a007c4c3SJ. Bruce Fields if (len == 0)
281a007c4c3SJ. Bruce Fields return -ENOENT;
282a007c4c3SJ. Bruce Fields
283a007c4c3SJ. Bruce Fields if (kstrtouint(buf, 0, anint))
284a007c4c3SJ. Bruce Fields return -EINVAL;
285a007c4c3SJ. Bruce Fields
286a007c4c3SJ. Bruce Fields return 0;
287a007c4c3SJ. Bruce Fields }
288a007c4c3SJ. Bruce Fields
get_time(char ** bpp,time64_t * time)289f559935eSArnd Bergmann static inline int get_time(char **bpp, time64_t *time)
2902f74f972SHarshula Jayasuriya {
2912f74f972SHarshula Jayasuriya char buf[50];
2922f74f972SHarshula Jayasuriya long long ll;
2932f74f972SHarshula Jayasuriya int len = qword_get(bpp, buf, sizeof(buf));
2942f74f972SHarshula Jayasuriya
2952f74f972SHarshula Jayasuriya if (len < 0)
2962f74f972SHarshula Jayasuriya return -EINVAL;
2972f74f972SHarshula Jayasuriya if (len == 0)
2982f74f972SHarshula Jayasuriya return -ENOENT;
2992f74f972SHarshula Jayasuriya
3002f74f972SHarshula Jayasuriya if (kstrtoll(buf, 0, &ll))
3012f74f972SHarshula Jayasuriya return -EINVAL;
3022f74f972SHarshula Jayasuriya
303f559935eSArnd Bergmann *time = ll;
3042f74f972SHarshula Jayasuriya return 0;
3052f74f972SHarshula Jayasuriya }
3062f74f972SHarshula Jayasuriya
get_expiry(char ** bpp,time64_t * rvp)307cf64b9bcSNeilBrown static inline int get_expiry(char **bpp, time64_t *rvp)
3081da177e4SLinus Torvalds {
309cf64b9bcSNeilBrown int error;
310f559935eSArnd Bergmann struct timespec64 boot;
311c5b29f88SNeilBrown
312cf64b9bcSNeilBrown error = get_time(bpp, rvp);
313cf64b9bcSNeilBrown if (error)
314cf64b9bcSNeilBrown return error;
315cf64b9bcSNeilBrown
316f559935eSArnd Bergmann getboottime64(&boot);
317cf64b9bcSNeilBrown (*rvp) -= boot.tv_sec;
318cf64b9bcSNeilBrown return 0;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds
3211da177e4SLinus Torvalds #endif /* _LINUX_SUNRPC_CACHE_H_ */
322