cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cache.h (9159B)


      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 */
     47struct 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#define	CACHE_VALID	0	/* Entry contains valid data */
     60#define	CACHE_NEGATIVE	1	/* Negative entry - there is no match for the key */
     61#define	CACHE_PENDING	2	/* An upcall has been sent but no reply received yet*/
     62#define	CACHE_CLEANED	3	/* Entry has been cleaned from cache */
     63
     64#define	CACHE_NEW_EXPIRY 120	/* keep new things pending confirmation for 120 seconds */
     65
     66struct cache_detail {
     67	struct module *		owner;
     68	int			hash_size;
     69	struct hlist_head *	hash_table;
     70	spinlock_t		hash_lock;
     71
     72	char			*name;
     73	void			(*cache_put)(struct kref *);
     74
     75	int			(*cache_upcall)(struct cache_detail *,
     76						struct cache_head *);
     77
     78	void			(*cache_request)(struct cache_detail *cd,
     79						 struct cache_head *ch,
     80						 char **bpp, int *blen);
     81
     82	int			(*cache_parse)(struct cache_detail *,
     83					       char *buf, int len);
     84
     85	int			(*cache_show)(struct seq_file *m,
     86					      struct cache_detail *cd,
     87					      struct cache_head *h);
     88	void			(*warn_no_listener)(struct cache_detail *cd,
     89					      int has_died);
     90
     91	struct cache_head *	(*alloc)(void);
     92	void			(*flush)(void);
     93	int			(*match)(struct cache_head *orig, struct cache_head *new);
     94	void			(*init)(struct cache_head *orig, struct cache_head *new);
     95	void			(*update)(struct cache_head *orig, struct cache_head *new);
     96
     97	/* fields below this comment are for internal use
     98	 * and should not be touched by cache owners
     99	 */
    100	time64_t		flush_time;		/* flush all cache items with
    101							 * last_refresh at or earlier
    102							 * than this.  last_refresh
    103							 * is never set at or earlier
    104							 * than this.
    105							 */
    106	struct list_head	others;
    107	time64_t		nextcheck;
    108	int			entries;
    109
    110	/* fields for communication over channel */
    111	struct list_head	queue;
    112
    113	atomic_t		writers;		/* how many time is /channel open */
    114	time64_t		last_close;		/* if no writers, when did last close */
    115	time64_t		last_warn;		/* when we last warned about no writers */
    116
    117	union {
    118		struct proc_dir_entry	*procfs;
    119		struct dentry		*pipefs;
    120	};
    121	struct net		*net;
    122};
    123
    124/* this must be embedded in any request structure that
    125 * identifies an object that will want a callback on
    126 * a cache fill
    127 */
    128struct cache_req {
    129	struct cache_deferred_req *(*defer)(struct cache_req *req);
    130	unsigned long	thread_wait;	/* How long (jiffies) we can block the
    131					 * current thread to wait for updates.
    132					 */
    133};
    134
    135/* this must be embedded in a deferred_request that is being
    136 * delayed awaiting cache-fill
    137 */
    138struct cache_deferred_req {
    139	struct hlist_node	hash;	/* on hash chain */
    140	struct list_head	recent; /* on fifo */
    141	struct cache_head	*item;  /* cache item we wait on */
    142	void			*owner; /* we might need to discard all defered requests
    143					 * owned by someone */
    144	void			(*revisit)(struct cache_deferred_req *req,
    145					   int too_many);
    146};
    147
    148/*
    149 * timestamps kept in the cache are expressed in seconds
    150 * since boot.  This is the best for measuring differences in
    151 * real time.
    152 * This reimplemnts ktime_get_boottime_seconds() in a slightly
    153 * faster but less accurate way. When we end up converting
    154 * back to wallclock (CLOCK_REALTIME), that error often
    155 * cancels out during the reverse operation.
    156 */
    157static inline time64_t seconds_since_boot(void)
    158{
    159	struct timespec64 boot;
    160	getboottime64(&boot);
    161	return ktime_get_real_seconds() - boot.tv_sec;
    162}
    163
    164static inline time64_t convert_to_wallclock(time64_t sinceboot)
    165{
    166	struct timespec64 boot;
    167	getboottime64(&boot);
    168	return boot.tv_sec + sinceboot;
    169}
    170
    171extern const struct file_operations cache_file_operations_pipefs;
    172extern const struct file_operations content_file_operations_pipefs;
    173extern const struct file_operations cache_flush_operations_pipefs;
    174
    175extern struct cache_head *
    176sunrpc_cache_lookup_rcu(struct cache_detail *detail,
    177			struct cache_head *key, int hash);
    178extern struct cache_head *
    179sunrpc_cache_update(struct cache_detail *detail,
    180		    struct cache_head *new, struct cache_head *old, int hash);
    181
    182extern int
    183sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h);
    184extern int
    185sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
    186				 struct cache_head *h);
    187
    188
    189extern void cache_clean_deferred(void *owner);
    190
    191static inline struct cache_head  *cache_get(struct cache_head *h)
    192{
    193	kref_get(&h->ref);
    194	return h;
    195}
    196
    197static inline struct cache_head  *cache_get_rcu(struct cache_head *h)
    198{
    199	if (kref_get_unless_zero(&h->ref))
    200		return h;
    201	return NULL;
    202}
    203
    204static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
    205{
    206	if (kref_read(&h->ref) <= 2 &&
    207	    h->expiry_time < cd->nextcheck)
    208		cd->nextcheck = h->expiry_time;
    209	kref_put(&h->ref, cd->cache_put);
    210}
    211
    212static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h)
    213{
    214	if (h->expiry_time < seconds_since_boot())
    215		return true;
    216	if (!test_bit(CACHE_VALID, &h->flags))
    217		return false;
    218	return detail->flush_time >= h->last_refresh;
    219}
    220
    221extern int cache_check(struct cache_detail *detail,
    222		       struct cache_head *h, struct cache_req *rqstp);
    223extern void cache_flush(void);
    224extern void cache_purge(struct cache_detail *detail);
    225#define NEVER (0x7FFFFFFF)
    226extern void __init cache_initialize(void);
    227extern int cache_register_net(struct cache_detail *cd, struct net *net);
    228extern void cache_unregister_net(struct cache_detail *cd, struct net *net);
    229
    230extern struct cache_detail *cache_create_net(const struct cache_detail *tmpl, struct net *net);
    231extern void cache_destroy_net(struct cache_detail *cd, struct net *net);
    232
    233extern void sunrpc_init_cache_detail(struct cache_detail *cd);
    234extern void sunrpc_destroy_cache_detail(struct cache_detail *cd);
    235extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
    236					umode_t, struct cache_detail *);
    237extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
    238extern void sunrpc_cache_unhash(struct cache_detail *, struct cache_head *);
    239
    240/* Must store cache_detail in seq_file->private if using next three functions */
    241extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos);
    242extern void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos);
    243extern void cache_seq_stop_rcu(struct seq_file *file, void *p);
    244
    245extern void qword_add(char **bpp, int *lp, char *str);
    246extern void qword_addhex(char **bpp, int *lp, char *buf, int blen);
    247extern int qword_get(char **bpp, char *dest, int bufsize);
    248
    249static inline int get_int(char **bpp, int *anint)
    250{
    251	char buf[50];
    252	char *ep;
    253	int rv;
    254	int len = qword_get(bpp, buf, sizeof(buf));
    255
    256	if (len < 0)
    257		return -EINVAL;
    258	if (len == 0)
    259		return -ENOENT;
    260
    261	rv = simple_strtol(buf, &ep, 0);
    262	if (*ep)
    263		return -EINVAL;
    264
    265	*anint = rv;
    266	return 0;
    267}
    268
    269static inline int get_uint(char **bpp, unsigned int *anint)
    270{
    271	char buf[50];
    272	int len = qword_get(bpp, buf, sizeof(buf));
    273
    274	if (len < 0)
    275		return -EINVAL;
    276	if (len == 0)
    277		return -ENOENT;
    278
    279	if (kstrtouint(buf, 0, anint))
    280		return -EINVAL;
    281
    282	return 0;
    283}
    284
    285static inline int get_time(char **bpp, time64_t *time)
    286{
    287	char buf[50];
    288	long long ll;
    289	int len = qword_get(bpp, buf, sizeof(buf));
    290
    291	if (len < 0)
    292		return -EINVAL;
    293	if (len == 0)
    294		return -ENOENT;
    295
    296	if (kstrtoll(buf, 0, &ll))
    297		return -EINVAL;
    298
    299	*time = ll;
    300	return 0;
    301}
    302
    303static inline time64_t get_expiry(char **bpp)
    304{
    305	time64_t rv;
    306	struct timespec64 boot;
    307
    308	if (get_time(bpp, &rv))
    309		return 0;
    310	if (rv < 0)
    311		return 0;
    312	getboottime64(&boot);
    313	return rv - boot.tv_sec;
    314}
    315
    316#endif /*  _LINUX_SUNRPC_CACHE_H_ */