xref: /linux/net/sunrpc/cache.c (revision 9dbc1f45d512f3a90c1df8ac35bcb7a4db548286)
1ddc64d0aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * net/sunrpc/cache.c
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 #include <linux/types.h>
121da177e4SLinus Torvalds #include <linux/fs.h>
131da177e4SLinus Torvalds #include <linux/file.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
151da177e4SLinus Torvalds #include <linux/signal.h>
161da177e4SLinus Torvalds #include <linux/sched.h>
171da177e4SLinus Torvalds #include <linux/kmod.h>
181da177e4SLinus Torvalds #include <linux/list.h>
191da177e4SLinus Torvalds #include <linux/module.h>
201da177e4SLinus Torvalds #include <linux/ctype.h>
211b2e122dSAndy Shevchenko #include <linux/string_helpers.h>
227c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
231da177e4SLinus Torvalds #include <linux/poll.h>
241da177e4SLinus Torvalds #include <linux/seq_file.h>
251da177e4SLinus Torvalds #include <linux/proc_fs.h>
261da177e4SLinus Torvalds #include <linux/net.h>
271da177e4SLinus Torvalds #include <linux/workqueue.h>
284a3e2f71SArjan van de Ven #include <linux/mutex.h>
29da77005fSTrond Myklebust #include <linux/pagemap.h>
301da177e4SLinus Torvalds #include <asm/ioctls.h>
311da177e4SLinus Torvalds #include <linux/sunrpc/types.h>
321da177e4SLinus Torvalds #include <linux/sunrpc/cache.h>
331da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
348854e82dSTrond Myklebust #include <linux/sunrpc/rpc_pipe_fs.h>
3578a947f5STrond Myklebust #include <trace/events/sunrpc.h>
364f42d0d5SPavel Emelyanov #include "netns.h"
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #define	 RPCDBG_FACILITY RPCDBG_CACHE
391da177e4SLinus Torvalds 
40d76d1815SJ. Bruce Fields static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
411da177e4SLinus Torvalds static void cache_revisit_request(struct cache_head *item);
421da177e4SLinus Torvalds 
4377862036SNeil Brown static void cache_init(struct cache_head *h, struct cache_detail *detail)
441da177e4SLinus Torvalds {
45f559935eSArnd Bergmann 	time64_t now = seconds_since_boot();
46129e5824SKinglong Mee 	INIT_HLIST_NODE(&h->cache_list);
471da177e4SLinus Torvalds 	h->flags = 0;
48baab935fSNeilBrown 	kref_init(&h->ref);
491da177e4SLinus Torvalds 	h->expiry_time = now + CACHE_NEW_EXPIRY;
5077862036SNeil Brown 	if (now <= detail->flush_time)
5177862036SNeil Brown 		/* ensure it isn't already expired */
5277862036SNeil Brown 		now = detail->flush_time + 1;
531da177e4SLinus Torvalds 	h->last_refresh = now;
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
564ecd55eaSVasily Averin static void cache_fresh_unlocked(struct cache_head *head,
574ecd55eaSVasily Averin 				struct cache_detail *detail);
584ecd55eaSVasily Averin 
59ae74136bSTrond Myklebust static struct cache_head *sunrpc_cache_find_rcu(struct cache_detail *detail,
60ae74136bSTrond Myklebust 						struct cache_head *key,
61ae74136bSTrond Myklebust 						int hash)
62ae74136bSTrond Myklebust {
63ae74136bSTrond Myklebust 	struct hlist_head *head = &detail->hash_table[hash];
64ae74136bSTrond Myklebust 	struct cache_head *tmp;
65ae74136bSTrond Myklebust 
66ae74136bSTrond Myklebust 	rcu_read_lock();
67ae74136bSTrond Myklebust 	hlist_for_each_entry_rcu(tmp, head, cache_list) {
68277f27e2STrond Myklebust 		if (!detail->match(tmp, key))
69277f27e2STrond Myklebust 			continue;
70277f27e2STrond Myklebust 		if (test_bit(CACHE_VALID, &tmp->flags) &&
71277f27e2STrond Myklebust 		    cache_is_expired(detail, tmp))
72ae74136bSTrond Myklebust 			continue;
73ae74136bSTrond Myklebust 		tmp = cache_get_rcu(tmp);
74ae74136bSTrond Myklebust 		rcu_read_unlock();
75ae74136bSTrond Myklebust 		return tmp;
76ae74136bSTrond Myklebust 	}
77ae74136bSTrond Myklebust 	rcu_read_unlock();
78ae74136bSTrond Myklebust 	return NULL;
79ae74136bSTrond Myklebust }
80ae74136bSTrond Myklebust 
81809fe3c5STrond Myklebust static void sunrpc_begin_cache_remove_entry(struct cache_head *ch,
82809fe3c5STrond Myklebust 					    struct cache_detail *cd)
83809fe3c5STrond Myklebust {
84809fe3c5STrond Myklebust 	/* Must be called under cd->hash_lock */
85809fe3c5STrond Myklebust 	hlist_del_init_rcu(&ch->cache_list);
86809fe3c5STrond Myklebust 	set_bit(CACHE_CLEANED, &ch->flags);
87809fe3c5STrond Myklebust 	cd->entries --;
88809fe3c5STrond Myklebust }
89809fe3c5STrond Myklebust 
90809fe3c5STrond Myklebust static void sunrpc_end_cache_remove_entry(struct cache_head *ch,
91809fe3c5STrond Myklebust 					  struct cache_detail *cd)
92809fe3c5STrond Myklebust {
93809fe3c5STrond Myklebust 	cache_fresh_unlocked(ch, cd);
94809fe3c5STrond Myklebust 	cache_put(ch, cd);
95809fe3c5STrond Myklebust }
96809fe3c5STrond Myklebust 
97b92a8fabSTrond Myklebust static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail,
98b92a8fabSTrond Myklebust 						 struct cache_head *key,
99b92a8fabSTrond Myklebust 						 int hash)
100b92a8fabSTrond Myklebust {
101b92a8fabSTrond Myklebust 	struct cache_head *new, *tmp, *freeme = NULL;
102b92a8fabSTrond Myklebust 	struct hlist_head *head = &detail->hash_table[hash];
10315a5f6bdSNeilBrown 
10415a5f6bdSNeilBrown 	new = detail->alloc();
10515a5f6bdSNeilBrown 	if (!new)
10615a5f6bdSNeilBrown 		return NULL;
1072f34931fSNeil Brown 	/* must fully initialise 'new', else
1082f34931fSNeil Brown 	 * we might get lose if we need to
1092f34931fSNeil Brown 	 * cache_put it soon.
1102f34931fSNeil Brown 	 */
11177862036SNeil Brown 	cache_init(new, detail);
1122f34931fSNeil Brown 	detail->init(new, key);
11315a5f6bdSNeilBrown 
1141863d77fSTrond Myklebust 	spin_lock(&detail->hash_lock);
11515a5f6bdSNeilBrown 
11615a5f6bdSNeilBrown 	/* check if entry appeared while we slept */
11751cae673SAmol Grover 	hlist_for_each_entry_rcu(tmp, head, cache_list,
11851cae673SAmol Grover 				 lockdep_is_held(&detail->hash_lock)) {
119277f27e2STrond Myklebust 		if (!detail->match(tmp, key))
120277f27e2STrond Myklebust 			continue;
121277f27e2STrond Myklebust 		if (test_bit(CACHE_VALID, &tmp->flags) &&
122277f27e2STrond Myklebust 		    cache_is_expired(detail, tmp)) {
123809fe3c5STrond Myklebust 			sunrpc_begin_cache_remove_entry(tmp, detail);
12478a947f5STrond Myklebust 			trace_cache_entry_expired(detail, tmp);
125d202cce8SNeilBrown 			freeme = tmp;
126d202cce8SNeilBrown 			break;
127d202cce8SNeilBrown 		}
12815a5f6bdSNeilBrown 		cache_get(tmp);
1291863d77fSTrond Myklebust 		spin_unlock(&detail->hash_lock);
130baab935fSNeilBrown 		cache_put(new, detail);
13115a5f6bdSNeilBrown 		return tmp;
13215a5f6bdSNeilBrown 	}
133129e5824SKinglong Mee 
134ae74136bSTrond Myklebust 	hlist_add_head_rcu(&new->cache_list, head);
13515a5f6bdSNeilBrown 	detail->entries++;
13615a5f6bdSNeilBrown 	cache_get(new);
1371863d77fSTrond Myklebust 	spin_unlock(&detail->hash_lock);
13815a5f6bdSNeilBrown 
139809fe3c5STrond Myklebust 	if (freeme)
140809fe3c5STrond Myklebust 		sunrpc_end_cache_remove_entry(freeme, detail);
14115a5f6bdSNeilBrown 	return new;
14215a5f6bdSNeilBrown }
14315a5f6bdSNeilBrown 
144ae74136bSTrond Myklebust struct cache_head *sunrpc_cache_lookup_rcu(struct cache_detail *detail,
145ae74136bSTrond Myklebust 					   struct cache_head *key, int hash)
146ae74136bSTrond Myklebust {
147ae74136bSTrond Myklebust 	struct cache_head *ret;
148ae74136bSTrond Myklebust 
149ae74136bSTrond Myklebust 	ret = sunrpc_cache_find_rcu(detail, key, hash);
150ae74136bSTrond Myklebust 	if (ret)
151ae74136bSTrond Myklebust 		return ret;
152ae74136bSTrond Myklebust 	/* Didn't find anything, insert an empty entry */
153ae74136bSTrond Myklebust 	return sunrpc_cache_add_entry(detail, key, hash);
154ae74136bSTrond Myklebust }
155ae74136bSTrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_lookup_rcu);
156ae74136bSTrond Myklebust 
157f866a819SNeilBrown static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
158ebd0cb1aSNeilBrown 
159f559935eSArnd Bergmann static void cache_fresh_locked(struct cache_head *head, time64_t expiry,
16077862036SNeil Brown 			       struct cache_detail *detail)
161ebd0cb1aSNeilBrown {
162f559935eSArnd Bergmann 	time64_t now = seconds_since_boot();
16377862036SNeil Brown 	if (now <= detail->flush_time)
16477862036SNeil Brown 		/* ensure it isn't immediately treated as expired */
16577862036SNeil Brown 		now = detail->flush_time + 1;
166ebd0cb1aSNeilBrown 	head->expiry_time = expiry;
16777862036SNeil Brown 	head->last_refresh = now;
168fdef7aa5SJ. Bruce Fields 	smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
169908329f2SNeilBrown 	set_bit(CACHE_VALID, &head->flags);
170ebd0cb1aSNeilBrown }
171ebd0cb1aSNeilBrown 
172ebd0cb1aSNeilBrown static void cache_fresh_unlocked(struct cache_head *head,
173908329f2SNeilBrown 				 struct cache_detail *detail)
174ebd0cb1aSNeilBrown {
175ebd0cb1aSNeilBrown 	if (test_and_clear_bit(CACHE_PENDING, &head->flags)) {
176ebd0cb1aSNeilBrown 		cache_revisit_request(head);
177f866a819SNeilBrown 		cache_dequeue(detail, head);
178ebd0cb1aSNeilBrown 	}
179ebd0cb1aSNeilBrown }
180ebd0cb1aSNeilBrown 
18178a947f5STrond Myklebust static void cache_make_negative(struct cache_detail *detail,
18278a947f5STrond Myklebust 				struct cache_head *h)
18378a947f5STrond Myklebust {
18478a947f5STrond Myklebust 	set_bit(CACHE_NEGATIVE, &h->flags);
18578a947f5STrond Myklebust 	trace_cache_entry_make_negative(detail, h);
18678a947f5STrond Myklebust }
18778a947f5STrond Myklebust 
18878a947f5STrond Myklebust static void cache_entry_update(struct cache_detail *detail,
18978a947f5STrond Myklebust 			       struct cache_head *h,
19078a947f5STrond Myklebust 			       struct cache_head *new)
19178a947f5STrond Myklebust {
19278a947f5STrond Myklebust 	if (!test_bit(CACHE_NEGATIVE, &new->flags)) {
19378a947f5STrond Myklebust 		detail->update(h, new);
19478a947f5STrond Myklebust 		trace_cache_entry_update(detail, h);
19578a947f5STrond Myklebust 	} else {
19678a947f5STrond Myklebust 		cache_make_negative(detail, h);
19778a947f5STrond Myklebust 	}
19878a947f5STrond Myklebust }
19978a947f5STrond Myklebust 
20015a5f6bdSNeilBrown struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
20115a5f6bdSNeilBrown 				       struct cache_head *new, struct cache_head *old, int hash)
20215a5f6bdSNeilBrown {
20315a5f6bdSNeilBrown 	/* The 'old' entry is to be replaced by 'new'.
20415a5f6bdSNeilBrown 	 * If 'old' is not VALID, we update it directly,
20515a5f6bdSNeilBrown 	 * otherwise we need to replace it
20615a5f6bdSNeilBrown 	 */
20715a5f6bdSNeilBrown 	struct cache_head *tmp;
20815a5f6bdSNeilBrown 
20915a5f6bdSNeilBrown 	if (!test_bit(CACHE_VALID, &old->flags)) {
2101863d77fSTrond Myklebust 		spin_lock(&detail->hash_lock);
21115a5f6bdSNeilBrown 		if (!test_bit(CACHE_VALID, &old->flags)) {
21278a947f5STrond Myklebust 			cache_entry_update(detail, old, new);
21377862036SNeil Brown 			cache_fresh_locked(old, new->expiry_time, detail);
2141863d77fSTrond Myklebust 			spin_unlock(&detail->hash_lock);
215908329f2SNeilBrown 			cache_fresh_unlocked(old, detail);
21615a5f6bdSNeilBrown 			return old;
21715a5f6bdSNeilBrown 		}
2181863d77fSTrond Myklebust 		spin_unlock(&detail->hash_lock);
21915a5f6bdSNeilBrown 	}
22015a5f6bdSNeilBrown 	/* We need to insert a new entry */
22115a5f6bdSNeilBrown 	tmp = detail->alloc();
22215a5f6bdSNeilBrown 	if (!tmp) {
223baab935fSNeilBrown 		cache_put(old, detail);
22415a5f6bdSNeilBrown 		return NULL;
22515a5f6bdSNeilBrown 	}
22677862036SNeil Brown 	cache_init(tmp, detail);
22715a5f6bdSNeilBrown 	detail->init(tmp, old);
22815a5f6bdSNeilBrown 
2291863d77fSTrond Myklebust 	spin_lock(&detail->hash_lock);
23078a947f5STrond Myklebust 	cache_entry_update(detail, tmp, new);
231129e5824SKinglong Mee 	hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]);
232f2d39586SNeilBrown 	detail->entries++;
23315a5f6bdSNeilBrown 	cache_get(tmp);
23477862036SNeil Brown 	cache_fresh_locked(tmp, new->expiry_time, detail);
23577862036SNeil Brown 	cache_fresh_locked(old, 0, detail);
2361863d77fSTrond Myklebust 	spin_unlock(&detail->hash_lock);
237908329f2SNeilBrown 	cache_fresh_unlocked(tmp, detail);
238908329f2SNeilBrown 	cache_fresh_unlocked(old, detail);
239baab935fSNeilBrown 	cache_put(old, detail);
24015a5f6bdSNeilBrown 	return tmp;
24115a5f6bdSNeilBrown }
24224c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_update);
2431da177e4SLinus Torvalds 
244b6040f97Schaoting fan static inline int cache_is_valid(struct cache_head *h)
245989a19b9SNeilBrown {
246d202cce8SNeilBrown 	if (!test_bit(CACHE_VALID, &h->flags))
247989a19b9SNeilBrown 		return -EAGAIN;
248989a19b9SNeilBrown 	else {
249989a19b9SNeilBrown 		/* entry is valid */
250989a19b9SNeilBrown 		if (test_bit(CACHE_NEGATIVE, &h->flags))
251989a19b9SNeilBrown 			return -ENOENT;
252fdef7aa5SJ. Bruce Fields 		else {
253fdef7aa5SJ. Bruce Fields 			/*
254fdef7aa5SJ. Bruce Fields 			 * In combination with write barrier in
255fdef7aa5SJ. Bruce Fields 			 * sunrpc_cache_update, ensures that anyone
256fdef7aa5SJ. Bruce Fields 			 * using the cache entry after this sees the
257fdef7aa5SJ. Bruce Fields 			 * updated contents:
258fdef7aa5SJ. Bruce Fields 			 */
259fdef7aa5SJ. Bruce Fields 			smp_rmb();
260989a19b9SNeilBrown 			return 0;
261989a19b9SNeilBrown 		}
262989a19b9SNeilBrown 	}
263fdef7aa5SJ. Bruce Fields }
264e9dc1221SJ. Bruce Fields 
2656bab93f8SJ. Bruce Fields static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h)
2666bab93f8SJ. Bruce Fields {
2676bab93f8SJ. Bruce Fields 	int rv;
2686bab93f8SJ. Bruce Fields 
2691863d77fSTrond Myklebust 	spin_lock(&detail->hash_lock);
270b6040f97Schaoting fan 	rv = cache_is_valid(h);
2712a1c7f53SNeilBrown 	if (rv == -EAGAIN) {
27278a947f5STrond Myklebust 		cache_make_negative(detail, h);
27377862036SNeil Brown 		cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY,
27477862036SNeil Brown 				   detail);
2752a1c7f53SNeilBrown 		rv = -ENOENT;
2762a1c7f53SNeilBrown 	}
2771863d77fSTrond Myklebust 	spin_unlock(&detail->hash_lock);
2786bab93f8SJ. Bruce Fields 	cache_fresh_unlocked(h, detail);
2792a1c7f53SNeilBrown 	return rv;
2806bab93f8SJ. Bruce Fields }
2816bab93f8SJ. Bruce Fields 
2821da177e4SLinus Torvalds /*
2831da177e4SLinus Torvalds  * This is the generic cache management routine for all
2841da177e4SLinus Torvalds  * the authentication caches.
2851da177e4SLinus Torvalds  * It checks the currency of a cache item and will (later)
2861da177e4SLinus Torvalds  * initiate an upcall to fill it if needed.
2871da177e4SLinus Torvalds  *
2881da177e4SLinus Torvalds  *
2891da177e4SLinus Torvalds  * Returns 0 if the cache_head can be used, or cache_puts it and returns
290989a19b9SNeilBrown  * -EAGAIN if upcall is pending and request has been queued
291989a19b9SNeilBrown  * -ETIMEDOUT if upcall failed or request could not be queue or
292989a19b9SNeilBrown  *           upcall completed but item is still invalid (implying that
293989a19b9SNeilBrown  *           the cache item has been replaced with a newer one).
2941da177e4SLinus Torvalds  * -ENOENT if cache entry was negative
2951da177e4SLinus Torvalds  */
2961da177e4SLinus Torvalds int cache_check(struct cache_detail *detail,
2971da177e4SLinus Torvalds 		    struct cache_head *h, struct cache_req *rqstp)
2981da177e4SLinus Torvalds {
2991da177e4SLinus Torvalds 	int rv;
300f559935eSArnd Bergmann 	time64_t refresh_age, age;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	/* First decide return status as best we can */
303b6040f97Schaoting fan 	rv = cache_is_valid(h);
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	/* now see if we want to start an upcall */
3061da177e4SLinus Torvalds 	refresh_age = (h->expiry_time - h->last_refresh);
307c5b29f88SNeilBrown 	age = seconds_since_boot() - h->last_refresh;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	if (rqstp == NULL) {
3101da177e4SLinus Torvalds 		if (rv == -EAGAIN)
3111da177e4SLinus Torvalds 			rv = -ENOENT;
3120bebc633SNeilBrown 	} else if (rv == -EAGAIN ||
3130bebc633SNeilBrown 		   (h->expiry_time != 0 && age > refresh_age/2)) {
314f559935eSArnd Bergmann 		dprintk("RPC:       Want update, refage=%lld, age=%lld\n",
31546121cf7SChuck Lever 				refresh_age, age);
31665286b88STrond Myklebust 		switch (detail->cache_upcall(detail, h)) {
3171da177e4SLinus Torvalds 		case -EINVAL:
3186bab93f8SJ. Bruce Fields 			rv = try_to_negate_entry(detail, h);
3191da177e4SLinus Torvalds 			break;
3201da177e4SLinus Torvalds 		case -EAGAIN:
3212a1c7f53SNeilBrown 			cache_fresh_unlocked(h, detail);
3221da177e4SLinus Torvalds 			break;
3231da177e4SLinus Torvalds 		}
3241da177e4SLinus Torvalds 	}
3251da177e4SLinus Torvalds 
326989a19b9SNeilBrown 	if (rv == -EAGAIN) {
327d76d1815SJ. Bruce Fields 		if (!cache_defer_req(rqstp, h)) {
328d76d1815SJ. Bruce Fields 			/*
329d76d1815SJ. Bruce Fields 			 * Request was not deferred; handle it as best
330d76d1815SJ. Bruce Fields 			 * we can ourselves:
331d76d1815SJ. Bruce Fields 			 */
332b6040f97Schaoting fan 			rv = cache_is_valid(h);
3331da177e4SLinus Torvalds 			if (rv == -EAGAIN)
334e0bb89efSJ.Bruce Fields 				rv = -ETIMEDOUT;
335989a19b9SNeilBrown 		}
336989a19b9SNeilBrown 	}
3374013edeaSNeilBrown 	if (rv)
338baab935fSNeilBrown 		cache_put(h, detail);
3391da177e4SLinus Torvalds 	return rv;
3401da177e4SLinus Torvalds }
34124c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(cache_check);
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds /*
3441da177e4SLinus Torvalds  * caches need to be periodically cleaned.
3451da177e4SLinus Torvalds  * For this we maintain a list of cache_detail and
3461da177e4SLinus Torvalds  * a current pointer into that list and into the table
3471da177e4SLinus Torvalds  * for that entry.
3481da177e4SLinus Torvalds  *
349013920ebSNeilBrown  * Each time cache_clean is called it finds the next non-empty entry
3501da177e4SLinus Torvalds  * in the current table and walks the list in that entry
3511da177e4SLinus Torvalds  * looking for entries that can be removed.
3521da177e4SLinus Torvalds  *
3531da177e4SLinus Torvalds  * An entry gets removed if:
3541da177e4SLinus Torvalds  * - The expiry is before current time
3551da177e4SLinus Torvalds  * - The last_refresh time is before the flush_time for that cache
3561da177e4SLinus Torvalds  *
3571da177e4SLinus Torvalds  * later we might drop old entries with non-NEVER expiry if that table
3581da177e4SLinus Torvalds  * is getting 'full' for some definition of 'full'
3591da177e4SLinus Torvalds  *
3601da177e4SLinus Torvalds  * The question of "how often to scan a table" is an interesting one
3611da177e4SLinus Torvalds  * and is answered in part by the use of the "nextcheck" field in the
3621da177e4SLinus Torvalds  * cache_detail.
3631da177e4SLinus Torvalds  * When a scan of a table begins, the nextcheck field is set to a time
3641da177e4SLinus Torvalds  * that is well into the future.
3651da177e4SLinus Torvalds  * While scanning, if an expiry time is found that is earlier than the
3661da177e4SLinus Torvalds  * current nextcheck time, nextcheck is set to that expiry time.
3671da177e4SLinus Torvalds  * If the flush_time is ever set to a time earlier than the nextcheck
3681da177e4SLinus Torvalds  * time, the nextcheck time is then set to that flush_time.
3691da177e4SLinus Torvalds  *
3701da177e4SLinus Torvalds  * A table is then only scanned if the current time is at least
3711da177e4SLinus Torvalds  * the nextcheck time.
3721da177e4SLinus Torvalds  *
3731da177e4SLinus Torvalds  */
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds static LIST_HEAD(cache_list);
3761da177e4SLinus Torvalds static DEFINE_SPINLOCK(cache_list_lock);
3771da177e4SLinus Torvalds static struct cache_detail *current_detail;
3781da177e4SLinus Torvalds static int current_index;
3791da177e4SLinus Torvalds 
38065f27f38SDavid Howells static void do_cache_clean(struct work_struct *work);
3818eab945cSArtem Bityutskiy static struct delayed_work cache_cleaner;
3821da177e4SLinus Torvalds 
383820f9442SStanislav Kinsbursky void sunrpc_init_cache_detail(struct cache_detail *cd)
3841da177e4SLinus Torvalds {
3851863d77fSTrond Myklebust 	spin_lock_init(&cd->hash_lock);
3861da177e4SLinus Torvalds 	INIT_LIST_HEAD(&cd->queue);
3871da177e4SLinus Torvalds 	spin_lock(&cache_list_lock);
3881da177e4SLinus Torvalds 	cd->nextcheck = 0;
3891da177e4SLinus Torvalds 	cd->entries = 0;
39064a38e84SDave Wysochanski 	atomic_set(&cd->writers, 0);
3911da177e4SLinus Torvalds 	cd->last_close = 0;
3921da177e4SLinus Torvalds 	cd->last_warn = -1;
3931da177e4SLinus Torvalds 	list_add(&cd->others, &cache_list);
3941da177e4SLinus Torvalds 	spin_unlock(&cache_list_lock);
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	/* start the cleaning process */
39777b00bc0SKe Wang 	queue_delayed_work(system_power_efficient_wq, &cache_cleaner, 0);
3981da177e4SLinus Torvalds }
399820f9442SStanislav Kinsbursky EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail);
4001da177e4SLinus Torvalds 
401820f9442SStanislav Kinsbursky void sunrpc_destroy_cache_detail(struct cache_detail *cd)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	cache_purge(cd);
4041da177e4SLinus Torvalds 	spin_lock(&cache_list_lock);
4051863d77fSTrond Myklebust 	spin_lock(&cd->hash_lock);
4061da177e4SLinus Torvalds 	if (current_detail == cd)
4071da177e4SLinus Torvalds 		current_detail = NULL;
4081da177e4SLinus Torvalds 	list_del_init(&cd->others);
4091863d77fSTrond Myklebust 	spin_unlock(&cd->hash_lock);
4101da177e4SLinus Torvalds 	spin_unlock(&cache_list_lock);
4111da177e4SLinus Torvalds 	if (list_empty(&cache_list)) {
4121da177e4SLinus Torvalds 		/* module must be being unloaded so its safe to kill the worker */
4134011cd97STrond Myklebust 		cancel_delayed_work_sync(&cache_cleaner);
4141da177e4SLinus Torvalds 	}
4151da177e4SLinus Torvalds }
416820f9442SStanislav Kinsbursky EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail);
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds /* clean cache tries to find something to clean
4191da177e4SLinus Torvalds  * and cleans it.
4201da177e4SLinus Torvalds  * It returns 1 if it cleaned something,
4211da177e4SLinus Torvalds  *            0 if it didn't find anything this time
4221da177e4SLinus Torvalds  *           -1 if it fell off the end of the list.
4231da177e4SLinus Torvalds  */
4241da177e4SLinus Torvalds static int cache_clean(void)
4251da177e4SLinus Torvalds {
4261da177e4SLinus Torvalds 	int rv = 0;
4271da177e4SLinus Torvalds 	struct list_head *next;
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	spin_lock(&cache_list_lock);
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	/* find a suitable table if we don't already have one */
4321da177e4SLinus Torvalds 	while (current_detail == NULL ||
4331da177e4SLinus Torvalds 	    current_index >= current_detail->hash_size) {
4341da177e4SLinus Torvalds 		if (current_detail)
4351da177e4SLinus Torvalds 			next = current_detail->others.next;
4361da177e4SLinus Torvalds 		else
4371da177e4SLinus Torvalds 			next = cache_list.next;
4381da177e4SLinus Torvalds 		if (next == &cache_list) {
4391da177e4SLinus Torvalds 			current_detail = NULL;
4401da177e4SLinus Torvalds 			spin_unlock(&cache_list_lock);
4411da177e4SLinus Torvalds 			return -1;
4421da177e4SLinus Torvalds 		}
4431da177e4SLinus Torvalds 		current_detail = list_entry(next, struct cache_detail, others);
444c5b29f88SNeilBrown 		if (current_detail->nextcheck > seconds_since_boot())
4451da177e4SLinus Torvalds 			current_index = current_detail->hash_size;
4461da177e4SLinus Torvalds 		else {
4471da177e4SLinus Torvalds 			current_index = 0;
448c5b29f88SNeilBrown 			current_detail->nextcheck = seconds_since_boot()+30*60;
4491da177e4SLinus Torvalds 		}
4501da177e4SLinus Torvalds 	}
4511da177e4SLinus Torvalds 
4521da177e4SLinus Torvalds 	/* find a non-empty bucket in the table */
4531da177e4SLinus Torvalds 	while (current_detail &&
4541da177e4SLinus Torvalds 	       current_index < current_detail->hash_size &&
455129e5824SKinglong Mee 	       hlist_empty(&current_detail->hash_table[current_index]))
4561da177e4SLinus Torvalds 		current_index++;
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 	/* find a cleanable entry in the bucket and clean it, or set to next bucket */
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds 	if (current_detail && current_index < current_detail->hash_size) {
461129e5824SKinglong Mee 		struct cache_head *ch = NULL;
4621da177e4SLinus Torvalds 		struct cache_detail *d;
463129e5824SKinglong Mee 		struct hlist_head *head;
464129e5824SKinglong Mee 		struct hlist_node *tmp;
4651da177e4SLinus Torvalds 
4661863d77fSTrond Myklebust 		spin_lock(&current_detail->hash_lock);
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 		/* Ok, now to clean this strand */
4691da177e4SLinus Torvalds 
470129e5824SKinglong Mee 		head = &current_detail->hash_table[current_index];
471129e5824SKinglong Mee 		hlist_for_each_entry_safe(ch, tmp, head, cache_list) {
4721da177e4SLinus Torvalds 			if (current_detail->nextcheck > ch->expiry_time)
4731da177e4SLinus Torvalds 				current_detail->nextcheck = ch->expiry_time+1;
4742f50d8b6SNeilBrown 			if (!cache_is_expired(current_detail, ch))
4751da177e4SLinus Torvalds 				continue;
4761da177e4SLinus Torvalds 
477809fe3c5STrond Myklebust 			sunrpc_begin_cache_remove_entry(ch, current_detail);
47878a947f5STrond Myklebust 			trace_cache_entry_expired(current_detail, ch);
4791da177e4SLinus Torvalds 			rv = 1;
4803af4974eSNeilBrown 			break;
4811da177e4SLinus Torvalds 		}
4823af4974eSNeilBrown 
4831863d77fSTrond Myklebust 		spin_unlock(&current_detail->hash_lock);
4841da177e4SLinus Torvalds 		d = current_detail;
4851da177e4SLinus Torvalds 		if (!ch)
4861da177e4SLinus Torvalds 			current_index ++;
4871da177e4SLinus Torvalds 		spin_unlock(&cache_list_lock);
488809fe3c5STrond Myklebust 		if (ch)
489809fe3c5STrond Myklebust 			sunrpc_end_cache_remove_entry(ch, d);
4901da177e4SLinus Torvalds 	} else
4911da177e4SLinus Torvalds 		spin_unlock(&cache_list_lock);
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	return rv;
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds /*
4971da177e4SLinus Torvalds  * We want to regularly clean the cache, so we need to schedule some work ...
4981da177e4SLinus Torvalds  */
49965f27f38SDavid Howells static void do_cache_clean(struct work_struct *work)
5001da177e4SLinus Torvalds {
5011da177e4SLinus Torvalds 	int delay = 5;
5021da177e4SLinus Torvalds 	if (cache_clean() == -1)
5036aad89c8SAnton Blanchard 		delay = round_jiffies_relative(30*HZ);
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 	if (list_empty(&cache_list))
5061da177e4SLinus Torvalds 		delay = 0;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	if (delay)
50977b00bc0SKe Wang 		queue_delayed_work(system_power_efficient_wq,
51077b00bc0SKe Wang 				   &cache_cleaner, delay);
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds /*
5151da177e4SLinus Torvalds  * Clean all caches promptly.  This just calls cache_clean
5161da177e4SLinus Torvalds  * repeatedly until we are sure that every cache has had a chance to
5171da177e4SLinus Torvalds  * be fully cleaned
5181da177e4SLinus Torvalds  */
5191da177e4SLinus Torvalds void cache_flush(void)
5201da177e4SLinus Torvalds {
5211da177e4SLinus Torvalds 	while (cache_clean() != -1)
5221da177e4SLinus Torvalds 		cond_resched();
5231da177e4SLinus Torvalds 	while (cache_clean() != -1)
5241da177e4SLinus Torvalds 		cond_resched();
5251da177e4SLinus Torvalds }
52624c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(cache_flush);
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds void cache_purge(struct cache_detail *detail)
5291da177e4SLinus Torvalds {
530471a930aSKinglong Mee 	struct cache_head *ch = NULL;
531471a930aSKinglong Mee 	struct hlist_head *head = NULL;
532471a930aSKinglong Mee 	int i = 0;
533471a930aSKinglong Mee 
5341863d77fSTrond Myklebust 	spin_lock(&detail->hash_lock);
535471a930aSKinglong Mee 	if (!detail->entries) {
5361863d77fSTrond Myklebust 		spin_unlock(&detail->hash_lock);
537471a930aSKinglong Mee 		return;
538471a930aSKinglong Mee 	}
539471a930aSKinglong Mee 
540471a930aSKinglong Mee 	dprintk("RPC: %d entries in %s cache\n", detail->entries, detail->name);
541471a930aSKinglong Mee 	for (i = 0; i < detail->hash_size; i++) {
542471a930aSKinglong Mee 		head = &detail->hash_table[i];
54343e33924SYihao Wu 		while (!hlist_empty(head)) {
54443e33924SYihao Wu 			ch = hlist_entry(head->first, struct cache_head,
54543e33924SYihao Wu 					 cache_list);
546809fe3c5STrond Myklebust 			sunrpc_begin_cache_remove_entry(ch, detail);
5471863d77fSTrond Myklebust 			spin_unlock(&detail->hash_lock);
548809fe3c5STrond Myklebust 			sunrpc_end_cache_remove_entry(ch, detail);
5491863d77fSTrond Myklebust 			spin_lock(&detail->hash_lock);
550471a930aSKinglong Mee 		}
551471a930aSKinglong Mee 	}
5521863d77fSTrond Myklebust 	spin_unlock(&detail->hash_lock);
5531da177e4SLinus Torvalds }
55424c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(cache_purge);
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds /*
5581da177e4SLinus Torvalds  * Deferral and Revisiting of Requests.
5591da177e4SLinus Torvalds  *
5601da177e4SLinus Torvalds  * If a cache lookup finds a pending entry, we
5611da177e4SLinus Torvalds  * need to defer the request and revisit it later.
5621da177e4SLinus Torvalds  * All deferred requests are stored in a hash table,
5631da177e4SLinus Torvalds  * indexed by "struct cache_head *".
5641da177e4SLinus Torvalds  * As it may be wasteful to store a whole request
5651da177e4SLinus Torvalds  * structure, we allow the request to provide a
5661da177e4SLinus Torvalds  * deferred form, which must contain a
5671da177e4SLinus Torvalds  * 'struct cache_deferred_req'
5681da177e4SLinus Torvalds  * This cache_deferred_req contains a method to allow
5691da177e4SLinus Torvalds  * it to be revisited when cache info is available
5701da177e4SLinus Torvalds  */
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds #define	DFR_HASHSIZE	(PAGE_SIZE/sizeof(struct list_head))
5731da177e4SLinus Torvalds #define	DFR_HASH(item)	((((long)item)>>4 ^ (((long)item)>>13)) % DFR_HASHSIZE)
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds #define	DFR_MAX	300	/* ??? */
5761da177e4SLinus Torvalds 
5771da177e4SLinus Torvalds static DEFINE_SPINLOCK(cache_defer_lock);
5781da177e4SLinus Torvalds static LIST_HEAD(cache_defer_list);
57911174492SNeilBrown static struct hlist_head cache_defer_hash[DFR_HASHSIZE];
5801da177e4SLinus Torvalds static int cache_defer_cnt;
5811da177e4SLinus Torvalds 
5826610f720SJ. Bruce Fields static void __unhash_deferred_req(struct cache_deferred_req *dreq)
5831da177e4SLinus Torvalds {
58411174492SNeilBrown 	hlist_del_init(&dreq->hash);
585e33534d5SNeilBrown 	if (!list_empty(&dreq->recent)) {
586e33534d5SNeilBrown 		list_del_init(&dreq->recent);
5876610f720SJ. Bruce Fields 		cache_defer_cnt--;
5886610f720SJ. Bruce Fields 	}
589e33534d5SNeilBrown }
5906610f720SJ. Bruce Fields 
5916610f720SJ. Bruce Fields static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item)
5926610f720SJ. Bruce Fields {
5931da177e4SLinus Torvalds 	int hash = DFR_HASH(item);
5941da177e4SLinus Torvalds 
595e33534d5SNeilBrown 	INIT_LIST_HEAD(&dreq->recent);
59611174492SNeilBrown 	hlist_add_head(&dreq->hash, &cache_defer_hash[hash]);
59701f3bd1fSJ.Bruce Fields }
5986610f720SJ. Bruce Fields 
599e33534d5SNeilBrown static void setup_deferral(struct cache_deferred_req *dreq,
600e33534d5SNeilBrown 			   struct cache_head *item,
601e33534d5SNeilBrown 			   int count_me)
6021da177e4SLinus Torvalds {
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	dreq->item = item;
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	spin_lock(&cache_defer_lock);
6071da177e4SLinus Torvalds 
6086610f720SJ. Bruce Fields 	__hash_deferred_req(dreq, item);
6091da177e4SLinus Torvalds 
610e33534d5SNeilBrown 	if (count_me) {
611e33534d5SNeilBrown 		cache_defer_cnt++;
6121da177e4SLinus Torvalds 		list_add(&dreq->recent, &cache_defer_list);
6131da177e4SLinus Torvalds 	}
614e33534d5SNeilBrown 
6151da177e4SLinus Torvalds 	spin_unlock(&cache_defer_lock);
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds }
618f16b6e8dSNeilBrown 
6193211af11SJ. Bruce Fields struct thread_deferred_req {
6203211af11SJ. Bruce Fields 	struct cache_deferred_req handle;
6213211af11SJ. Bruce Fields 	struct completion completion;
6223211af11SJ. Bruce Fields };
6233211af11SJ. Bruce Fields 
6243211af11SJ. Bruce Fields static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many)
6253211af11SJ. Bruce Fields {
6263211af11SJ. Bruce Fields 	struct thread_deferred_req *dr =
6273211af11SJ. Bruce Fields 		container_of(dreq, struct thread_deferred_req, handle);
6283211af11SJ. Bruce Fields 	complete(&dr->completion);
6293211af11SJ. Bruce Fields }
6303211af11SJ. Bruce Fields 
631d29068c4SNeilBrown static void cache_wait_req(struct cache_req *req, struct cache_head *item)
6323211af11SJ. Bruce Fields {
6333211af11SJ. Bruce Fields 	struct thread_deferred_req sleeper;
6343211af11SJ. Bruce Fields 	struct cache_deferred_req *dreq = &sleeper.handle;
6353211af11SJ. Bruce Fields 
6363211af11SJ. Bruce Fields 	sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion);
6373211af11SJ. Bruce Fields 	dreq->revisit = cache_restart_thread;
6383211af11SJ. Bruce Fields 
639e33534d5SNeilBrown 	setup_deferral(dreq, item, 0);
6403211af11SJ. Bruce Fields 
641d29068c4SNeilBrown 	if (!test_bit(CACHE_PENDING, &item->flags) ||
642277f68dbSNeilBrown 	    wait_for_completion_interruptible_timeout(
643f16b6e8dSNeilBrown 		    &sleeper.completion, req->thread_wait) <= 0) {
644f16b6e8dSNeilBrown 		/* The completion wasn't completed, so we need
645f16b6e8dSNeilBrown 		 * to clean up
646f16b6e8dSNeilBrown 		 */
647f16b6e8dSNeilBrown 		spin_lock(&cache_defer_lock);
64811174492SNeilBrown 		if (!hlist_unhashed(&sleeper.handle.hash)) {
6496610f720SJ. Bruce Fields 			__unhash_deferred_req(&sleeper.handle);
650f16b6e8dSNeilBrown 			spin_unlock(&cache_defer_lock);
651f16b6e8dSNeilBrown 		} else {
652f16b6e8dSNeilBrown 			/* cache_revisit_request already removed
653f16b6e8dSNeilBrown 			 * this from the hash table, but hasn't
654f16b6e8dSNeilBrown 			 * called ->revisit yet.  It will very soon
655f16b6e8dSNeilBrown 			 * and we need to wait for it.
656f16b6e8dSNeilBrown 			 */
657f16b6e8dSNeilBrown 			spin_unlock(&cache_defer_lock);
658f16b6e8dSNeilBrown 			wait_for_completion(&sleeper.completion);
659f16b6e8dSNeilBrown 		}
660f16b6e8dSNeilBrown 	}
661f16b6e8dSNeilBrown }
6623211af11SJ. Bruce Fields 
663e33534d5SNeilBrown static void cache_limit_defers(void)
664e33534d5SNeilBrown {
665e33534d5SNeilBrown 	/* Make sure we haven't exceed the limit of allowed deferred
666e33534d5SNeilBrown 	 * requests.
667e33534d5SNeilBrown 	 */
668e33534d5SNeilBrown 	struct cache_deferred_req *discard = NULL;
669e33534d5SNeilBrown 
670e33534d5SNeilBrown 	if (cache_defer_cnt <= DFR_MAX)
671e33534d5SNeilBrown 		return;
672e33534d5SNeilBrown 
673e33534d5SNeilBrown 	spin_lock(&cache_defer_lock);
674e33534d5SNeilBrown 
675e33534d5SNeilBrown 	/* Consider removing either the first or the last */
676e33534d5SNeilBrown 	if (cache_defer_cnt > DFR_MAX) {
67763862b5bSAruna-Hewapathirane 		if (prandom_u32() & 1)
678e33534d5SNeilBrown 			discard = list_entry(cache_defer_list.next,
679e33534d5SNeilBrown 					     struct cache_deferred_req, recent);
680e33534d5SNeilBrown 		else
681e33534d5SNeilBrown 			discard = list_entry(cache_defer_list.prev,
682e33534d5SNeilBrown 					     struct cache_deferred_req, recent);
683e33534d5SNeilBrown 		__unhash_deferred_req(discard);
684e33534d5SNeilBrown 	}
685e33534d5SNeilBrown 	spin_unlock(&cache_defer_lock);
686e33534d5SNeilBrown 	if (discard)
687e33534d5SNeilBrown 		discard->revisit(discard, 1);
688e33534d5SNeilBrown }
689e33534d5SNeilBrown 
690d76d1815SJ. Bruce Fields /* Return true if and only if a deferred request is queued. */
691d76d1815SJ. Bruce Fields static bool cache_defer_req(struct cache_req *req, struct cache_head *item)
6923211af11SJ. Bruce Fields {
6933211af11SJ. Bruce Fields 	struct cache_deferred_req *dreq;
6943211af11SJ. Bruce Fields 
6953211af11SJ. Bruce Fields 	if (req->thread_wait) {
696d29068c4SNeilBrown 		cache_wait_req(req, item);
697d29068c4SNeilBrown 		if (!test_bit(CACHE_PENDING, &item->flags))
698d76d1815SJ. Bruce Fields 			return false;
6993211af11SJ. Bruce Fields 	}
7003211af11SJ. Bruce Fields 	dreq = req->defer(req);
7013211af11SJ. Bruce Fields 	if (dreq == NULL)
702d76d1815SJ. Bruce Fields 		return false;
703e33534d5SNeilBrown 	setup_deferral(dreq, item, 1);
704d29068c4SNeilBrown 	if (!test_bit(CACHE_PENDING, &item->flags))
705d29068c4SNeilBrown 		/* Bit could have been cleared before we managed to
706d29068c4SNeilBrown 		 * set up the deferral, so need to revisit just in case
707d29068c4SNeilBrown 		 */
708d29068c4SNeilBrown 		cache_revisit_request(item);
709e33534d5SNeilBrown 
710e33534d5SNeilBrown 	cache_limit_defers();
711d76d1815SJ. Bruce Fields 	return true;
712989a19b9SNeilBrown }
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds static void cache_revisit_request(struct cache_head *item)
7151da177e4SLinus Torvalds {
7161da177e4SLinus Torvalds 	struct cache_deferred_req *dreq;
7171da177e4SLinus Torvalds 	struct list_head pending;
718b67bfe0dSSasha Levin 	struct hlist_node *tmp;
7191da177e4SLinus Torvalds 	int hash = DFR_HASH(item);
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	INIT_LIST_HEAD(&pending);
7221da177e4SLinus Torvalds 	spin_lock(&cache_defer_lock);
7231da177e4SLinus Torvalds 
724b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(dreq, tmp, &cache_defer_hash[hash], hash)
7251da177e4SLinus Torvalds 		if (dreq->item == item) {
7266610f720SJ. Bruce Fields 			__unhash_deferred_req(dreq);
7276610f720SJ. Bruce Fields 			list_add(&dreq->recent, &pending);
7281da177e4SLinus Torvalds 		}
72911174492SNeilBrown 
7301da177e4SLinus Torvalds 	spin_unlock(&cache_defer_lock);
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	while (!list_empty(&pending)) {
7331da177e4SLinus Torvalds 		dreq = list_entry(pending.next, struct cache_deferred_req, recent);
7341da177e4SLinus Torvalds 		list_del_init(&dreq->recent);
7351da177e4SLinus Torvalds 		dreq->revisit(dreq, 0);
7361da177e4SLinus Torvalds 	}
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds void cache_clean_deferred(void *owner)
7401da177e4SLinus Torvalds {
7411da177e4SLinus Torvalds 	struct cache_deferred_req *dreq, *tmp;
7421da177e4SLinus Torvalds 	struct list_head pending;
7431da177e4SLinus Torvalds 
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 	INIT_LIST_HEAD(&pending);
7461da177e4SLinus Torvalds 	spin_lock(&cache_defer_lock);
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) {
7491da177e4SLinus Torvalds 		if (dreq->owner == owner) {
7506610f720SJ. Bruce Fields 			__unhash_deferred_req(dreq);
751e95dffa4SNeilBrown 			list_add(&dreq->recent, &pending);
7521da177e4SLinus Torvalds 		}
7531da177e4SLinus Torvalds 	}
7541da177e4SLinus Torvalds 	spin_unlock(&cache_defer_lock);
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	while (!list_empty(&pending)) {
7571da177e4SLinus Torvalds 		dreq = list_entry(pending.next, struct cache_deferred_req, recent);
7581da177e4SLinus Torvalds 		list_del_init(&dreq->recent);
7591da177e4SLinus Torvalds 		dreq->revisit(dreq, 1);
7601da177e4SLinus Torvalds 	}
7611da177e4SLinus Torvalds }
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds /*
7641da177e4SLinus Torvalds  * communicate with user-space
7651da177e4SLinus Torvalds  *
7666489a8f4SKinglong Mee  * We have a magic /proc file - /proc/net/rpc/<cachename>/channel.
767a490c681SJ. Bruce Fields  * On read, you get a full request, or block.
768a490c681SJ. Bruce Fields  * On write, an update request is processed.
769a490c681SJ. Bruce Fields  * Poll works if anything to read, and always allows write.
7701da177e4SLinus Torvalds  *
7711da177e4SLinus Torvalds  * Implemented by linked list of requests.  Each open file has
772a490c681SJ. Bruce Fields  * a ->private that also exists in this list.  New requests are added
7731da177e4SLinus Torvalds  * to the end and may wakeup and preceding readers.
7741da177e4SLinus Torvalds  * New readers are added to the head.  If, on read, an item is found with
7751da177e4SLinus Torvalds  * CACHE_UPCALLING clear, we free it from the list.
7761da177e4SLinus Torvalds  *
7771da177e4SLinus Torvalds  */
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds static DEFINE_SPINLOCK(queue_lock);
7804a3e2f71SArjan van de Ven static DEFINE_MUTEX(queue_io_mutex);
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds struct cache_queue {
7831da177e4SLinus Torvalds 	struct list_head	list;
7841da177e4SLinus Torvalds 	int			reader;	/* if 0, then request */
7851da177e4SLinus Torvalds };
7861da177e4SLinus Torvalds struct cache_request {
7871da177e4SLinus Torvalds 	struct cache_queue	q;
7881da177e4SLinus Torvalds 	struct cache_head	*item;
7891da177e4SLinus Torvalds 	char			* buf;
7901da177e4SLinus Torvalds 	int			len;
7911da177e4SLinus Torvalds 	int			readers;
7921da177e4SLinus Torvalds };
7931da177e4SLinus Torvalds struct cache_reader {
7941da177e4SLinus Torvalds 	struct cache_queue	q;
7951da177e4SLinus Torvalds 	int			offset;	/* if non-0, we have a refcnt on next request */
7961da177e4SLinus Torvalds };
7971da177e4SLinus Torvalds 
798d94af6deSStanislav Kinsbursky static int cache_request(struct cache_detail *detail,
799d94af6deSStanislav Kinsbursky 			       struct cache_request *crq)
800d94af6deSStanislav Kinsbursky {
801d94af6deSStanislav Kinsbursky 	char *bp = crq->buf;
802d94af6deSStanislav Kinsbursky 	int len = PAGE_SIZE;
803d94af6deSStanislav Kinsbursky 
804d94af6deSStanislav Kinsbursky 	detail->cache_request(detail, crq->item, &bp, &len);
805d94af6deSStanislav Kinsbursky 	if (len < 0)
806d94af6deSStanislav Kinsbursky 		return -EAGAIN;
807d94af6deSStanislav Kinsbursky 	return PAGE_SIZE - len;
808d94af6deSStanislav Kinsbursky }
809d94af6deSStanislav Kinsbursky 
810173912a6STrond Myklebust static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
811173912a6STrond Myklebust 			  loff_t *ppos, struct cache_detail *cd)
8121da177e4SLinus Torvalds {
8131da177e4SLinus Torvalds 	struct cache_reader *rp = filp->private_data;
8141da177e4SLinus Torvalds 	struct cache_request *rq;
815496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
8161da177e4SLinus Torvalds 	int err;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	if (count == 0)
8191da177e4SLinus Torvalds 		return 0;
8201da177e4SLinus Torvalds 
8215955102cSAl Viro 	inode_lock(inode); /* protect against multiple concurrent
8221da177e4SLinus Torvalds 			      * readers on this file */
8231da177e4SLinus Torvalds  again:
8241da177e4SLinus Torvalds 	spin_lock(&queue_lock);
8251da177e4SLinus Torvalds 	/* need to find next request */
8261da177e4SLinus Torvalds 	while (rp->q.list.next != &cd->queue &&
8271da177e4SLinus Torvalds 	       list_entry(rp->q.list.next, struct cache_queue, list)
8281da177e4SLinus Torvalds 	       ->reader) {
8291da177e4SLinus Torvalds 		struct list_head *next = rp->q.list.next;
8301da177e4SLinus Torvalds 		list_move(&rp->q.list, next);
8311da177e4SLinus Torvalds 	}
8321da177e4SLinus Torvalds 	if (rp->q.list.next == &cd->queue) {
8331da177e4SLinus Torvalds 		spin_unlock(&queue_lock);
8345955102cSAl Viro 		inode_unlock(inode);
8350db74d9aSWeston Andros Adamson 		WARN_ON_ONCE(rp->offset);
8361da177e4SLinus Torvalds 		return 0;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 	rq = container_of(rp->q.list.next, struct cache_request, q.list);
8390db74d9aSWeston Andros Adamson 	WARN_ON_ONCE(rq->q.reader);
8401da177e4SLinus Torvalds 	if (rp->offset == 0)
8411da177e4SLinus Torvalds 		rq->readers++;
8421da177e4SLinus Torvalds 	spin_unlock(&queue_lock);
8431da177e4SLinus Torvalds 
844d94af6deSStanislav Kinsbursky 	if (rq->len == 0) {
845d94af6deSStanislav Kinsbursky 		err = cache_request(cd, rq);
846d94af6deSStanislav Kinsbursky 		if (err < 0)
847d94af6deSStanislav Kinsbursky 			goto out;
848d94af6deSStanislav Kinsbursky 		rq->len = err;
849d94af6deSStanislav Kinsbursky 	}
850d94af6deSStanislav Kinsbursky 
8511da177e4SLinus Torvalds 	if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) {
8521da177e4SLinus Torvalds 		err = -EAGAIN;
8531da177e4SLinus Torvalds 		spin_lock(&queue_lock);
8541da177e4SLinus Torvalds 		list_move(&rp->q.list, &rq->q.list);
8551da177e4SLinus Torvalds 		spin_unlock(&queue_lock);
8561da177e4SLinus Torvalds 	} else {
8571da177e4SLinus Torvalds 		if (rp->offset + count > rq->len)
8581da177e4SLinus Torvalds 			count = rq->len - rp->offset;
8591da177e4SLinus Torvalds 		err = -EFAULT;
8601da177e4SLinus Torvalds 		if (copy_to_user(buf, rq->buf + rp->offset, count))
8611da177e4SLinus Torvalds 			goto out;
8621da177e4SLinus Torvalds 		rp->offset += count;
8631da177e4SLinus Torvalds 		if (rp->offset >= rq->len) {
8641da177e4SLinus Torvalds 			rp->offset = 0;
8651da177e4SLinus Torvalds 			spin_lock(&queue_lock);
8661da177e4SLinus Torvalds 			list_move(&rp->q.list, &rq->q.list);
8671da177e4SLinus Torvalds 			spin_unlock(&queue_lock);
8681da177e4SLinus Torvalds 		}
8691da177e4SLinus Torvalds 		err = 0;
8701da177e4SLinus Torvalds 	}
8711da177e4SLinus Torvalds  out:
8721da177e4SLinus Torvalds 	if (rp->offset == 0) {
8731da177e4SLinus Torvalds 		/* need to release rq */
8741da177e4SLinus Torvalds 		spin_lock(&queue_lock);
8751da177e4SLinus Torvalds 		rq->readers--;
8761da177e4SLinus Torvalds 		if (rq->readers == 0 &&
8771da177e4SLinus Torvalds 		    !test_bit(CACHE_PENDING, &rq->item->flags)) {
8781da177e4SLinus Torvalds 			list_del(&rq->q.list);
8791da177e4SLinus Torvalds 			spin_unlock(&queue_lock);
880baab935fSNeilBrown 			cache_put(rq->item, cd);
8811da177e4SLinus Torvalds 			kfree(rq->buf);
8821da177e4SLinus Torvalds 			kfree(rq);
8831da177e4SLinus Torvalds 		} else
8841da177e4SLinus Torvalds 			spin_unlock(&queue_lock);
8851da177e4SLinus Torvalds 	}
8861da177e4SLinus Torvalds 	if (err == -EAGAIN)
8871da177e4SLinus Torvalds 		goto again;
8885955102cSAl Viro 	inode_unlock(inode);
8891da177e4SLinus Torvalds 	return err ? err :  count;
8901da177e4SLinus Torvalds }
8911da177e4SLinus Torvalds 
892da77005fSTrond Myklebust static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
893da77005fSTrond Myklebust 				 size_t count, struct cache_detail *cd)
8941da177e4SLinus Torvalds {
895da77005fSTrond Myklebust 	ssize_t ret;
8961da177e4SLinus Torvalds 
8976d8d1749SDan Carpenter 	if (count == 0)
8986d8d1749SDan Carpenter 		return -EINVAL;
899da77005fSTrond Myklebust 	if (copy_from_user(kaddr, buf, count))
9001da177e4SLinus Torvalds 		return -EFAULT;
901da77005fSTrond Myklebust 	kaddr[count] = '\0';
902da77005fSTrond Myklebust 	ret = cd->cache_parse(cd, kaddr, count);
903da77005fSTrond Myklebust 	if (!ret)
904da77005fSTrond Myklebust 		ret = count;
905da77005fSTrond Myklebust 	return ret;
9061da177e4SLinus Torvalds }
9071da177e4SLinus Torvalds 
908da77005fSTrond Myklebust static ssize_t cache_slow_downcall(const char __user *buf,
909da77005fSTrond Myklebust 				   size_t count, struct cache_detail *cd)
910da77005fSTrond Myklebust {
9111da177e4SLinus Torvalds 	static char write_buf[8192]; /* protected by queue_io_mutex */
912da77005fSTrond Myklebust 	ssize_t ret = -EINVAL;
913da77005fSTrond Myklebust 
914da77005fSTrond Myklebust 	if (count >= sizeof(write_buf))
915da77005fSTrond Myklebust 		goto out;
916da77005fSTrond Myklebust 	mutex_lock(&queue_io_mutex);
917da77005fSTrond Myklebust 	ret = cache_do_downcall(write_buf, buf, count, cd);
9184a3e2f71SArjan van de Ven 	mutex_unlock(&queue_io_mutex);
919da77005fSTrond Myklebust out:
920da77005fSTrond Myklebust 	return ret;
921da77005fSTrond Myklebust }
922da77005fSTrond Myklebust 
923da77005fSTrond Myklebust static ssize_t cache_downcall(struct address_space *mapping,
924da77005fSTrond Myklebust 			      const char __user *buf,
925da77005fSTrond Myklebust 			      size_t count, struct cache_detail *cd)
926da77005fSTrond Myklebust {
927da77005fSTrond Myklebust 	struct page *page;
928da77005fSTrond Myklebust 	char *kaddr;
929da77005fSTrond Myklebust 	ssize_t ret = -ENOMEM;
930da77005fSTrond Myklebust 
93109cbfeafSKirill A. Shutemov 	if (count >= PAGE_SIZE)
932da77005fSTrond Myklebust 		goto out_slow;
933da77005fSTrond Myklebust 
934da77005fSTrond Myklebust 	page = find_or_create_page(mapping, 0, GFP_KERNEL);
935da77005fSTrond Myklebust 	if (!page)
936da77005fSTrond Myklebust 		goto out_slow;
937da77005fSTrond Myklebust 
938da77005fSTrond Myklebust 	kaddr = kmap(page);
939da77005fSTrond Myklebust 	ret = cache_do_downcall(kaddr, buf, count, cd);
940da77005fSTrond Myklebust 	kunmap(page);
941da77005fSTrond Myklebust 	unlock_page(page);
94209cbfeafSKirill A. Shutemov 	put_page(page);
943da77005fSTrond Myklebust 	return ret;
944da77005fSTrond Myklebust out_slow:
945da77005fSTrond Myklebust 	return cache_slow_downcall(buf, count, cd);
946da77005fSTrond Myklebust }
9471da177e4SLinus Torvalds 
948173912a6STrond Myklebust static ssize_t cache_write(struct file *filp, const char __user *buf,
949173912a6STrond Myklebust 			   size_t count, loff_t *ppos,
950173912a6STrond Myklebust 			   struct cache_detail *cd)
9511da177e4SLinus Torvalds {
952da77005fSTrond Myklebust 	struct address_space *mapping = filp->f_mapping;
953496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
954da77005fSTrond Myklebust 	ssize_t ret = -EINVAL;
9551da177e4SLinus Torvalds 
956da77005fSTrond Myklebust 	if (!cd->cache_parse)
957da77005fSTrond Myklebust 		goto out;
9581da177e4SLinus Torvalds 
9595955102cSAl Viro 	inode_lock(inode);
960da77005fSTrond Myklebust 	ret = cache_downcall(mapping, buf, count, cd);
9615955102cSAl Viro 	inode_unlock(inode);
962da77005fSTrond Myklebust out:
963da77005fSTrond Myklebust 	return ret;
9641da177e4SLinus Torvalds }
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(queue_wait);
9671da177e4SLinus Torvalds 
968ade994f4SAl Viro static __poll_t cache_poll(struct file *filp, poll_table *wait,
969173912a6STrond Myklebust 			       struct cache_detail *cd)
9701da177e4SLinus Torvalds {
971ade994f4SAl Viro 	__poll_t mask;
9721da177e4SLinus Torvalds 	struct cache_reader *rp = filp->private_data;
9731da177e4SLinus Torvalds 	struct cache_queue *cq;
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 	poll_wait(filp, &queue_wait, wait);
9761da177e4SLinus Torvalds 
9771da177e4SLinus Torvalds 	/* alway allow write */
978a9a08845SLinus Torvalds 	mask = EPOLLOUT | EPOLLWRNORM;
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	if (!rp)
9811da177e4SLinus Torvalds 		return mask;
9821da177e4SLinus Torvalds 
9831da177e4SLinus Torvalds 	spin_lock(&queue_lock);
9841da177e4SLinus Torvalds 
9851da177e4SLinus Torvalds 	for (cq= &rp->q; &cq->list != &cd->queue;
9861da177e4SLinus Torvalds 	     cq = list_entry(cq->list.next, struct cache_queue, list))
9871da177e4SLinus Torvalds 		if (!cq->reader) {
988a9a08845SLinus Torvalds 			mask |= EPOLLIN | EPOLLRDNORM;
9891da177e4SLinus Torvalds 			break;
9901da177e4SLinus Torvalds 		}
9911da177e4SLinus Torvalds 	spin_unlock(&queue_lock);
9921da177e4SLinus Torvalds 	return mask;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds 
995173912a6STrond Myklebust static int cache_ioctl(struct inode *ino, struct file *filp,
996173912a6STrond Myklebust 		       unsigned int cmd, unsigned long arg,
997173912a6STrond Myklebust 		       struct cache_detail *cd)
9981da177e4SLinus Torvalds {
9991da177e4SLinus Torvalds 	int len = 0;
10001da177e4SLinus Torvalds 	struct cache_reader *rp = filp->private_data;
10011da177e4SLinus Torvalds 	struct cache_queue *cq;
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 	if (cmd != FIONREAD || !rp)
10041da177e4SLinus Torvalds 		return -EINVAL;
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds 	spin_lock(&queue_lock);
10071da177e4SLinus Torvalds 
10081da177e4SLinus Torvalds 	/* only find the length remaining in current request,
10091da177e4SLinus Torvalds 	 * or the length of the next request
10101da177e4SLinus Torvalds 	 */
10111da177e4SLinus Torvalds 	for (cq= &rp->q; &cq->list != &cd->queue;
10121da177e4SLinus Torvalds 	     cq = list_entry(cq->list.next, struct cache_queue, list))
10131da177e4SLinus Torvalds 		if (!cq->reader) {
10141da177e4SLinus Torvalds 			struct cache_request *cr =
10151da177e4SLinus Torvalds 				container_of(cq, struct cache_request, q);
10161da177e4SLinus Torvalds 			len = cr->len - rp->offset;
10171da177e4SLinus Torvalds 			break;
10181da177e4SLinus Torvalds 		}
10191da177e4SLinus Torvalds 	spin_unlock(&queue_lock);
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 	return put_user(len, (int __user *)arg);
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds 
1024173912a6STrond Myklebust static int cache_open(struct inode *inode, struct file *filp,
1025173912a6STrond Myklebust 		      struct cache_detail *cd)
10261da177e4SLinus Torvalds {
10271da177e4SLinus Torvalds 	struct cache_reader *rp = NULL;
10281da177e4SLinus Torvalds 
1029f7e86ab9STrond Myklebust 	if (!cd || !try_module_get(cd->owner))
1030f7e86ab9STrond Myklebust 		return -EACCES;
10311da177e4SLinus Torvalds 	nonseekable_open(inode, filp);
10321da177e4SLinus Torvalds 	if (filp->f_mode & FMODE_READ) {
10331da177e4SLinus Torvalds 		rp = kmalloc(sizeof(*rp), GFP_KERNEL);
1034a7823c79SAlexey Khoroshilov 		if (!rp) {
1035a7823c79SAlexey Khoroshilov 			module_put(cd->owner);
10361da177e4SLinus Torvalds 			return -ENOMEM;
1037a7823c79SAlexey Khoroshilov 		}
10381da177e4SLinus Torvalds 		rp->offset = 0;
10391da177e4SLinus Torvalds 		rp->q.reader = 1;
104064a38e84SDave Wysochanski 
10411da177e4SLinus Torvalds 		spin_lock(&queue_lock);
10421da177e4SLinus Torvalds 		list_add(&rp->q.list, &cd->queue);
10431da177e4SLinus Torvalds 		spin_unlock(&queue_lock);
10441da177e4SLinus Torvalds 	}
104564a38e84SDave Wysochanski 	if (filp->f_mode & FMODE_WRITE)
104664a38e84SDave Wysochanski 		atomic_inc(&cd->writers);
10471da177e4SLinus Torvalds 	filp->private_data = rp;
10481da177e4SLinus Torvalds 	return 0;
10491da177e4SLinus Torvalds }
10501da177e4SLinus Torvalds 
1051173912a6STrond Myklebust static int cache_release(struct inode *inode, struct file *filp,
1052173912a6STrond Myklebust 			 struct cache_detail *cd)
10531da177e4SLinus Torvalds {
10541da177e4SLinus Torvalds 	struct cache_reader *rp = filp->private_data;
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	if (rp) {
10571da177e4SLinus Torvalds 		spin_lock(&queue_lock);
10581da177e4SLinus Torvalds 		if (rp->offset) {
10591da177e4SLinus Torvalds 			struct cache_queue *cq;
10601da177e4SLinus Torvalds 			for (cq= &rp->q; &cq->list != &cd->queue;
10611da177e4SLinus Torvalds 			     cq = list_entry(cq->list.next, struct cache_queue, list))
10621da177e4SLinus Torvalds 				if (!cq->reader) {
10631da177e4SLinus Torvalds 					container_of(cq, struct cache_request, q)
10641da177e4SLinus Torvalds 						->readers--;
10651da177e4SLinus Torvalds 					break;
10661da177e4SLinus Torvalds 				}
10671da177e4SLinus Torvalds 			rp->offset = 0;
10681da177e4SLinus Torvalds 		}
10691da177e4SLinus Torvalds 		list_del(&rp->q.list);
10701da177e4SLinus Torvalds 		spin_unlock(&queue_lock);
10711da177e4SLinus Torvalds 
10721da177e4SLinus Torvalds 		filp->private_data = NULL;
10731da177e4SLinus Torvalds 		kfree(rp);
10741da177e4SLinus Torvalds 
107564a38e84SDave Wysochanski 	}
107664a38e84SDave Wysochanski 	if (filp->f_mode & FMODE_WRITE) {
107764a38e84SDave Wysochanski 		atomic_dec(&cd->writers);
1078c5b29f88SNeilBrown 		cd->last_close = seconds_since_boot();
10791da177e4SLinus Torvalds 	}
1080f7e86ab9STrond Myklebust 	module_put(cd->owner);
10811da177e4SLinus Torvalds 	return 0;
10821da177e4SLinus Torvalds }
10831da177e4SLinus Torvalds 
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 
1086f866a819SNeilBrown static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch)
10871da177e4SLinus Torvalds {
1088f9e1aedcSNeilBrown 	struct cache_queue *cq, *tmp;
1089f9e1aedcSNeilBrown 	struct cache_request *cr;
1090f9e1aedcSNeilBrown 	struct list_head dequeued;
1091f9e1aedcSNeilBrown 
1092f9e1aedcSNeilBrown 	INIT_LIST_HEAD(&dequeued);
10931da177e4SLinus Torvalds 	spin_lock(&queue_lock);
1094f9e1aedcSNeilBrown 	list_for_each_entry_safe(cq, tmp, &detail->queue, list)
10951da177e4SLinus Torvalds 		if (!cq->reader) {
1096f9e1aedcSNeilBrown 			cr = container_of(cq, struct cache_request, q);
10971da177e4SLinus Torvalds 			if (cr->item != ch)
10981da177e4SLinus Torvalds 				continue;
1099f9e1aedcSNeilBrown 			if (test_bit(CACHE_PENDING, &ch->flags))
1100f9e1aedcSNeilBrown 				/* Lost a race and it is pending again */
1101f9e1aedcSNeilBrown 				break;
11021da177e4SLinus Torvalds 			if (cr->readers != 0)
11034013edeaSNeilBrown 				continue;
1104f9e1aedcSNeilBrown 			list_move(&cr->q.list, &dequeued);
1105f9e1aedcSNeilBrown 		}
11061da177e4SLinus Torvalds 	spin_unlock(&queue_lock);
1107f9e1aedcSNeilBrown 	while (!list_empty(&dequeued)) {
1108f9e1aedcSNeilBrown 		cr = list_entry(dequeued.next, struct cache_request, q.list);
1109f9e1aedcSNeilBrown 		list_del(&cr->q.list);
1110baab935fSNeilBrown 		cache_put(cr->item, detail);
11111da177e4SLinus Torvalds 		kfree(cr->buf);
11121da177e4SLinus Torvalds 		kfree(cr);
11131da177e4SLinus Torvalds 	}
11141da177e4SLinus Torvalds }
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds /*
11171da177e4SLinus Torvalds  * Support routines for text-based upcalls.
11181da177e4SLinus Torvalds  * Fields are separated by spaces.
11191da177e4SLinus Torvalds  * Fields are either mangled to quote space tab newline slosh with slosh
11201da177e4SLinus Torvalds  * or a hexified with a leading \x
11211da177e4SLinus Torvalds  * Record is terminated with newline.
11221da177e4SLinus Torvalds  *
11231da177e4SLinus Torvalds  */
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds void qword_add(char **bpp, int *lp, char *str)
11261da177e4SLinus Torvalds {
11271da177e4SLinus Torvalds 	char *bp = *bpp;
11281da177e4SLinus Torvalds 	int len = *lp;
11291b2e122dSAndy Shevchenko 	int ret;
11301da177e4SLinus Torvalds 
11311da177e4SLinus Torvalds 	if (len < 0) return;
11321da177e4SLinus Torvalds 
113341416f23SRasmus Villemoes 	ret = string_escape_str(str, bp, len, ESCAPE_OCTAL, "\\ \n\t");
113441416f23SRasmus Villemoes 	if (ret >= len) {
113541416f23SRasmus Villemoes 		bp += len;
11361b2e122dSAndy Shevchenko 		len = -1;
113741416f23SRasmus Villemoes 	} else {
113841416f23SRasmus Villemoes 		bp += ret;
11391b2e122dSAndy Shevchenko 		len -= ret;
11401da177e4SLinus Torvalds 		*bp++ = ' ';
11411da177e4SLinus Torvalds 		len--;
11421da177e4SLinus Torvalds 	}
11431da177e4SLinus Torvalds 	*bpp = bp;
11441da177e4SLinus Torvalds 	*lp = len;
11451da177e4SLinus Torvalds }
114624c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(qword_add);
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds void qword_addhex(char **bpp, int *lp, char *buf, int blen)
11491da177e4SLinus Torvalds {
11501da177e4SLinus Torvalds 	char *bp = *bpp;
11511da177e4SLinus Torvalds 	int len = *lp;
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 	if (len < 0) return;
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	if (len > 2) {
11561da177e4SLinus Torvalds 		*bp++ = '\\';
11571da177e4SLinus Torvalds 		*bp++ = 'x';
11581da177e4SLinus Torvalds 		len -= 2;
11591da177e4SLinus Torvalds 		while (blen && len >= 2) {
1160056785eaSAndy Shevchenko 			bp = hex_byte_pack(bp, *buf++);
11611da177e4SLinus Torvalds 			len -= 2;
11621da177e4SLinus Torvalds 			blen--;
11631da177e4SLinus Torvalds 		}
11641da177e4SLinus Torvalds 	}
11651da177e4SLinus Torvalds 	if (blen || len<1) len = -1;
11661da177e4SLinus Torvalds 	else {
11671da177e4SLinus Torvalds 		*bp++ = ' ';
11681da177e4SLinus Torvalds 		len--;
11691da177e4SLinus Torvalds 	}
11701da177e4SLinus Torvalds 	*bpp = bp;
11711da177e4SLinus Torvalds 	*lp = len;
11721da177e4SLinus Torvalds }
117324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(qword_addhex);
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds static void warn_no_listener(struct cache_detail *detail)
11761da177e4SLinus Torvalds {
11771da177e4SLinus Torvalds 	if (detail->last_warn != detail->last_close) {
11781da177e4SLinus Torvalds 		detail->last_warn = detail->last_close;
11791da177e4SLinus Torvalds 		if (detail->warn_no_listener)
11802da8ca26STrond Myklebust 			detail->warn_no_listener(detail, detail->last_close != 0);
11811da177e4SLinus Torvalds 	}
11821da177e4SLinus Torvalds }
11831da177e4SLinus Torvalds 
118406497524SJ. Bruce Fields static bool cache_listeners_exist(struct cache_detail *detail)
118506497524SJ. Bruce Fields {
118664a38e84SDave Wysochanski 	if (atomic_read(&detail->writers))
118706497524SJ. Bruce Fields 		return true;
118806497524SJ. Bruce Fields 	if (detail->last_close == 0)
118906497524SJ. Bruce Fields 		/* This cache was never opened */
119006497524SJ. Bruce Fields 		return false;
119106497524SJ. Bruce Fields 	if (detail->last_close < seconds_since_boot() - 30)
119206497524SJ. Bruce Fields 		/*
119306497524SJ. Bruce Fields 		 * We allow for the possibility that someone might
119406497524SJ. Bruce Fields 		 * restart a userspace daemon without restarting the
119506497524SJ. Bruce Fields 		 * server; but after 30 seconds, we give up.
119606497524SJ. Bruce Fields 		 */
119706497524SJ. Bruce Fields 		 return false;
119806497524SJ. Bruce Fields 	return true;
119906497524SJ. Bruce Fields }
120006497524SJ. Bruce Fields 
12011da177e4SLinus Torvalds /*
1202bc74b4f5STrond Myklebust  * register an upcall request to user-space and queue it up for read() by the
1203bc74b4f5STrond Myklebust  * upcall daemon.
1204bc74b4f5STrond Myklebust  *
12051da177e4SLinus Torvalds  * Each request is at most one page long.
12061da177e4SLinus Torvalds  */
120765286b88STrond Myklebust static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
12081da177e4SLinus Torvalds {
12091da177e4SLinus Torvalds 	char *buf;
12101da177e4SLinus Torvalds 	struct cache_request *crq;
1211f9e1aedcSNeilBrown 	int ret = 0;
12121da177e4SLinus Torvalds 
1213013920ebSNeilBrown 	if (test_bit(CACHE_CLEANED, &h->flags))
1214013920ebSNeilBrown 		/* Too late to make an upcall */
1215013920ebSNeilBrown 		return -EAGAIN;
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
12181da177e4SLinus Torvalds 	if (!buf)
12191da177e4SLinus Torvalds 		return -EAGAIN;
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds 	crq = kmalloc(sizeof (*crq), GFP_KERNEL);
12221da177e4SLinus Torvalds 	if (!crq) {
12231da177e4SLinus Torvalds 		kfree(buf);
12241da177e4SLinus Torvalds 		return -EAGAIN;
12251da177e4SLinus Torvalds 	}
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	crq->q.reader = 0;
12281da177e4SLinus Torvalds 	crq->buf = buf;
1229d94af6deSStanislav Kinsbursky 	crq->len = 0;
12301da177e4SLinus Torvalds 	crq->readers = 0;
12311da177e4SLinus Torvalds 	spin_lock(&queue_lock);
1232a6ab1e81SNeilBrown 	if (test_bit(CACHE_PENDING, &h->flags)) {
1233a6ab1e81SNeilBrown 		crq->item = cache_get(h);
12341da177e4SLinus Torvalds 		list_add_tail(&crq->q.list, &detail->queue);
123578a947f5STrond Myklebust 		trace_cache_entry_upcall(detail, h);
1236a6ab1e81SNeilBrown 	} else
1237f9e1aedcSNeilBrown 		/* Lost a race, no longer PENDING, so don't enqueue */
1238f9e1aedcSNeilBrown 		ret = -EAGAIN;
12391da177e4SLinus Torvalds 	spin_unlock(&queue_lock);
12401da177e4SLinus Torvalds 	wake_up(&queue_wait);
1241f9e1aedcSNeilBrown 	if (ret == -EAGAIN) {
1242f9e1aedcSNeilBrown 		kfree(buf);
1243f9e1aedcSNeilBrown 		kfree(crq);
1244f9e1aedcSNeilBrown 	}
1245f9e1aedcSNeilBrown 	return ret;
12461da177e4SLinus Torvalds }
124765286b88STrond Myklebust 
124865286b88STrond Myklebust int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
124965286b88STrond Myklebust {
125065286b88STrond Myklebust 	if (test_and_set_bit(CACHE_PENDING, &h->flags))
125165286b88STrond Myklebust 		return 0;
125265286b88STrond Myklebust 	return cache_pipe_upcall(detail, h);
125365286b88STrond Myklebust }
1254bc74b4f5STrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
12551da177e4SLinus Torvalds 
125665286b88STrond Myklebust int sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
125765286b88STrond Myklebust 				     struct cache_head *h)
125865286b88STrond Myklebust {
125965286b88STrond Myklebust 	if (!cache_listeners_exist(detail)) {
126065286b88STrond Myklebust 		warn_no_listener(detail);
126178a947f5STrond Myklebust 		trace_cache_entry_no_listener(detail, h);
126265286b88STrond Myklebust 		return -EINVAL;
126365286b88STrond Myklebust 	}
126465286b88STrond Myklebust 	return sunrpc_cache_pipe_upcall(detail, h);
126565286b88STrond Myklebust }
126665286b88STrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall_timeout);
126765286b88STrond Myklebust 
12681da177e4SLinus Torvalds /*
12691da177e4SLinus Torvalds  * parse a message from user-space and pass it
12701da177e4SLinus Torvalds  * to an appropriate cache
12711da177e4SLinus Torvalds  * Messages are, like requests, separated into fields by
12721da177e4SLinus Torvalds  * spaces and dequotes as \xHEXSTRING or embedded \nnn octal
12731da177e4SLinus Torvalds  *
12741da177e4SLinus Torvalds  * Message is
12751da177e4SLinus Torvalds  *   reply cachename expiry key ... content....
12761da177e4SLinus Torvalds  *
12771da177e4SLinus Torvalds  * key and content are both parsed by cache
12781da177e4SLinus Torvalds  */
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds int qword_get(char **bpp, char *dest, int bufsize)
12811da177e4SLinus Torvalds {
12821da177e4SLinus Torvalds 	/* return bytes copied, or -1 on error */
12831da177e4SLinus Torvalds 	char *bp = *bpp;
12841da177e4SLinus Torvalds 	int len = 0;
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds 	while (*bp == ' ') bp++;
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	if (bp[0] == '\\' && bp[1] == 'x') {
12891da177e4SLinus Torvalds 		/* HEX STRING */
12901da177e4SLinus Torvalds 		bp += 2;
1291b7052cd7SStefan Hajnoczi 		while (len < bufsize - 1) {
1292e7f483eaSAndy Shevchenko 			int h, l;
1293e7f483eaSAndy Shevchenko 
1294e7f483eaSAndy Shevchenko 			h = hex_to_bin(bp[0]);
1295e7f483eaSAndy Shevchenko 			if (h < 0)
1296e7f483eaSAndy Shevchenko 				break;
1297e7f483eaSAndy Shevchenko 
1298e7f483eaSAndy Shevchenko 			l = hex_to_bin(bp[1]);
1299e7f483eaSAndy Shevchenko 			if (l < 0)
1300e7f483eaSAndy Shevchenko 				break;
1301e7f483eaSAndy Shevchenko 
1302e7f483eaSAndy Shevchenko 			*dest++ = (h << 4) | l;
1303e7f483eaSAndy Shevchenko 			bp += 2;
13041da177e4SLinus Torvalds 			len++;
13051da177e4SLinus Torvalds 		}
13061da177e4SLinus Torvalds 	} else {
13071da177e4SLinus Torvalds 		/* text with \nnn octal quoting */
13081da177e4SLinus Torvalds 		while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
13091da177e4SLinus Torvalds 			if (*bp == '\\' &&
13101da177e4SLinus Torvalds 			    isodigit(bp[1]) && (bp[1] <= '3') &&
13111da177e4SLinus Torvalds 			    isodigit(bp[2]) &&
13121da177e4SLinus Torvalds 			    isodigit(bp[3])) {
13131da177e4SLinus Torvalds 				int byte = (*++bp -'0');
13141da177e4SLinus Torvalds 				bp++;
13151da177e4SLinus Torvalds 				byte = (byte << 3) | (*bp++ - '0');
13161da177e4SLinus Torvalds 				byte = (byte << 3) | (*bp++ - '0');
13171da177e4SLinus Torvalds 				*dest++ = byte;
13181da177e4SLinus Torvalds 				len++;
13191da177e4SLinus Torvalds 			} else {
13201da177e4SLinus Torvalds 				*dest++ = *bp++;
13211da177e4SLinus Torvalds 				len++;
13221da177e4SLinus Torvalds 			}
13231da177e4SLinus Torvalds 		}
13241da177e4SLinus Torvalds 	}
13251da177e4SLinus Torvalds 
13261da177e4SLinus Torvalds 	if (*bp != ' ' && *bp != '\n' && *bp != '\0')
13271da177e4SLinus Torvalds 		return -1;
13281da177e4SLinus Torvalds 	while (*bp == ' ') bp++;
13291da177e4SLinus Torvalds 	*bpp = bp;
13301da177e4SLinus Torvalds 	*dest = '\0';
13311da177e4SLinus Torvalds 	return len;
13321da177e4SLinus Torvalds }
133324c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(qword_get);
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds /*
13376489a8f4SKinglong Mee  * support /proc/net/rpc/$CACHENAME/content
13381da177e4SLinus Torvalds  * as a seqfile.
13391da177e4SLinus Torvalds  * We call ->cache_show passing NULL for the item to
13401da177e4SLinus Torvalds  * get a header, then pass each real item in the cache
13411da177e4SLinus Torvalds  */
13421da177e4SLinus Torvalds 
1343ae74136bSTrond Myklebust static void *__cache_seq_start(struct seq_file *m, loff_t *pos)
13441da177e4SLinus Torvalds {
13451da177e4SLinus Torvalds 	loff_t n = *pos;
134695c96174SEric Dumazet 	unsigned int hash, entry;
13471da177e4SLinus Torvalds 	struct cache_head *ch;
13489936f2aeSKinglong Mee 	struct cache_detail *cd = m->private;
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds 	if (!n--)
13511da177e4SLinus Torvalds 		return SEQ_START_TOKEN;
13521da177e4SLinus Torvalds 	hash = n >> 32;
13531da177e4SLinus Torvalds 	entry = n & ((1LL<<32) - 1);
13541da177e4SLinus Torvalds 
1355ae74136bSTrond Myklebust 	hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list)
13561da177e4SLinus Torvalds 		if (!entry--)
13571da177e4SLinus Torvalds 			return ch;
13581da177e4SLinus Torvalds 	n &= ~((1LL<<32) - 1);
13591da177e4SLinus Torvalds 	do {
13601da177e4SLinus Torvalds 		hash++;
13611da177e4SLinus Torvalds 		n += 1LL<<32;
13621da177e4SLinus Torvalds 	} while(hash < cd->hash_size &&
1363129e5824SKinglong Mee 		hlist_empty(&cd->hash_table[hash]));
13641da177e4SLinus Torvalds 	if (hash >= cd->hash_size)
13651da177e4SLinus Torvalds 		return NULL;
13661da177e4SLinus Torvalds 	*pos = n+1;
1367ae74136bSTrond Myklebust 	return hlist_entry_safe(rcu_dereference_raw(
1368ae74136bSTrond Myklebust 				hlist_first_rcu(&cd->hash_table[hash])),
1369129e5824SKinglong Mee 				struct cache_head, cache_list);
13701da177e4SLinus Torvalds }
1371ae74136bSTrond Myklebust 
1372d48cf356STrond Myklebust static void *cache_seq_next(struct seq_file *m, void *p, loff_t *pos)
13731da177e4SLinus Torvalds {
13741da177e4SLinus Torvalds 	struct cache_head *ch = p;
13751da177e4SLinus Torvalds 	int hash = (*pos >> 32);
13769936f2aeSKinglong Mee 	struct cache_detail *cd = m->private;
13771da177e4SLinus Torvalds 
13781da177e4SLinus Torvalds 	if (p == SEQ_START_TOKEN)
13791da177e4SLinus Torvalds 		hash = 0;
1380129e5824SKinglong Mee 	else if (ch->cache_list.next == NULL) {
13811da177e4SLinus Torvalds 		hash++;
13821da177e4SLinus Torvalds 		*pos += 1LL<<32;
13831da177e4SLinus Torvalds 	} else {
13841da177e4SLinus Torvalds 		++*pos;
1385ae74136bSTrond Myklebust 		return hlist_entry_safe(rcu_dereference_raw(
1386ae74136bSTrond Myklebust 					hlist_next_rcu(&ch->cache_list)),
1387129e5824SKinglong Mee 					struct cache_head, cache_list);
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 	*pos &= ~((1LL<<32) - 1);
13901da177e4SLinus Torvalds 	while (hash < cd->hash_size &&
1391129e5824SKinglong Mee 	       hlist_empty(&cd->hash_table[hash])) {
13921da177e4SLinus Torvalds 		hash++;
13931da177e4SLinus Torvalds 		*pos += 1LL<<32;
13941da177e4SLinus Torvalds 	}
13951da177e4SLinus Torvalds 	if (hash >= cd->hash_size)
13961da177e4SLinus Torvalds 		return NULL;
13971da177e4SLinus Torvalds 	++*pos;
1398ae74136bSTrond Myklebust 	return hlist_entry_safe(rcu_dereference_raw(
1399ae74136bSTrond Myklebust 				hlist_first_rcu(&cd->hash_table[hash])),
1400129e5824SKinglong Mee 				struct cache_head, cache_list);
14011da177e4SLinus Torvalds }
14021da177e4SLinus Torvalds 
1403ae74136bSTrond Myklebust void *cache_seq_start_rcu(struct seq_file *m, loff_t *pos)
1404ae74136bSTrond Myklebust 	__acquires(RCU)
1405ae74136bSTrond Myklebust {
1406ae74136bSTrond Myklebust 	rcu_read_lock();
1407ae74136bSTrond Myklebust 	return __cache_seq_start(m, pos);
1408ae74136bSTrond Myklebust }
1409ae74136bSTrond Myklebust EXPORT_SYMBOL_GPL(cache_seq_start_rcu);
1410ae74136bSTrond Myklebust 
1411ae74136bSTrond Myklebust void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos)
1412ae74136bSTrond Myklebust {
1413ae74136bSTrond Myklebust 	return cache_seq_next(file, p, pos);
1414ae74136bSTrond Myklebust }
1415ae74136bSTrond Myklebust EXPORT_SYMBOL_GPL(cache_seq_next_rcu);
1416ae74136bSTrond Myklebust 
1417ae74136bSTrond Myklebust void cache_seq_stop_rcu(struct seq_file *m, void *p)
1418ae74136bSTrond Myklebust 	__releases(RCU)
1419ae74136bSTrond Myklebust {
1420ae74136bSTrond Myklebust 	rcu_read_unlock();
1421ae74136bSTrond Myklebust }
1422ae74136bSTrond Myklebust EXPORT_SYMBOL_GPL(cache_seq_stop_rcu);
1423ae74136bSTrond Myklebust 
14241da177e4SLinus Torvalds static int c_show(struct seq_file *m, void *p)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	struct cache_head *cp = p;
14279936f2aeSKinglong Mee 	struct cache_detail *cd = m->private;
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 	if (p == SEQ_START_TOKEN)
14301da177e4SLinus Torvalds 		return cd->cache_show(m, cd, NULL);
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 	ifdebug(CACHE)
1433f559935eSArnd Bergmann 		seq_printf(m, "# expiry=%lld refcnt=%d flags=%lx\n",
1434c5b29f88SNeilBrown 			   convert_to_wallclock(cp->expiry_time),
14352c935bc5SPeter Zijlstra 			   kref_read(&cp->ref), cp->flags);
14361da177e4SLinus Torvalds 	cache_get(cp);
14371da177e4SLinus Torvalds 	if (cache_check(cd, cp, NULL))
14381da177e4SLinus Torvalds 		/* cache_check does a cache_put on failure */
1439*9dbc1f45SXu Wang 		seq_puts(m, "# ");
1440200724a7SNeilBrown 	else {
1441200724a7SNeilBrown 		if (cache_is_expired(cd, cp))
1442*9dbc1f45SXu Wang 			seq_puts(m, "# ");
14431da177e4SLinus Torvalds 		cache_put(cp, cd);
1444200724a7SNeilBrown 	}
14451da177e4SLinus Torvalds 
14461da177e4SLinus Torvalds 	return cd->cache_show(m, cd, cp);
14471da177e4SLinus Torvalds }
14481da177e4SLinus Torvalds 
144956b3d975SPhilippe De Muyter static const struct seq_operations cache_content_op = {
1450d48cf356STrond Myklebust 	.start	= cache_seq_start_rcu,
1451d48cf356STrond Myklebust 	.next	= cache_seq_next_rcu,
1452d48cf356STrond Myklebust 	.stop	= cache_seq_stop_rcu,
14531da177e4SLinus Torvalds 	.show	= c_show,
14541da177e4SLinus Torvalds };
14551da177e4SLinus Torvalds 
1456173912a6STrond Myklebust static int content_open(struct inode *inode, struct file *file,
1457173912a6STrond Myklebust 			struct cache_detail *cd)
14581da177e4SLinus Torvalds {
14599936f2aeSKinglong Mee 	struct seq_file *seq;
14609936f2aeSKinglong Mee 	int err;
14611da177e4SLinus Torvalds 
1462f7e86ab9STrond Myklebust 	if (!cd || !try_module_get(cd->owner))
1463f7e86ab9STrond Myklebust 		return -EACCES;
14649936f2aeSKinglong Mee 
14659936f2aeSKinglong Mee 	err = seq_open(file, &cache_content_op);
14669936f2aeSKinglong Mee 	if (err) {
1467a5990ea1SLi Zefan 		module_put(cd->owner);
14689936f2aeSKinglong Mee 		return err;
1469a5990ea1SLi Zefan 	}
14701da177e4SLinus Torvalds 
14719936f2aeSKinglong Mee 	seq = file->private_data;
14729936f2aeSKinglong Mee 	seq->private = cd;
1473ec931035SPavel Emelyanov 	return 0;
14741da177e4SLinus Torvalds }
14751da177e4SLinus Torvalds 
1476f7e86ab9STrond Myklebust static int content_release(struct inode *inode, struct file *file,
1477f7e86ab9STrond Myklebust 		struct cache_detail *cd)
1478f7e86ab9STrond Myklebust {
14799936f2aeSKinglong Mee 	int ret = seq_release(inode, file);
1480f7e86ab9STrond Myklebust 	module_put(cd->owner);
1481f7e86ab9STrond Myklebust 	return ret;
1482f7e86ab9STrond Myklebust }
1483f7e86ab9STrond Myklebust 
1484f7e86ab9STrond Myklebust static int open_flush(struct inode *inode, struct file *file,
1485f7e86ab9STrond Myklebust 			struct cache_detail *cd)
1486f7e86ab9STrond Myklebust {
1487f7e86ab9STrond Myklebust 	if (!cd || !try_module_get(cd->owner))
1488f7e86ab9STrond Myklebust 		return -EACCES;
1489f7e86ab9STrond Myklebust 	return nonseekable_open(inode, file);
1490f7e86ab9STrond Myklebust }
1491f7e86ab9STrond Myklebust 
1492f7e86ab9STrond Myklebust static int release_flush(struct inode *inode, struct file *file,
1493f7e86ab9STrond Myklebust 			struct cache_detail *cd)
1494f7e86ab9STrond Myklebust {
1495f7e86ab9STrond Myklebust 	module_put(cd->owner);
1496f7e86ab9STrond Myklebust 	return 0;
1497f7e86ab9STrond Myklebust }
14981da177e4SLinus Torvalds 
14991da177e4SLinus Torvalds static ssize_t read_flush(struct file *file, char __user *buf,
1500173912a6STrond Myklebust 			  size_t count, loff_t *ppos,
1501173912a6STrond Myklebust 			  struct cache_detail *cd)
15021da177e4SLinus Torvalds {
1503212ba906SSasha Levin 	char tbuf[22];
150401b2969aSChuck Lever 	size_t len;
15051da177e4SLinus Torvalds 
1506f559935eSArnd Bergmann 	len = snprintf(tbuf, sizeof(tbuf), "%llu\n",
15078ccc8691SKinglong Mee 			convert_to_wallclock(cd->flush_time));
15088ccc8691SKinglong Mee 	return simple_read_from_buffer(buf, count, ppos, tbuf, len);
15091da177e4SLinus Torvalds }
15101da177e4SLinus Torvalds 
15111da177e4SLinus Torvalds static ssize_t write_flush(struct file *file, const char __user *buf,
1512173912a6STrond Myklebust 			   size_t count, loff_t *ppos,
1513173912a6STrond Myklebust 			   struct cache_detail *cd)
15141da177e4SLinus Torvalds {
15151da177e4SLinus Torvalds 	char tbuf[20];
15163b68e6eeSNeilBrown 	char *ep;
1517f559935eSArnd Bergmann 	time64_t now;
1518c5b29f88SNeilBrown 
15191da177e4SLinus Torvalds 	if (*ppos || count > sizeof(tbuf)-1)
15201da177e4SLinus Torvalds 		return -EINVAL;
15211da177e4SLinus Torvalds 	if (copy_from_user(tbuf, buf, count))
15221da177e4SLinus Torvalds 		return -EFAULT;
15231da177e4SLinus Torvalds 	tbuf[count] = 0;
1524c5b29f88SNeilBrown 	simple_strtoul(tbuf, &ep, 0);
15251da177e4SLinus Torvalds 	if (*ep && *ep != '\n')
15261da177e4SLinus Torvalds 		return -EINVAL;
15273b68e6eeSNeilBrown 	/* Note that while we check that 'buf' holds a valid number,
15283b68e6eeSNeilBrown 	 * we always ignore the value and just flush everything.
15293b68e6eeSNeilBrown 	 * Making use of the number leads to races.
153077862036SNeil Brown 	 */
15313b68e6eeSNeilBrown 
15323b68e6eeSNeilBrown 	now = seconds_since_boot();
15333b68e6eeSNeilBrown 	/* Always flush everything, so behave like cache_purge()
15343b68e6eeSNeilBrown 	 * Do this by advancing flush_time to the current time,
15353b68e6eeSNeilBrown 	 * or by one second if it has already reached the current time.
15363b68e6eeSNeilBrown 	 * Newly added cache entries will always have ->last_refresh greater
15373b68e6eeSNeilBrown 	 * that ->flush_time, so they don't get flushed prematurely.
15383b68e6eeSNeilBrown 	 */
15393b68e6eeSNeilBrown 
154077862036SNeil Brown 	if (cd->flush_time >= now)
154177862036SNeil Brown 		now = cd->flush_time + 1;
154277862036SNeil Brown 
15433b68e6eeSNeilBrown 	cd->flush_time = now;
15443b68e6eeSNeilBrown 	cd->nextcheck = now;
15451da177e4SLinus Torvalds 	cache_flush();
15461da177e4SLinus Torvalds 
1547f69d6d8eSJeff Layton 	if (cd->flush)
1548f69d6d8eSJeff Layton 		cd->flush();
1549f69d6d8eSJeff Layton 
15501da177e4SLinus Torvalds 	*ppos += count;
15511da177e4SLinus Torvalds 	return count;
15521da177e4SLinus Torvalds }
15531da177e4SLinus Torvalds 
1554173912a6STrond Myklebust static ssize_t cache_read_procfs(struct file *filp, char __user *buf,
1555173912a6STrond Myklebust 				 size_t count, loff_t *ppos)
1556173912a6STrond Myklebust {
1557d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(file_inode(filp));
1558173912a6STrond Myklebust 
1559173912a6STrond Myklebust 	return cache_read(filp, buf, count, ppos, cd);
1560173912a6STrond Myklebust }
1561173912a6STrond Myklebust 
1562173912a6STrond Myklebust static ssize_t cache_write_procfs(struct file *filp, const char __user *buf,
1563173912a6STrond Myklebust 				  size_t count, loff_t *ppos)
1564173912a6STrond Myklebust {
1565d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(file_inode(filp));
1566173912a6STrond Myklebust 
1567173912a6STrond Myklebust 	return cache_write(filp, buf, count, ppos, cd);
1568173912a6STrond Myklebust }
1569173912a6STrond Myklebust 
1570ade994f4SAl Viro static __poll_t cache_poll_procfs(struct file *filp, poll_table *wait)
1571173912a6STrond Myklebust {
1572d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(file_inode(filp));
1573173912a6STrond Myklebust 
1574173912a6STrond Myklebust 	return cache_poll(filp, wait, cd);
1575173912a6STrond Myklebust }
1576173912a6STrond Myklebust 
1577d79b6f4dSFrederic Weisbecker static long cache_ioctl_procfs(struct file *filp,
1578173912a6STrond Myklebust 			       unsigned int cmd, unsigned long arg)
1579173912a6STrond Myklebust {
1580496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
1581d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1582173912a6STrond Myklebust 
1583a6f8dbc6SArnd Bergmann 	return cache_ioctl(inode, filp, cmd, arg, cd);
1584173912a6STrond Myklebust }
1585173912a6STrond Myklebust 
1586173912a6STrond Myklebust static int cache_open_procfs(struct inode *inode, struct file *filp)
1587173912a6STrond Myklebust {
1588d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1589173912a6STrond Myklebust 
1590173912a6STrond Myklebust 	return cache_open(inode, filp, cd);
1591173912a6STrond Myklebust }
1592173912a6STrond Myklebust 
1593173912a6STrond Myklebust static int cache_release_procfs(struct inode *inode, struct file *filp)
1594173912a6STrond Myklebust {
1595d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1596173912a6STrond Myklebust 
1597173912a6STrond Myklebust 	return cache_release(inode, filp, cd);
1598173912a6STrond Myklebust }
1599173912a6STrond Myklebust 
160097a32539SAlexey Dobriyan static const struct proc_ops cache_channel_proc_ops = {
160197a32539SAlexey Dobriyan 	.proc_lseek	= no_llseek,
160297a32539SAlexey Dobriyan 	.proc_read	= cache_read_procfs,
160397a32539SAlexey Dobriyan 	.proc_write	= cache_write_procfs,
160497a32539SAlexey Dobriyan 	.proc_poll	= cache_poll_procfs,
160597a32539SAlexey Dobriyan 	.proc_ioctl	= cache_ioctl_procfs, /* for FIONREAD */
160697a32539SAlexey Dobriyan 	.proc_open	= cache_open_procfs,
160797a32539SAlexey Dobriyan 	.proc_release	= cache_release_procfs,
16081da177e4SLinus Torvalds };
1609173912a6STrond Myklebust 
1610173912a6STrond Myklebust static int content_open_procfs(struct inode *inode, struct file *filp)
1611173912a6STrond Myklebust {
1612d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1613173912a6STrond Myklebust 
1614173912a6STrond Myklebust 	return content_open(inode, filp, cd);
1615173912a6STrond Myklebust }
1616173912a6STrond Myklebust 
1617f7e86ab9STrond Myklebust static int content_release_procfs(struct inode *inode, struct file *filp)
1618f7e86ab9STrond Myklebust {
1619d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1620f7e86ab9STrond Myklebust 
1621f7e86ab9STrond Myklebust 	return content_release(inode, filp, cd);
1622f7e86ab9STrond Myklebust }
1623f7e86ab9STrond Myklebust 
162497a32539SAlexey Dobriyan static const struct proc_ops content_proc_ops = {
162597a32539SAlexey Dobriyan 	.proc_open	= content_open_procfs,
162697a32539SAlexey Dobriyan 	.proc_read	= seq_read,
162797a32539SAlexey Dobriyan 	.proc_lseek	= seq_lseek,
162897a32539SAlexey Dobriyan 	.proc_release	= content_release_procfs,
1629173912a6STrond Myklebust };
1630173912a6STrond Myklebust 
1631f7e86ab9STrond Myklebust static int open_flush_procfs(struct inode *inode, struct file *filp)
1632f7e86ab9STrond Myklebust {
1633d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1634f7e86ab9STrond Myklebust 
1635f7e86ab9STrond Myklebust 	return open_flush(inode, filp, cd);
1636f7e86ab9STrond Myklebust }
1637f7e86ab9STrond Myklebust 
1638f7e86ab9STrond Myklebust static int release_flush_procfs(struct inode *inode, struct file *filp)
1639f7e86ab9STrond Myklebust {
1640d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(inode);
1641f7e86ab9STrond Myklebust 
1642f7e86ab9STrond Myklebust 	return release_flush(inode, filp, cd);
1643f7e86ab9STrond Myklebust }
1644f7e86ab9STrond Myklebust 
1645173912a6STrond Myklebust static ssize_t read_flush_procfs(struct file *filp, char __user *buf,
1646173912a6STrond Myklebust 			    size_t count, loff_t *ppos)
1647173912a6STrond Myklebust {
1648d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(file_inode(filp));
1649173912a6STrond Myklebust 
1650173912a6STrond Myklebust 	return read_flush(filp, buf, count, ppos, cd);
1651173912a6STrond Myklebust }
1652173912a6STrond Myklebust 
1653173912a6STrond Myklebust static ssize_t write_flush_procfs(struct file *filp,
1654173912a6STrond Myklebust 				  const char __user *buf,
1655173912a6STrond Myklebust 				  size_t count, loff_t *ppos)
1656173912a6STrond Myklebust {
1657d9dda78bSAl Viro 	struct cache_detail *cd = PDE_DATA(file_inode(filp));
1658173912a6STrond Myklebust 
1659173912a6STrond Myklebust 	return write_flush(filp, buf, count, ppos, cd);
1660173912a6STrond Myklebust }
1661173912a6STrond Myklebust 
166297a32539SAlexey Dobriyan static const struct proc_ops cache_flush_proc_ops = {
166397a32539SAlexey Dobriyan 	.proc_open	= open_flush_procfs,
166497a32539SAlexey Dobriyan 	.proc_read	= read_flush_procfs,
166597a32539SAlexey Dobriyan 	.proc_write	= write_flush_procfs,
166697a32539SAlexey Dobriyan 	.proc_release	= release_flush_procfs,
166797a32539SAlexey Dobriyan 	.proc_lseek	= no_llseek,
1668173912a6STrond Myklebust };
1669173912a6STrond Myklebust 
1670863d7d9cSKinglong Mee static void remove_cache_proc_entries(struct cache_detail *cd)
1671173912a6STrond Myklebust {
1672863d7d9cSKinglong Mee 	if (cd->procfs) {
1673863d7d9cSKinglong Mee 		proc_remove(cd->procfs);
1674863d7d9cSKinglong Mee 		cd->procfs = NULL;
1675863d7d9cSKinglong Mee 	}
1676173912a6STrond Myklebust }
1677173912a6STrond Myklebust 
1678173912a6STrond Myklebust #ifdef CONFIG_PROC_FS
1679593ce16bSPavel Emelyanov static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
1680173912a6STrond Myklebust {
1681173912a6STrond Myklebust 	struct proc_dir_entry *p;
16824f42d0d5SPavel Emelyanov 	struct sunrpc_net *sn;
1683173912a6STrond Myklebust 
16844f42d0d5SPavel Emelyanov 	sn = net_generic(net, sunrpc_net_id);
1685863d7d9cSKinglong Mee 	cd->procfs = proc_mkdir(cd->name, sn->proc_net_rpc);
1686863d7d9cSKinglong Mee 	if (cd->procfs == NULL)
1687173912a6STrond Myklebust 		goto out_nomem;
1688173912a6STrond Myklebust 
1689d6444062SJoe Perches 	p = proc_create_data("flush", S_IFREG | 0600,
169097a32539SAlexey Dobriyan 			     cd->procfs, &cache_flush_proc_ops, cd);
1691173912a6STrond Myklebust 	if (p == NULL)
1692173912a6STrond Myklebust 		goto out_nomem;
1693173912a6STrond Myklebust 
16942d438338SStanislav Kinsbursky 	if (cd->cache_request || cd->cache_parse) {
1695d6444062SJoe Perches 		p = proc_create_data("channel", S_IFREG | 0600, cd->procfs,
169697a32539SAlexey Dobriyan 				     &cache_channel_proc_ops, cd);
1697173912a6STrond Myklebust 		if (p == NULL)
1698173912a6STrond Myklebust 			goto out_nomem;
1699173912a6STrond Myklebust 	}
1700173912a6STrond Myklebust 	if (cd->cache_show) {
1701d6444062SJoe Perches 		p = proc_create_data("content", S_IFREG | 0400, cd->procfs,
170297a32539SAlexey Dobriyan 				     &content_proc_ops, cd);
1703173912a6STrond Myklebust 		if (p == NULL)
1704173912a6STrond Myklebust 			goto out_nomem;
1705173912a6STrond Myklebust 	}
1706173912a6STrond Myklebust 	return 0;
1707173912a6STrond Myklebust out_nomem:
1708863d7d9cSKinglong Mee 	remove_cache_proc_entries(cd);
1709173912a6STrond Myklebust 	return -ENOMEM;
1710173912a6STrond Myklebust }
1711173912a6STrond Myklebust #else /* CONFIG_PROC_FS */
1712593ce16bSPavel Emelyanov static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
1713173912a6STrond Myklebust {
1714173912a6STrond Myklebust 	return 0;
1715173912a6STrond Myklebust }
1716173912a6STrond Myklebust #endif
1717173912a6STrond Myklebust 
17188eab945cSArtem Bityutskiy void __init cache_initialize(void)
17198eab945cSArtem Bityutskiy {
1720203b42f7STejun Heo 	INIT_DEFERRABLE_WORK(&cache_cleaner, do_cache_clean);
17218eab945cSArtem Bityutskiy }
17228eab945cSArtem Bityutskiy 
1723593ce16bSPavel Emelyanov int cache_register_net(struct cache_detail *cd, struct net *net)
1724173912a6STrond Myklebust {
1725173912a6STrond Myklebust 	int ret;
1726173912a6STrond Myklebust 
1727173912a6STrond Myklebust 	sunrpc_init_cache_detail(cd);
1728593ce16bSPavel Emelyanov 	ret = create_cache_proc_entries(cd, net);
1729173912a6STrond Myklebust 	if (ret)
1730173912a6STrond Myklebust 		sunrpc_destroy_cache_detail(cd);
1731173912a6STrond Myklebust 	return ret;
1732173912a6STrond Myklebust }
1733f5c8593bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(cache_register_net);
1734593ce16bSPavel Emelyanov 
1735593ce16bSPavel Emelyanov void cache_unregister_net(struct cache_detail *cd, struct net *net)
1736593ce16bSPavel Emelyanov {
1737863d7d9cSKinglong Mee 	remove_cache_proc_entries(cd);
1738593ce16bSPavel Emelyanov 	sunrpc_destroy_cache_detail(cd);
1739593ce16bSPavel Emelyanov }
1740f5c8593bSStanislav Kinsbursky EXPORT_SYMBOL_GPL(cache_unregister_net);
1741593ce16bSPavel Emelyanov 
1742d34971a6SBhumika Goyal struct cache_detail *cache_create_net(const struct cache_detail *tmpl, struct net *net)
1743173912a6STrond Myklebust {
17440a402d5aSStanislav Kinsbursky 	struct cache_detail *cd;
1745129e5824SKinglong Mee 	int i;
17460a402d5aSStanislav Kinsbursky 
17470a402d5aSStanislav Kinsbursky 	cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL);
17480a402d5aSStanislav Kinsbursky 	if (cd == NULL)
17490a402d5aSStanislav Kinsbursky 		return ERR_PTR(-ENOMEM);
17500a402d5aSStanislav Kinsbursky 
17516396bb22SKees Cook 	cd->hash_table = kcalloc(cd->hash_size, sizeof(struct hlist_head),
17520a402d5aSStanislav Kinsbursky 				 GFP_KERNEL);
17530a402d5aSStanislav Kinsbursky 	if (cd->hash_table == NULL) {
17540a402d5aSStanislav Kinsbursky 		kfree(cd);
17550a402d5aSStanislav Kinsbursky 		return ERR_PTR(-ENOMEM);
1756173912a6STrond Myklebust 	}
1757129e5824SKinglong Mee 
1758129e5824SKinglong Mee 	for (i = 0; i < cd->hash_size; i++)
1759129e5824SKinglong Mee 		INIT_HLIST_HEAD(&cd->hash_table[i]);
17600a402d5aSStanislav Kinsbursky 	cd->net = net;
17610a402d5aSStanislav Kinsbursky 	return cd;
17620a402d5aSStanislav Kinsbursky }
17630a402d5aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(cache_create_net);
17640a402d5aSStanislav Kinsbursky 
17650a402d5aSStanislav Kinsbursky void cache_destroy_net(struct cache_detail *cd, struct net *net)
17660a402d5aSStanislav Kinsbursky {
17670a402d5aSStanislav Kinsbursky 	kfree(cd->hash_table);
17680a402d5aSStanislav Kinsbursky 	kfree(cd);
17690a402d5aSStanislav Kinsbursky }
17700a402d5aSStanislav Kinsbursky EXPORT_SYMBOL_GPL(cache_destroy_net);
17718854e82dSTrond Myklebust 
17728854e82dSTrond Myklebust static ssize_t cache_read_pipefs(struct file *filp, char __user *buf,
17738854e82dSTrond Myklebust 				 size_t count, loff_t *ppos)
17748854e82dSTrond Myklebust {
1775496ad9aaSAl Viro 	struct cache_detail *cd = RPC_I(file_inode(filp))->private;
17768854e82dSTrond Myklebust 
17778854e82dSTrond Myklebust 	return cache_read(filp, buf, count, ppos, cd);
17788854e82dSTrond Myklebust }
17798854e82dSTrond Myklebust 
17808854e82dSTrond Myklebust static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf,
17818854e82dSTrond Myklebust 				  size_t count, loff_t *ppos)
17828854e82dSTrond Myklebust {
1783496ad9aaSAl Viro 	struct cache_detail *cd = RPC_I(file_inode(filp))->private;
17848854e82dSTrond Myklebust 
17858854e82dSTrond Myklebust 	return cache_write(filp, buf, count, ppos, cd);
17868854e82dSTrond Myklebust }
17878854e82dSTrond Myklebust 
1788ade994f4SAl Viro static __poll_t cache_poll_pipefs(struct file *filp, poll_table *wait)
17898854e82dSTrond Myklebust {
1790496ad9aaSAl Viro 	struct cache_detail *cd = RPC_I(file_inode(filp))->private;
17918854e82dSTrond Myklebust 
17928854e82dSTrond Myklebust 	return cache_poll(filp, wait, cd);
17938854e82dSTrond Myklebust }
17948854e82dSTrond Myklebust 
17959918ff26SFrederic Weisbecker static long cache_ioctl_pipefs(struct file *filp,
17968854e82dSTrond Myklebust 			      unsigned int cmd, unsigned long arg)
17978854e82dSTrond Myklebust {
1798496ad9aaSAl Viro 	struct inode *inode = file_inode(filp);
17998854e82dSTrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
18008854e82dSTrond Myklebust 
1801a6f8dbc6SArnd Bergmann 	return cache_ioctl(inode, filp, cmd, arg, cd);
18028854e82dSTrond Myklebust }
18038854e82dSTrond Myklebust 
18048854e82dSTrond Myklebust static int cache_open_pipefs(struct inode *inode, struct file *filp)
18058854e82dSTrond Myklebust {
18068854e82dSTrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
18078854e82dSTrond Myklebust 
18088854e82dSTrond Myklebust 	return cache_open(inode, filp, cd);
18098854e82dSTrond Myklebust }
18108854e82dSTrond Myklebust 
18118854e82dSTrond Myklebust static int cache_release_pipefs(struct inode *inode, struct file *filp)
18128854e82dSTrond Myklebust {
18138854e82dSTrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
18148854e82dSTrond Myklebust 
18158854e82dSTrond Myklebust 	return cache_release(inode, filp, cd);
18168854e82dSTrond Myklebust }
18178854e82dSTrond Myklebust 
18188854e82dSTrond Myklebust const struct file_operations cache_file_operations_pipefs = {
18198854e82dSTrond Myklebust 	.owner		= THIS_MODULE,
18208854e82dSTrond Myklebust 	.llseek		= no_llseek,
18218854e82dSTrond Myklebust 	.read		= cache_read_pipefs,
18228854e82dSTrond Myklebust 	.write		= cache_write_pipefs,
18238854e82dSTrond Myklebust 	.poll		= cache_poll_pipefs,
18249918ff26SFrederic Weisbecker 	.unlocked_ioctl	= cache_ioctl_pipefs, /* for FIONREAD */
18258854e82dSTrond Myklebust 	.open		= cache_open_pipefs,
18268854e82dSTrond Myklebust 	.release	= cache_release_pipefs,
18278854e82dSTrond Myklebust };
18288854e82dSTrond Myklebust 
18298854e82dSTrond Myklebust static int content_open_pipefs(struct inode *inode, struct file *filp)
18308854e82dSTrond Myklebust {
18318854e82dSTrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
18328854e82dSTrond Myklebust 
18338854e82dSTrond Myklebust 	return content_open(inode, filp, cd);
18348854e82dSTrond Myklebust }
18358854e82dSTrond Myklebust 
1836f7e86ab9STrond Myklebust static int content_release_pipefs(struct inode *inode, struct file *filp)
1837f7e86ab9STrond Myklebust {
1838f7e86ab9STrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
1839f7e86ab9STrond Myklebust 
1840f7e86ab9STrond Myklebust 	return content_release(inode, filp, cd);
1841f7e86ab9STrond Myklebust }
1842f7e86ab9STrond Myklebust 
18438854e82dSTrond Myklebust const struct file_operations content_file_operations_pipefs = {
18448854e82dSTrond Myklebust 	.open		= content_open_pipefs,
18458854e82dSTrond Myklebust 	.read		= seq_read,
18468854e82dSTrond Myklebust 	.llseek		= seq_lseek,
1847f7e86ab9STrond Myklebust 	.release	= content_release_pipefs,
18488854e82dSTrond Myklebust };
18498854e82dSTrond Myklebust 
1850f7e86ab9STrond Myklebust static int open_flush_pipefs(struct inode *inode, struct file *filp)
1851f7e86ab9STrond Myklebust {
1852f7e86ab9STrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
1853f7e86ab9STrond Myklebust 
1854f7e86ab9STrond Myklebust 	return open_flush(inode, filp, cd);
1855f7e86ab9STrond Myklebust }
1856f7e86ab9STrond Myklebust 
1857f7e86ab9STrond Myklebust static int release_flush_pipefs(struct inode *inode, struct file *filp)
1858f7e86ab9STrond Myklebust {
1859f7e86ab9STrond Myklebust 	struct cache_detail *cd = RPC_I(inode)->private;
1860f7e86ab9STrond Myklebust 
1861f7e86ab9STrond Myklebust 	return release_flush(inode, filp, cd);
1862f7e86ab9STrond Myklebust }
1863f7e86ab9STrond Myklebust 
18648854e82dSTrond Myklebust static ssize_t read_flush_pipefs(struct file *filp, char __user *buf,
18658854e82dSTrond Myklebust 			    size_t count, loff_t *ppos)
18668854e82dSTrond Myklebust {
1867496ad9aaSAl Viro 	struct cache_detail *cd = RPC_I(file_inode(filp))->private;
18688854e82dSTrond Myklebust 
18698854e82dSTrond Myklebust 	return read_flush(filp, buf, count, ppos, cd);
18708854e82dSTrond Myklebust }
18718854e82dSTrond Myklebust 
18728854e82dSTrond Myklebust static ssize_t write_flush_pipefs(struct file *filp,
18738854e82dSTrond Myklebust 				  const char __user *buf,
18748854e82dSTrond Myklebust 				  size_t count, loff_t *ppos)
18758854e82dSTrond Myklebust {
1876496ad9aaSAl Viro 	struct cache_detail *cd = RPC_I(file_inode(filp))->private;
18778854e82dSTrond Myklebust 
18788854e82dSTrond Myklebust 	return write_flush(filp, buf, count, ppos, cd);
18798854e82dSTrond Myklebust }
18808854e82dSTrond Myklebust 
18818854e82dSTrond Myklebust const struct file_operations cache_flush_operations_pipefs = {
1882f7e86ab9STrond Myklebust 	.open		= open_flush_pipefs,
18838854e82dSTrond Myklebust 	.read		= read_flush_pipefs,
18848854e82dSTrond Myklebust 	.write		= write_flush_pipefs,
1885f7e86ab9STrond Myklebust 	.release	= release_flush_pipefs,
18866038f373SArnd Bergmann 	.llseek		= no_llseek,
18878854e82dSTrond Myklebust };
18888854e82dSTrond Myklebust 
18898854e82dSTrond Myklebust int sunrpc_cache_register_pipefs(struct dentry *parent,
189064f1426fSAl Viro 				 const char *name, umode_t umode,
18918854e82dSTrond Myklebust 				 struct cache_detail *cd)
18928854e82dSTrond Myklebust {
1893a95e691fSAl Viro 	struct dentry *dir = rpc_create_cache_dir(parent, name, umode, cd);
1894a95e691fSAl Viro 	if (IS_ERR(dir))
1895a95e691fSAl Viro 		return PTR_ERR(dir);
1896863d7d9cSKinglong Mee 	cd->pipefs = dir;
1897a95e691fSAl Viro 	return 0;
18988854e82dSTrond Myklebust }
18998854e82dSTrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs);
19008854e82dSTrond Myklebust 
19018854e82dSTrond Myklebust void sunrpc_cache_unregister_pipefs(struct cache_detail *cd)
19028854e82dSTrond Myklebust {
1903863d7d9cSKinglong Mee 	if (cd->pipefs) {
1904863d7d9cSKinglong Mee 		rpc_remove_cache_dir(cd->pipefs);
1905863d7d9cSKinglong Mee 		cd->pipefs = NULL;
1906863d7d9cSKinglong Mee 	}
19078854e82dSTrond Myklebust }
19088854e82dSTrond Myklebust EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs);
19098854e82dSTrond Myklebust 
19102b477c00SNeil Brown void sunrpc_cache_unhash(struct cache_detail *cd, struct cache_head *h)
19112b477c00SNeil Brown {
19121863d77fSTrond Myklebust 	spin_lock(&cd->hash_lock);
19132b477c00SNeil Brown 	if (!hlist_unhashed(&h->cache_list)){
1914809fe3c5STrond Myklebust 		sunrpc_begin_cache_remove_entry(h, cd);
19151863d77fSTrond Myklebust 		spin_unlock(&cd->hash_lock);
1916809fe3c5STrond Myklebust 		sunrpc_end_cache_remove_entry(h, cd);
19172b477c00SNeil Brown 	} else
19181863d77fSTrond Myklebust 		spin_unlock(&cd->hash_lock);
19192b477c00SNeil Brown }
19202b477c00SNeil Brown EXPORT_SYMBOL_GPL(sunrpc_cache_unhash);
1921