xref: /openbmc/linux/fs/nfsd/filecache.c (revision 92e4a6733f922f0fef1d0995f7b2d0eaff86c7ea)
13f054211SChuck Lever // SPDX-License-Identifier: GPL-2.0
265294c1fSJeff Layton /*
33f054211SChuck Lever  * The NFSD open file cache.
465294c1fSJeff Layton  *
565294c1fSJeff Layton  * (c) 2015 - Jeff Layton <jeff.layton@primarydata.com>
6b3276c1fSChuck Lever  *
7b3276c1fSChuck Lever  * An nfsd_file object is a per-file collection of open state that binds
8b3276c1fSChuck Lever  * together:
9b3276c1fSChuck Lever  *   - a struct file *
10b3276c1fSChuck Lever  *   - a user credential
11b3276c1fSChuck Lever  *   - a network namespace
12b3276c1fSChuck Lever  *   - a read-ahead context
13b3276c1fSChuck Lever  *   - monitoring for writeback errors
14b3276c1fSChuck Lever  *
15b3276c1fSChuck Lever  * nfsd_file objects are reference-counted. Consumers acquire a new
16b3276c1fSChuck Lever  * object via the nfsd_file_acquire API. They manage their interest in
17b3276c1fSChuck Lever  * the acquired object, and hence the object's reference count, via
18b3276c1fSChuck Lever  * nfsd_file_get and nfsd_file_put. There are two varieties of nfsd_file
19b3276c1fSChuck Lever  * object:
20b3276c1fSChuck Lever  *
21b3276c1fSChuck Lever  *  * non-garbage-collected: When a consumer wants to precisely control
22b3276c1fSChuck Lever  *    the lifetime of a file's open state, it acquires a non-garbage-
23b3276c1fSChuck Lever  *    collected nfsd_file. The final nfsd_file_put releases the open
24b3276c1fSChuck Lever  *    state immediately.
25b3276c1fSChuck Lever  *
26b3276c1fSChuck Lever  *  * garbage-collected: When a consumer does not control the lifetime
27b3276c1fSChuck Lever  *    of open state, it acquires a garbage-collected nfsd_file. The
28b3276c1fSChuck Lever  *    final nfsd_file_put allows the open state to linger for a period
29b3276c1fSChuck Lever  *    during which it may be re-used.
3065294c1fSJeff Layton  */
3165294c1fSJeff Layton 
3265294c1fSJeff Layton #include <linux/hash.h>
3365294c1fSJeff Layton #include <linux/slab.h>
3465294c1fSJeff Layton #include <linux/file.h>
35cbcc268bSMatthew Wilcox (Oracle) #include <linux/pagemap.h>
3665294c1fSJeff Layton #include <linux/sched.h>
3765294c1fSJeff Layton #include <linux/list_lru.h>
3865294c1fSJeff Layton #include <linux/fsnotify_backend.h>
3965294c1fSJeff Layton #include <linux/fsnotify.h>
4065294c1fSJeff Layton #include <linux/seq_file.h>
41fc22945eSChuck Lever #include <linux/rhashtable.h>
4265294c1fSJeff Layton 
4365294c1fSJeff Layton #include "vfs.h"
4465294c1fSJeff Layton #include "nfsd.h"
4565294c1fSJeff Layton #include "nfsfh.h"
465e113224STrond Myklebust #include "netns.h"
4765294c1fSJeff Layton #include "filecache.h"
4865294c1fSJeff Layton #include "trace.h"
4965294c1fSJeff Layton 
5065294c1fSJeff Layton #define NFSD_LAUNDRETTE_DELAY		     (2 * HZ)
5165294c1fSJeff Layton 
52c7b824c3SChuck Lever #define NFSD_FILE_CACHE_UP		     (0)
5365294c1fSJeff Layton 
5465294c1fSJeff Layton /* We only care about NFSD_MAY_READ/WRITE for this cache */
5565294c1fSJeff Layton #define NFSD_FILE_MAY_MASK	(NFSD_MAY_READ|NFSD_MAY_WRITE)
5665294c1fSJeff Layton 
5765294c1fSJeff Layton static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
5829d4bdbbSChuck Lever static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
59d6329327SChuck Lever static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
60904940e9SChuck Lever static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
6194660cc1SChuck Lever static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
6265294c1fSJeff Layton 
639542e6a6STrond Myklebust struct nfsd_fcache_disposal {
649542e6a6STrond Myklebust 	struct work_struct work;
659542e6a6STrond Myklebust 	spinlock_t lock;
669542e6a6STrond Myklebust 	struct list_head freeme;
679542e6a6STrond Myklebust };
689542e6a6STrond Myklebust 
6950d0def9SChen Zhou static struct workqueue_struct *nfsd_filecache_wq __read_mostly;
709542e6a6STrond Myklebust 
7165294c1fSJeff Layton static struct kmem_cache		*nfsd_file_slab;
7265294c1fSJeff Layton static struct kmem_cache		*nfsd_file_mark_slab;
7365294c1fSJeff Layton static struct list_lru			nfsd_file_lru;
74c7b824c3SChuck Lever static unsigned long			nfsd_file_flags;
7565294c1fSJeff Layton static struct fsnotify_group		*nfsd_file_fsnotify_group;
7665294c1fSJeff Layton static struct delayed_work		nfsd_filecache_laundrette;
77c4c649abSChuck Lever static struct rhltable			nfsd_file_rhltable
78fc22945eSChuck Lever 						____cacheline_aligned_in_smp;
7965294c1fSJeff Layton 
80fc22945eSChuck Lever static bool
81fc22945eSChuck Lever nfsd_match_cred(const struct cred *c1, const struct cred *c2)
82fc22945eSChuck Lever {
83fc22945eSChuck Lever 	int i;
84fc22945eSChuck Lever 
85fc22945eSChuck Lever 	if (!uid_eq(c1->fsuid, c2->fsuid))
86fc22945eSChuck Lever 		return false;
87fc22945eSChuck Lever 	if (!gid_eq(c1->fsgid, c2->fsgid))
88fc22945eSChuck Lever 		return false;
89fc22945eSChuck Lever 	if (c1->group_info == NULL || c2->group_info == NULL)
90fc22945eSChuck Lever 		return c1->group_info == c2->group_info;
91fc22945eSChuck Lever 	if (c1->group_info->ngroups != c2->group_info->ngroups)
92fc22945eSChuck Lever 		return false;
93fc22945eSChuck Lever 	for (i = 0; i < c1->group_info->ngroups; i++) {
94fc22945eSChuck Lever 		if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i]))
95fc22945eSChuck Lever 			return false;
96fc22945eSChuck Lever 	}
97fc22945eSChuck Lever 	return true;
98fc22945eSChuck Lever }
99fc22945eSChuck Lever 
100fc22945eSChuck Lever static const struct rhashtable_params nfsd_file_rhash_params = {
101fc22945eSChuck Lever 	.key_len		= sizeof_field(struct nfsd_file, nf_inode),
102fc22945eSChuck Lever 	.key_offset		= offsetof(struct nfsd_file, nf_inode),
103c4c649abSChuck Lever 	.head_offset		= offsetof(struct nfsd_file, nf_rlist),
104c4c649abSChuck Lever 
105c4c649abSChuck Lever 	/*
106c4c649abSChuck Lever 	 * Start with a single page hash table to reduce resizing churn
107c4c649abSChuck Lever 	 * on light workloads.
108c4c649abSChuck Lever 	 */
109c4c649abSChuck Lever 	.min_size		= 256,
110fc22945eSChuck Lever 	.automatic_shrinking	= true,
111fc22945eSChuck Lever };
11265294c1fSJeff Layton 
11365294c1fSJeff Layton static void
1149542e6a6STrond Myklebust nfsd_file_schedule_laundrette(void)
11565294c1fSJeff Layton {
11622ae4c11SJeff Layton 	if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags))
1179542e6a6STrond Myklebust 		queue_delayed_work(system_wq, &nfsd_filecache_laundrette,
1189542e6a6STrond Myklebust 				   NFSD_LAUNDRETTE_DELAY);
11965294c1fSJeff Layton }
12065294c1fSJeff Layton 
12165294c1fSJeff Layton static void
12265294c1fSJeff Layton nfsd_file_slab_free(struct rcu_head *rcu)
12365294c1fSJeff Layton {
12465294c1fSJeff Layton 	struct nfsd_file *nf = container_of(rcu, struct nfsd_file, nf_rcu);
12565294c1fSJeff Layton 
12665294c1fSJeff Layton 	put_cred(nf->nf_cred);
12765294c1fSJeff Layton 	kmem_cache_free(nfsd_file_slab, nf);
12865294c1fSJeff Layton }
12965294c1fSJeff Layton 
13065294c1fSJeff Layton static void
13165294c1fSJeff Layton nfsd_file_mark_free(struct fsnotify_mark *mark)
13265294c1fSJeff Layton {
13365294c1fSJeff Layton 	struct nfsd_file_mark *nfm = container_of(mark, struct nfsd_file_mark,
13465294c1fSJeff Layton 						  nfm_mark);
13565294c1fSJeff Layton 
13665294c1fSJeff Layton 	kmem_cache_free(nfsd_file_mark_slab, nfm);
13765294c1fSJeff Layton }
13865294c1fSJeff Layton 
13965294c1fSJeff Layton static struct nfsd_file_mark *
14065294c1fSJeff Layton nfsd_file_mark_get(struct nfsd_file_mark *nfm)
14165294c1fSJeff Layton {
142689827cdSTrond Myklebust 	if (!refcount_inc_not_zero(&nfm->nfm_ref))
14365294c1fSJeff Layton 		return NULL;
14465294c1fSJeff Layton 	return nfm;
14565294c1fSJeff Layton }
14665294c1fSJeff Layton 
14765294c1fSJeff Layton static void
14865294c1fSJeff Layton nfsd_file_mark_put(struct nfsd_file_mark *nfm)
14965294c1fSJeff Layton {
150689827cdSTrond Myklebust 	if (refcount_dec_and_test(&nfm->nfm_ref)) {
15165294c1fSJeff Layton 		fsnotify_destroy_mark(&nfm->nfm_mark, nfsd_file_fsnotify_group);
15265294c1fSJeff Layton 		fsnotify_put_mark(&nfm->nfm_mark);
15365294c1fSJeff Layton 	}
15465294c1fSJeff Layton }
15565294c1fSJeff Layton 
15665294c1fSJeff Layton static struct nfsd_file_mark *
157427f5f83SChuck Lever nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode)
15865294c1fSJeff Layton {
15965294c1fSJeff Layton 	int			err;
16065294c1fSJeff Layton 	struct fsnotify_mark	*mark;
16165294c1fSJeff Layton 	struct nfsd_file_mark	*nfm = NULL, *new;
16265294c1fSJeff Layton 
16365294c1fSJeff Layton 	do {
164b8962a9dSAmir Goldstein 		fsnotify_group_lock(nfsd_file_fsnotify_group);
16565294c1fSJeff Layton 		mark = fsnotify_find_mark(&inode->i_fsnotify_marks,
16665294c1fSJeff Layton 					  nfsd_file_fsnotify_group);
16765294c1fSJeff Layton 		if (mark) {
16865294c1fSJeff Layton 			nfm = nfsd_file_mark_get(container_of(mark,
16965294c1fSJeff Layton 						 struct nfsd_file_mark,
17065294c1fSJeff Layton 						 nfm_mark));
171b8962a9dSAmir Goldstein 			fsnotify_group_unlock(nfsd_file_fsnotify_group);
17290d2f1daSTrond Myklebust 			if (nfm) {
17365294c1fSJeff Layton 				fsnotify_put_mark(mark);
17465294c1fSJeff Layton 				break;
17590d2f1daSTrond Myklebust 			}
17690d2f1daSTrond Myklebust 			/* Avoid soft lockup race with nfsd_file_mark_put() */
17790d2f1daSTrond Myklebust 			fsnotify_destroy_mark(mark, nfsd_file_fsnotify_group);
17890d2f1daSTrond Myklebust 			fsnotify_put_mark(mark);
179b8962a9dSAmir Goldstein 		} else {
180b8962a9dSAmir Goldstein 			fsnotify_group_unlock(nfsd_file_fsnotify_group);
181b8962a9dSAmir Goldstein 		}
18265294c1fSJeff Layton 
18365294c1fSJeff Layton 		/* allocate a new nfm */
18465294c1fSJeff Layton 		new = kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL);
18565294c1fSJeff Layton 		if (!new)
18665294c1fSJeff Layton 			return NULL;
18765294c1fSJeff Layton 		fsnotify_init_mark(&new->nfm_mark, nfsd_file_fsnotify_group);
18865294c1fSJeff Layton 		new->nfm_mark.mask = FS_ATTRIB|FS_DELETE_SELF;
189689827cdSTrond Myklebust 		refcount_set(&new->nfm_ref, 1);
19065294c1fSJeff Layton 
19165294c1fSJeff Layton 		err = fsnotify_add_inode_mark(&new->nfm_mark, inode, 0);
19265294c1fSJeff Layton 
19365294c1fSJeff Layton 		/*
19465294c1fSJeff Layton 		 * If the add was successful, then return the object.
19565294c1fSJeff Layton 		 * Otherwise, we need to put the reference we hold on the
19665294c1fSJeff Layton 		 * nfm_mark. The fsnotify code will take a reference and put
19765294c1fSJeff Layton 		 * it on failure, so we can't just free it directly. It's also
19865294c1fSJeff Layton 		 * not safe to call fsnotify_destroy_mark on it as the
19965294c1fSJeff Layton 		 * mark->group will be NULL. Thus, we can't let the nfm_ref
20065294c1fSJeff Layton 		 * counter drive the destruction at this point.
20165294c1fSJeff Layton 		 */
20265294c1fSJeff Layton 		if (likely(!err))
20365294c1fSJeff Layton 			nfm = new;
20465294c1fSJeff Layton 		else
20565294c1fSJeff Layton 			fsnotify_put_mark(&new->nfm_mark);
20665294c1fSJeff Layton 	} while (unlikely(err == -EEXIST));
20765294c1fSJeff Layton 
20865294c1fSJeff Layton 	return nfm;
20965294c1fSJeff Layton }
21065294c1fSJeff Layton 
21165294c1fSJeff Layton static struct nfsd_file *
212c4c649abSChuck Lever nfsd_file_alloc(struct net *net, struct inode *inode, unsigned char need,
213c4c649abSChuck Lever 		bool want_gc)
21465294c1fSJeff Layton {
21565294c1fSJeff Layton 	struct nfsd_file *nf;
21665294c1fSJeff Layton 
21765294c1fSJeff Layton 	nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
218c4c649abSChuck Lever 	if (unlikely(!nf))
219c4c649abSChuck Lever 		return NULL;
220c4c649abSChuck Lever 
22165294c1fSJeff Layton 	INIT_LIST_HEAD(&nf->nf_lru);
222904940e9SChuck Lever 	nf->nf_birthtime = ktime_get();
22365294c1fSJeff Layton 	nf->nf_file = NULL;
22465294c1fSJeff Layton 	nf->nf_cred = get_current_cred();
225c4c649abSChuck Lever 	nf->nf_net = net;
226c4c649abSChuck Lever 	nf->nf_flags = want_gc ?
227c4c649abSChuck Lever 		BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING) | BIT(NFSD_FILE_GC) :
228c4c649abSChuck Lever 		BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING);
229c4c649abSChuck Lever 	nf->nf_inode = inode;
230ac3a2585SJeff Layton 	refcount_set(&nf->nf_ref, 1);
231c4c649abSChuck Lever 	nf->nf_may = need;
23265294c1fSJeff Layton 	nf->nf_mark = NULL;
23365294c1fSJeff Layton 	return nf;
23465294c1fSJeff Layton }
23565294c1fSJeff Layton 
2364c475eeeSJeff Layton /**
2374c475eeeSJeff Layton  * nfsd_file_check_write_error - check for writeback errors on a file
2384c475eeeSJeff Layton  * @nf: nfsd_file to check for writeback errors
2394c475eeeSJeff Layton  *
2404c475eeeSJeff Layton  * Check whether a nfsd_file has an unseen error. Reset the write
2414c475eeeSJeff Layton  * verifier if so.
2424c475eeeSJeff Layton  */
24382141185SJeff Layton static void
24482141185SJeff Layton nfsd_file_check_write_error(struct nfsd_file *nf)
24582141185SJeff Layton {
24682141185SJeff Layton 	struct file *file = nf->nf_file;
24782141185SJeff Layton 
2484c475eeeSJeff Layton 	if ((file->f_mode & FMODE_WRITE) &&
2494c475eeeSJeff Layton 	    filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)))
2504c475eeeSJeff Layton 		nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id));
25182141185SJeff Layton }
25282141185SJeff Layton 
25382141185SJeff Layton static void
25482141185SJeff Layton nfsd_file_hash_remove(struct nfsd_file *nf)
25582141185SJeff Layton {
25682141185SJeff Layton 	trace_nfsd_file_unhash(nf);
257c4c649abSChuck Lever 	rhltable_remove(&nfsd_file_rhltable, &nf->nf_rlist,
25882141185SJeff Layton 			nfsd_file_rhash_params);
25982141185SJeff Layton }
26082141185SJeff Layton 
26182141185SJeff Layton static bool
26282141185SJeff Layton nfsd_file_unhash(struct nfsd_file *nf)
26382141185SJeff Layton {
26482141185SJeff Layton 	if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
26582141185SJeff Layton 		nfsd_file_hash_remove(nf);
26682141185SJeff Layton 		return true;
26782141185SJeff Layton 	}
26882141185SJeff Layton 	return false;
26982141185SJeff Layton }
27082141185SJeff Layton 
271ac3a2585SJeff Layton static void
27265294c1fSJeff Layton nfsd_file_free(struct nfsd_file *nf)
27365294c1fSJeff Layton {
274904940e9SChuck Lever 	s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime));
27565294c1fSJeff Layton 
27682141185SJeff Layton 	trace_nfsd_file_free(nf);
27782141185SJeff Layton 
278d6329327SChuck Lever 	this_cpu_inc(nfsd_file_releases);
279904940e9SChuck Lever 	this_cpu_add(nfsd_file_total_age, age);
280d6329327SChuck Lever 
281ac3a2585SJeff Layton 	nfsd_file_unhash(nf);
28265294c1fSJeff Layton 	if (nf->nf_mark)
28365294c1fSJeff Layton 		nfsd_file_mark_put(nf->nf_mark);
28465294c1fSJeff Layton 	if (nf->nf_file) {
2854c475eeeSJeff Layton 		nfsd_file_check_write_error(nf);
286b2ff1bd7SJeff Layton 		filp_close(nf->nf_file, NULL);
28765294c1fSJeff Layton 	}
288668ed92eSChuck Lever 
289668ed92eSChuck Lever 	/*
290668ed92eSChuck Lever 	 * If this item is still linked via nf_lru, that's a bug.
291668ed92eSChuck Lever 	 * WARN and leak it to preserve system stability.
292668ed92eSChuck Lever 	 */
293668ed92eSChuck Lever 	if (WARN_ON_ONCE(!list_empty(&nf->nf_lru)))
294ac3a2585SJeff Layton 		return;
295668ed92eSChuck Lever 
29665294c1fSJeff Layton 	call_rcu(&nf->nf_rcu, nfsd_file_slab_free);
29765294c1fSJeff Layton }
29865294c1fSJeff Layton 
299055b24a8STrond Myklebust static bool
300055b24a8STrond Myklebust nfsd_file_check_writeback(struct nfsd_file *nf)
301055b24a8STrond Myklebust {
302055b24a8STrond Myklebust 	struct file *file = nf->nf_file;
303055b24a8STrond Myklebust 	struct address_space *mapping;
304055b24a8STrond Myklebust 
305dcb779fcSJeff Layton 	/* File not open for write? */
306dcb779fcSJeff Layton 	if (!(file->f_mode & FMODE_WRITE))
307055b24a8STrond Myklebust 		return false;
308dcb779fcSJeff Layton 
309dcb779fcSJeff Layton 	/*
310dcb779fcSJeff Layton 	 * Some filesystems (e.g. NFS) flush all dirty data on close.
311dcb779fcSJeff Layton 	 * On others, there is no need to wait for writeback.
312dcb779fcSJeff Layton 	 */
313dcb779fcSJeff Layton 	if (!(file_inode(file)->i_sb->s_export_op->flags & EXPORT_OP_FLUSH_ON_CLOSE))
314dcb779fcSJeff Layton 		return false;
315dcb779fcSJeff Layton 
316055b24a8STrond Myklebust 	mapping = file->f_mapping;
317055b24a8STrond Myklebust 	return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||
318055b24a8STrond Myklebust 		mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
319055b24a8STrond Myklebust }
320055b24a8STrond Myklebust 
321dcb779fcSJeff Layton 
322ac3a2585SJeff Layton static bool nfsd_file_lru_add(struct nfsd_file *nf)
32365294c1fSJeff Layton {
3244a0e73e6SChuck Lever 	set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
325ac3a2585SJeff Layton 	if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) {
326c46203acSChuck Lever 		trace_nfsd_file_lru_add(nf);
327ac3a2585SJeff Layton 		return true;
328ac3a2585SJeff Layton 	}
329ac3a2585SJeff Layton 	return false;
330c46203acSChuck Lever }
33165294c1fSJeff Layton 
332ac3a2585SJeff Layton static bool nfsd_file_lru_remove(struct nfsd_file *nf)
333c46203acSChuck Lever {
334ac3a2585SJeff Layton 	if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) {
335c46203acSChuck Lever 		trace_nfsd_file_lru_del(nf);
336ac3a2585SJeff Layton 		return true;
337ac3a2585SJeff Layton 	}
338ac3a2585SJeff Layton 	return false;
339c46203acSChuck Lever }
340c46203acSChuck Lever 
34182141185SJeff Layton struct nfsd_file *
34282141185SJeff Layton nfsd_file_get(struct nfsd_file *nf)
34365294c1fSJeff Layton {
34470f62231SJeff Layton 	if (nf && refcount_inc_not_zero(&nf->nf_ref))
34582141185SJeff Layton 		return nf;
34682141185SJeff Layton 	return NULL;
34765294c1fSJeff Layton }
34865294c1fSJeff Layton 
349ac3a2585SJeff Layton /**
350ac3a2585SJeff Layton  * nfsd_file_put - put the reference to a nfsd_file
351ac3a2585SJeff Layton  * @nf: nfsd_file of which to put the reference
352ac3a2585SJeff Layton  *
353ac3a2585SJeff Layton  * Put a reference to a nfsd_file. In the non-GC case, we just put the
354ac3a2585SJeff Layton  * reference immediately. In the GC case, if the reference would be
355ac3a2585SJeff Layton  * the last one, the put it on the LRU instead to be cleaned up later.
356ac3a2585SJeff Layton  */
35765294c1fSJeff Layton void
35865294c1fSJeff Layton nfsd_file_put(struct nfsd_file *nf)
35965294c1fSJeff Layton {
36008af54b3SChuck Lever 	might_sleep();
361ac3a2585SJeff Layton 	trace_nfsd_file_put(nf);
36208af54b3SChuck Lever 
363ac3a2585SJeff Layton 	if (test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
364ac3a2585SJeff Layton 	    test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
365ac3a2585SJeff Layton 		/*
366ac3a2585SJeff Layton 		 * If this is the last reference (nf_ref == 1), then try to
367ac3a2585SJeff Layton 		 * transfer it to the LRU.
368ac3a2585SJeff Layton 		 */
369ac3a2585SJeff Layton 		if (refcount_dec_not_one(&nf->nf_ref))
370ac3a2585SJeff Layton 			return;
3714d1ea845SChuck Lever 
372ac3a2585SJeff Layton 		/* Try to add it to the LRU.  If that fails, decrement. */
373ac3a2585SJeff Layton 		if (nfsd_file_lru_add(nf)) {
374ac3a2585SJeff Layton 			/* If it's still hashed, we're done */
375ac3a2585SJeff Layton 			if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
3769542e6a6STrond Myklebust 				nfsd_file_schedule_laundrette();
377ac3a2585SJeff Layton 				return;
378ac3a2585SJeff Layton 			}
379ac3a2585SJeff Layton 
380ac3a2585SJeff Layton 			/*
381ac3a2585SJeff Layton 			 * We're racing with unhashing, so try to remove it from
382ac3a2585SJeff Layton 			 * the LRU. If removal fails, then someone else already
383ac3a2585SJeff Layton 			 * has our reference.
384ac3a2585SJeff Layton 			 */
385ac3a2585SJeff Layton 			if (!nfsd_file_lru_remove(nf))
386ac3a2585SJeff Layton 				return;
387ac3a2585SJeff Layton 		}
388ac3a2585SJeff Layton 	}
389ac3a2585SJeff Layton 	if (refcount_dec_and_test(&nf->nf_ref))
390ac3a2585SJeff Layton 		nfsd_file_free(nf);
39165294c1fSJeff Layton }
39265294c1fSJeff Layton 
39365294c1fSJeff Layton static void
39465294c1fSJeff Layton nfsd_file_dispose_list(struct list_head *dispose)
39565294c1fSJeff Layton {
39665294c1fSJeff Layton 	struct nfsd_file *nf;
39765294c1fSJeff Layton 
39865294c1fSJeff Layton 	while (!list_empty(dispose)) {
39965294c1fSJeff Layton 		nf = list_first_entry(dispose, struct nfsd_file, nf_lru);
400668ed92eSChuck Lever 		list_del_init(&nf->nf_lru);
401ac3a2585SJeff Layton 		nfsd_file_free(nf);
40265294c1fSJeff Layton 	}
40365294c1fSJeff Layton }
40465294c1fSJeff Layton 
405*92e4a673SJeff Layton /**
406*92e4a673SJeff Layton  * nfsd_file_dispose_list_delayed - move list of dead files to net's freeme list
407*92e4a673SJeff Layton  * @dispose: list of nfsd_files to be disposed
408*92e4a673SJeff Layton  *
409*92e4a673SJeff Layton  * Transfers each file to the "freeme" list for its nfsd_net, to eventually
410*92e4a673SJeff Layton  * be disposed of by the per-net garbage collector.
411*92e4a673SJeff Layton  */
4129542e6a6STrond Myklebust static void
4139542e6a6STrond Myklebust nfsd_file_dispose_list_delayed(struct list_head *dispose)
4149542e6a6STrond Myklebust {
4159542e6a6STrond Myklebust 	while(!list_empty(dispose)) {
416*92e4a673SJeff Layton 		struct nfsd_file *nf = list_first_entry(dispose,
417*92e4a673SJeff Layton 						struct nfsd_file, nf_lru);
418*92e4a673SJeff Layton 		struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
419*92e4a673SJeff Layton 		struct nfsd_fcache_disposal *l = nn->fcache_disposal;
420*92e4a673SJeff Layton 
421*92e4a673SJeff Layton 		spin_lock(&l->lock);
422*92e4a673SJeff Layton 		list_move_tail(&nf->nf_lru, &l->freeme);
423*92e4a673SJeff Layton 		spin_unlock(&l->lock);
424*92e4a673SJeff Layton 		queue_work(nfsd_filecache_wq, &l->work);
4259542e6a6STrond Myklebust 	}
4269542e6a6STrond Myklebust }
4279542e6a6STrond Myklebust 
4284a0e73e6SChuck Lever /**
4294a0e73e6SChuck Lever  * nfsd_file_lru_cb - Examine an entry on the LRU list
4304a0e73e6SChuck Lever  * @item: LRU entry to examine
4314a0e73e6SChuck Lever  * @lru: controlling LRU
4324a0e73e6SChuck Lever  * @lock: LRU list lock (unused)
4334a0e73e6SChuck Lever  * @arg: dispose list
4344a0e73e6SChuck Lever  *
4354a0e73e6SChuck Lever  * Return values:
4364a0e73e6SChuck Lever  *   %LRU_REMOVED: @item was removed from the LRU
437edead3a5SChuck Lever  *   %LRU_ROTATE: @item is to be moved to the LRU tail
4384a0e73e6SChuck Lever  *   %LRU_SKIP: @item cannot be evicted
43965294c1fSJeff Layton  */
44065294c1fSJeff Layton static enum lru_status
44165294c1fSJeff Layton nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
44265294c1fSJeff Layton 		 spinlock_t *lock, void *arg)
44365294c1fSJeff Layton 	__releases(lock)
44465294c1fSJeff Layton 	__acquires(lock)
44565294c1fSJeff Layton {
44665294c1fSJeff Layton 	struct list_head *head = arg;
44765294c1fSJeff Layton 	struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru);
44865294c1fSJeff Layton 
449ac3a2585SJeff Layton 	/* We should only be dealing with GC entries here */
450ac3a2585SJeff Layton 	WARN_ON_ONCE(!test_bit(NFSD_FILE_GC, &nf->nf_flags));
451055b24a8STrond Myklebust 
452055b24a8STrond Myklebust 	/*
453055b24a8STrond Myklebust 	 * Don't throw out files that are still undergoing I/O or
454055b24a8STrond Myklebust 	 * that have uncleared errors pending.
455055b24a8STrond Myklebust 	 */
456c46203acSChuck Lever 	if (nfsd_file_check_writeback(nf)) {
457c46203acSChuck Lever 		trace_nfsd_file_gc_writeback(nf);
45865294c1fSJeff Layton 		return LRU_SKIP;
45965294c1fSJeff Layton 	}
46065294c1fSJeff Layton 
461ac3a2585SJeff Layton 	/* If it was recently added to the list, skip it */
462c46203acSChuck Lever 	if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) {
463c46203acSChuck Lever 		trace_nfsd_file_gc_referenced(nf);
464edead3a5SChuck Lever 		return LRU_ROTATE;
46565294c1fSJeff Layton 	}
46665294c1fSJeff Layton 
467ac3a2585SJeff Layton 	/*
468ac3a2585SJeff Layton 	 * Put the reference held on behalf of the LRU. If it wasn't the last
469ac3a2585SJeff Layton 	 * one, then just remove it from the LRU and ignore it.
470ac3a2585SJeff Layton 	 */
471ac3a2585SJeff Layton 	if (!refcount_dec_and_test(&nf->nf_ref)) {
472ac3a2585SJeff Layton 		trace_nfsd_file_gc_in_use(nf);
473ac3a2585SJeff Layton 		list_lru_isolate(lru, &nf->nf_lru);
474ac3a2585SJeff Layton 		return LRU_REMOVED;
475c46203acSChuck Lever 	}
47665294c1fSJeff Layton 
477ac3a2585SJeff Layton 	/* Refcount went to zero. Unhash it and queue it to the dispose list */
478ac3a2585SJeff Layton 	nfsd_file_unhash(nf);
47965294c1fSJeff Layton 	list_lru_isolate_move(lru, &nf->nf_lru, head);
48094660cc1SChuck Lever 	this_cpu_inc(nfsd_file_evictions);
481c46203acSChuck Lever 	trace_nfsd_file_gc_disposed(nf);
48265294c1fSJeff Layton 	return LRU_REMOVED;
48365294c1fSJeff Layton }
48465294c1fSJeff Layton 
4859542e6a6STrond Myklebust static void
4869542e6a6STrond Myklebust nfsd_file_gc(void)
4879542e6a6STrond Myklebust {
4883bc6d347SChuck Lever 	LIST_HEAD(dispose);
48994660cc1SChuck Lever 	unsigned long ret;
4903bc6d347SChuck Lever 
49194660cc1SChuck Lever 	ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb,
492edead3a5SChuck Lever 			    &dispose, list_lru_count(&nfsd_file_lru));
49394660cc1SChuck Lever 	trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
494ac3a2585SJeff Layton 	nfsd_file_dispose_list_delayed(&dispose);
4959542e6a6STrond Myklebust }
4969542e6a6STrond Myklebust 
4979542e6a6STrond Myklebust static void
4989542e6a6STrond Myklebust nfsd_file_gc_worker(struct work_struct *work)
4999542e6a6STrond Myklebust {
5009542e6a6STrond Myklebust 	nfsd_file_gc();
50122ae4c11SJeff Layton 	if (list_lru_count(&nfsd_file_lru))
5029542e6a6STrond Myklebust 		nfsd_file_schedule_laundrette();
50365294c1fSJeff Layton }
50465294c1fSJeff Layton 
50565294c1fSJeff Layton static unsigned long
50665294c1fSJeff Layton nfsd_file_lru_count(struct shrinker *s, struct shrink_control *sc)
50765294c1fSJeff Layton {
50865294c1fSJeff Layton 	return list_lru_count(&nfsd_file_lru);
50965294c1fSJeff Layton }
51065294c1fSJeff Layton 
51165294c1fSJeff Layton static unsigned long
51265294c1fSJeff Layton nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
51365294c1fSJeff Layton {
51439f1d1ffSChuck Lever 	LIST_HEAD(dispose);
51539f1d1ffSChuck Lever 	unsigned long ret;
51639f1d1ffSChuck Lever 
51739f1d1ffSChuck Lever 	ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
51839f1d1ffSChuck Lever 				   nfsd_file_lru_cb, &dispose);
51994660cc1SChuck Lever 	trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
520ac3a2585SJeff Layton 	nfsd_file_dispose_list_delayed(&dispose);
52139f1d1ffSChuck Lever 	return ret;
52265294c1fSJeff Layton }
52365294c1fSJeff Layton 
52465294c1fSJeff Layton static struct shrinker	nfsd_file_shrinker = {
52565294c1fSJeff Layton 	.scan_objects = nfsd_file_lru_scan,
52665294c1fSJeff Layton 	.count_objects = nfsd_file_lru_count,
52765294c1fSJeff Layton 	.seeks = 1,
52865294c1fSJeff Layton };
52965294c1fSJeff Layton 
530ac3a2585SJeff Layton /**
5314bdbba54SJeff Layton  * nfsd_file_cond_queue - conditionally unhash and queue a nfsd_file
5324bdbba54SJeff Layton  * @nf: nfsd_file to attempt to queue
5334bdbba54SJeff Layton  * @dispose: private list to queue successfully-put objects
5344bdbba54SJeff Layton  *
5354bdbba54SJeff Layton  * Unhash an nfsd_file, try to get a reference to it, and then put that
5364bdbba54SJeff Layton  * reference. If it's the last reference, queue it to the dispose list.
5374bdbba54SJeff Layton  */
5384bdbba54SJeff Layton static void
5394bdbba54SJeff Layton nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose)
5404bdbba54SJeff Layton 	__must_hold(RCU)
5414bdbba54SJeff Layton {
5424bdbba54SJeff Layton 	int decrement = 1;
5434bdbba54SJeff Layton 
5444bdbba54SJeff Layton 	/* If we raced with someone else unhashing, ignore it */
5454bdbba54SJeff Layton 	if (!nfsd_file_unhash(nf))
5464bdbba54SJeff Layton 		return;
5474bdbba54SJeff Layton 
5484bdbba54SJeff Layton 	/* If we can't get a reference, ignore it */
5494bdbba54SJeff Layton 	if (!nfsd_file_get(nf))
5504bdbba54SJeff Layton 		return;
5514bdbba54SJeff Layton 
5524bdbba54SJeff Layton 	/* Extra decrement if we remove from the LRU */
5534bdbba54SJeff Layton 	if (nfsd_file_lru_remove(nf))
5544bdbba54SJeff Layton 		++decrement;
5554bdbba54SJeff Layton 
5564bdbba54SJeff Layton 	/* If refcount goes to 0, then put on the dispose list */
5574bdbba54SJeff Layton 	if (refcount_sub_and_test(decrement, &nf->nf_ref)) {
5584bdbba54SJeff Layton 		list_add(&nf->nf_lru, dispose);
5594bdbba54SJeff Layton 		trace_nfsd_file_closing(nf);
5604bdbba54SJeff Layton 	}
5614bdbba54SJeff Layton }
5624bdbba54SJeff Layton 
5634bdbba54SJeff Layton /**
564ac3a2585SJeff Layton  * nfsd_file_queue_for_close: try to close out any open nfsd_files for an inode
565ac3a2585SJeff Layton  * @inode:   inode on which to close out nfsd_files
566ac3a2585SJeff Layton  * @dispose: list on which to gather nfsd_files to close out
567ac3a2585SJeff Layton  *
568c4c649abSChuck Lever  * An nfsd_file represents a struct file being held open on behalf of nfsd.
569c4c649abSChuck Lever  * An open file however can block other activity (such as leases), or cause
570ac3a2585SJeff Layton  * undesirable behavior (e.g. spurious silly-renames when reexporting NFS).
571ac3a2585SJeff Layton  *
572ac3a2585SJeff Layton  * This function is intended to find open nfsd_files when this sort of
573ac3a2585SJeff Layton  * conflicting access occurs and then attempt to close those files out.
574ac3a2585SJeff Layton  *
575ac3a2585SJeff Layton  * Populates the dispose list with entries that have already had their
576ac3a2585SJeff Layton  * refcounts go to zero. The actual free of an nfsd_file can be expensive,
577ac3a2585SJeff Layton  * so we leave it up to the caller whether it wants to wait or not.
578a8455110SChuck Lever  */
579ac3a2585SJeff Layton static void
580ac3a2585SJeff Layton nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
58165294c1fSJeff Layton {
582c4c649abSChuck Lever 	struct rhlist_head *tmp, *list;
58365294c1fSJeff Layton 	struct nfsd_file *nf;
58465294c1fSJeff Layton 
585ce502f81SChuck Lever 	rcu_read_lock();
586c4c649abSChuck Lever 	list = rhltable_lookup(&nfsd_file_rhltable, &inode,
587ce502f81SChuck Lever 			       nfsd_file_rhash_params);
588c4c649abSChuck Lever 	rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) {
589c4c649abSChuck Lever 		if (!test_bit(NFSD_FILE_GC, &nf->nf_flags))
590c4c649abSChuck Lever 			continue;
5914bdbba54SJeff Layton 		nfsd_file_cond_queue(nf, dispose);
592c4c649abSChuck Lever 	}
593ce502f81SChuck Lever 	rcu_read_unlock();
59465294c1fSJeff Layton }
59565294c1fSJeff Layton 
59665294c1fSJeff Layton /**
59719598141STrond Myklebust  * nfsd_file_close_inode - attempt a delayed close of a nfsd_file
59865294c1fSJeff Layton  * @inode: inode of the file to attempt to remove
59965294c1fSJeff Layton  *
600ac3a2585SJeff Layton  * Close out any open nfsd_files that can be reaped for @inode. The
601ac3a2585SJeff Layton  * actual freeing is deferred to the dispose_list_delayed infrastructure.
602ac3a2585SJeff Layton  *
603ac3a2585SJeff Layton  * This is used by the fsnotify callbacks and setlease notifier.
60465294c1fSJeff Layton  */
60565294c1fSJeff Layton static void
60665294c1fSJeff Layton nfsd_file_close_inode(struct inode *inode)
60765294c1fSJeff Layton {
60865294c1fSJeff Layton 	LIST_HEAD(dispose);
60965294c1fSJeff Layton 
610ac3a2585SJeff Layton 	nfsd_file_queue_for_close(inode, &dispose);
6119542e6a6STrond Myklebust 	nfsd_file_dispose_list_delayed(&dispose);
61265294c1fSJeff Layton }
61365294c1fSJeff Layton 
61465294c1fSJeff Layton /**
615ac3a2585SJeff Layton  * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file
616ac3a2585SJeff Layton  * @inode: inode of the file to attempt to remove
617ac3a2585SJeff Layton  *
618ac3a2585SJeff Layton  * Close out any open nfsd_files that can be reaped for @inode. The
619ac3a2585SJeff Layton  * nfsd_files are closed out synchronously.
620ac3a2585SJeff Layton  *
621ac3a2585SJeff Layton  * This is called from nfsd_rename and nfsd_unlink to avoid silly-renames
622ac3a2585SJeff Layton  * when reexporting NFS.
623ac3a2585SJeff Layton  */
624ac3a2585SJeff Layton void
625ac3a2585SJeff Layton nfsd_file_close_inode_sync(struct inode *inode)
626ac3a2585SJeff Layton {
627ac3a2585SJeff Layton 	struct nfsd_file *nf;
628ac3a2585SJeff Layton 	LIST_HEAD(dispose);
629ac3a2585SJeff Layton 
630ac3a2585SJeff Layton 	trace_nfsd_file_close(inode);
631ac3a2585SJeff Layton 
632ac3a2585SJeff Layton 	nfsd_file_queue_for_close(inode, &dispose);
633ac3a2585SJeff Layton 	while (!list_empty(&dispose)) {
634ac3a2585SJeff Layton 		nf = list_first_entry(&dispose, struct nfsd_file, nf_lru);
635ac3a2585SJeff Layton 		list_del_init(&nf->nf_lru);
636ac3a2585SJeff Layton 		nfsd_file_free(nf);
637ac3a2585SJeff Layton 	}
638ac3a2585SJeff Layton 	flush_delayed_fput();
639ac3a2585SJeff Layton }
640ac3a2585SJeff Layton 
641ac3a2585SJeff Layton /**
64265294c1fSJeff Layton  * nfsd_file_delayed_close - close unused nfsd_files
64365294c1fSJeff Layton  * @work: dummy
64465294c1fSJeff Layton  *
645*92e4a673SJeff Layton  * Scrape the freeme list for this nfsd_net, and then dispose of them
646*92e4a673SJeff Layton  * all.
64765294c1fSJeff Layton  */
64865294c1fSJeff Layton static void
64965294c1fSJeff Layton nfsd_file_delayed_close(struct work_struct *work)
65065294c1fSJeff Layton {
65165294c1fSJeff Layton 	LIST_HEAD(head);
6529542e6a6STrond Myklebust 	struct nfsd_fcache_disposal *l = container_of(work,
6539542e6a6STrond Myklebust 			struct nfsd_fcache_disposal, work);
65465294c1fSJeff Layton 
655*92e4a673SJeff Layton 	spin_lock(&l->lock);
656*92e4a673SJeff Layton 	list_splice_init(&l->freeme, &head);
657*92e4a673SJeff Layton 	spin_unlock(&l->lock);
658*92e4a673SJeff Layton 
6599542e6a6STrond Myklebust 	nfsd_file_dispose_list(&head);
66065294c1fSJeff Layton }
66165294c1fSJeff Layton 
66265294c1fSJeff Layton static int
66365294c1fSJeff Layton nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg,
66465294c1fSJeff Layton 			    void *data)
66565294c1fSJeff Layton {
66665294c1fSJeff Layton 	struct file_lock *fl = data;
66765294c1fSJeff Layton 
66865294c1fSJeff Layton 	/* Only close files for F_SETLEASE leases */
66965294c1fSJeff Layton 	if (fl->fl_flags & FL_LEASE)
670ac3a2585SJeff Layton 		nfsd_file_close_inode(file_inode(fl->fl_file));
67165294c1fSJeff Layton 	return 0;
67265294c1fSJeff Layton }
67365294c1fSJeff Layton 
67465294c1fSJeff Layton static struct notifier_block nfsd_file_lease_notifier = {
67565294c1fSJeff Layton 	.notifier_call = nfsd_file_lease_notifier_call,
67665294c1fSJeff Layton };
67765294c1fSJeff Layton 
67865294c1fSJeff Layton static int
679b9a1b977SAmir Goldstein nfsd_file_fsnotify_handle_event(struct fsnotify_mark *mark, u32 mask,
680b9a1b977SAmir Goldstein 				struct inode *inode, struct inode *dir,
681950cc0d2SAmir Goldstein 				const struct qstr *name, u32 cookie)
68265294c1fSJeff Layton {
68324dca905SGabriel Krisman Bertazi 	if (WARN_ON_ONCE(!inode))
68424dca905SGabriel Krisman Bertazi 		return 0;
68524dca905SGabriel Krisman Bertazi 
68665294c1fSJeff Layton 	trace_nfsd_file_fsnotify_handle_event(inode, mask);
68765294c1fSJeff Layton 
68865294c1fSJeff Layton 	/* Should be no marks on non-regular files */
68965294c1fSJeff Layton 	if (!S_ISREG(inode->i_mode)) {
69065294c1fSJeff Layton 		WARN_ON_ONCE(1);
69165294c1fSJeff Layton 		return 0;
69265294c1fSJeff Layton 	}
69365294c1fSJeff Layton 
69465294c1fSJeff Layton 	/* don't close files if this was not the last link */
69565294c1fSJeff Layton 	if (mask & FS_ATTRIB) {
69665294c1fSJeff Layton 		if (inode->i_nlink)
69765294c1fSJeff Layton 			return 0;
69865294c1fSJeff Layton 	}
69965294c1fSJeff Layton 
70065294c1fSJeff Layton 	nfsd_file_close_inode(inode);
70165294c1fSJeff Layton 	return 0;
70265294c1fSJeff Layton }
70365294c1fSJeff Layton 
70465294c1fSJeff Layton 
70565294c1fSJeff Layton static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
706b9a1b977SAmir Goldstein 	.handle_inode_event = nfsd_file_fsnotify_handle_event,
70765294c1fSJeff Layton 	.free_mark = nfsd_file_mark_free,
70865294c1fSJeff Layton };
70965294c1fSJeff Layton 
71065294c1fSJeff Layton int
71165294c1fSJeff Layton nfsd_file_cache_init(void)
71265294c1fSJeff Layton {
713fc22945eSChuck Lever 	int ret;
71465294c1fSJeff Layton 
715c7b824c3SChuck Lever 	lockdep_assert_held(&nfsd_mutex);
716c7b824c3SChuck Lever 	if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
71765294c1fSJeff Layton 		return 0;
71865294c1fSJeff Layton 
719c4c649abSChuck Lever 	ret = rhltable_init(&nfsd_file_rhltable, &nfsd_file_rhash_params);
720fc22945eSChuck Lever 	if (ret)
721fc22945eSChuck Lever 		return ret;
722fc22945eSChuck Lever 
723fc22945eSChuck Lever 	ret = -ENOMEM;
7249542e6a6STrond Myklebust 	nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0);
7259542e6a6STrond Myklebust 	if (!nfsd_filecache_wq)
7269542e6a6STrond Myklebust 		goto out;
7279542e6a6STrond Myklebust 
72865294c1fSJeff Layton 	nfsd_file_slab = kmem_cache_create("nfsd_file",
72965294c1fSJeff Layton 				sizeof(struct nfsd_file), 0, 0, NULL);
73065294c1fSJeff Layton 	if (!nfsd_file_slab) {
73165294c1fSJeff Layton 		pr_err("nfsd: unable to create nfsd_file_slab\n");
73265294c1fSJeff Layton 		goto out_err;
73365294c1fSJeff Layton 	}
73465294c1fSJeff Layton 
73565294c1fSJeff Layton 	nfsd_file_mark_slab = kmem_cache_create("nfsd_file_mark",
73665294c1fSJeff Layton 					sizeof(struct nfsd_file_mark), 0, 0, NULL);
73765294c1fSJeff Layton 	if (!nfsd_file_mark_slab) {
73865294c1fSJeff Layton 		pr_err("nfsd: unable to create nfsd_file_mark_slab\n");
73965294c1fSJeff Layton 		goto out_err;
74065294c1fSJeff Layton 	}
74165294c1fSJeff Layton 
74265294c1fSJeff Layton 
74365294c1fSJeff Layton 	ret = list_lru_init(&nfsd_file_lru);
74465294c1fSJeff Layton 	if (ret) {
74565294c1fSJeff Layton 		pr_err("nfsd: failed to init nfsd_file_lru: %d\n", ret);
74665294c1fSJeff Layton 		goto out_err;
74765294c1fSJeff Layton 	}
74865294c1fSJeff Layton 
749e33c267aSRoman Gushchin 	ret = register_shrinker(&nfsd_file_shrinker, "nfsd-filecache");
75065294c1fSJeff Layton 	if (ret) {
75165294c1fSJeff Layton 		pr_err("nfsd: failed to register nfsd_file_shrinker: %d\n", ret);
75265294c1fSJeff Layton 		goto out_lru;
75365294c1fSJeff Layton 	}
75465294c1fSJeff Layton 
75565294c1fSJeff Layton 	ret = lease_register_notifier(&nfsd_file_lease_notifier);
75665294c1fSJeff Layton 	if (ret) {
75765294c1fSJeff Layton 		pr_err("nfsd: unable to register lease notifier: %d\n", ret);
75865294c1fSJeff Layton 		goto out_shrinker;
75965294c1fSJeff Layton 	}
76065294c1fSJeff Layton 
761867a448dSAmir Goldstein 	nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops,
762b8962a9dSAmir Goldstein 							FSNOTIFY_GROUP_NOFS);
76365294c1fSJeff Layton 	if (IS_ERR(nfsd_file_fsnotify_group)) {
76465294c1fSJeff Layton 		pr_err("nfsd: unable to create fsnotify group: %ld\n",
76565294c1fSJeff Layton 			PTR_ERR(nfsd_file_fsnotify_group));
766231307dfSHuang Guobin 		ret = PTR_ERR(nfsd_file_fsnotify_group);
76765294c1fSJeff Layton 		nfsd_file_fsnotify_group = NULL;
76865294c1fSJeff Layton 		goto out_notifier;
76965294c1fSJeff Layton 	}
77065294c1fSJeff Layton 
7719542e6a6STrond Myklebust 	INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker);
77265294c1fSJeff Layton out:
77365294c1fSJeff Layton 	return ret;
77465294c1fSJeff Layton out_notifier:
77565294c1fSJeff Layton 	lease_unregister_notifier(&nfsd_file_lease_notifier);
77665294c1fSJeff Layton out_shrinker:
77765294c1fSJeff Layton 	unregister_shrinker(&nfsd_file_shrinker);
77865294c1fSJeff Layton out_lru:
77965294c1fSJeff Layton 	list_lru_destroy(&nfsd_file_lru);
78065294c1fSJeff Layton out_err:
78165294c1fSJeff Layton 	kmem_cache_destroy(nfsd_file_slab);
78265294c1fSJeff Layton 	nfsd_file_slab = NULL;
78365294c1fSJeff Layton 	kmem_cache_destroy(nfsd_file_mark_slab);
78465294c1fSJeff Layton 	nfsd_file_mark_slab = NULL;
7859542e6a6STrond Myklebust 	destroy_workqueue(nfsd_filecache_wq);
7869542e6a6STrond Myklebust 	nfsd_filecache_wq = NULL;
787c4c649abSChuck Lever 	rhltable_destroy(&nfsd_file_rhltable);
78865294c1fSJeff Layton 	goto out;
78965294c1fSJeff Layton }
79065294c1fSJeff Layton 
791ac3a2585SJeff Layton /**
792ac3a2585SJeff Layton  * __nfsd_file_cache_purge: clean out the cache for shutdown
793ac3a2585SJeff Layton  * @net: net-namespace to shut down the cache (may be NULL)
794ac3a2585SJeff Layton  *
795ac3a2585SJeff Layton  * Walk the nfsd_file cache and close out any that match @net. If @net is NULL,
796972cc0e0SJeff Layton  * then close out everything. Called when an nfsd instance is being shut down,
797972cc0e0SJeff Layton  * and when the exports table is flushed.
798ac3a2585SJeff Layton  */
799c7b824c3SChuck Lever static void
800c7b824c3SChuck Lever __nfsd_file_cache_purge(struct net *net)
80165294c1fSJeff Layton {
802ce502f81SChuck Lever 	struct rhashtable_iter iter;
80365294c1fSJeff Layton 	struct nfsd_file *nf;
80465294c1fSJeff Layton 	LIST_HEAD(dispose);
80565294c1fSJeff Layton 
806c4c649abSChuck Lever 	rhltable_walk_enter(&nfsd_file_rhltable, &iter);
807ce502f81SChuck Lever 	do {
808ce502f81SChuck Lever 		rhashtable_walk_start(&iter);
80965294c1fSJeff Layton 
810ce502f81SChuck Lever 		nf = rhashtable_walk_next(&iter);
811ce502f81SChuck Lever 		while (!IS_ERR_OR_NULL(nf)) {
8124bdbba54SJeff Layton 			if (!net || nf->nf_net == net)
8134bdbba54SJeff Layton 				nfsd_file_cond_queue(nf, &dispose);
814ce502f81SChuck Lever 			nf = rhashtable_walk_next(&iter);
81565294c1fSJeff Layton 		}
816ce502f81SChuck Lever 
817ce502f81SChuck Lever 		rhashtable_walk_stop(&iter);
818ce502f81SChuck Lever 	} while (nf == ERR_PTR(-EAGAIN));
819ce502f81SChuck Lever 	rhashtable_walk_exit(&iter);
820ce502f81SChuck Lever 
82165294c1fSJeff Layton 	nfsd_file_dispose_list(&dispose);
82265294c1fSJeff Layton }
82365294c1fSJeff Layton 
8249542e6a6STrond Myklebust static struct nfsd_fcache_disposal *
8251463b38eSNeilBrown nfsd_alloc_fcache_disposal(void)
8269542e6a6STrond Myklebust {
8279542e6a6STrond Myklebust 	struct nfsd_fcache_disposal *l;
8289542e6a6STrond Myklebust 
8299542e6a6STrond Myklebust 	l = kmalloc(sizeof(*l), GFP_KERNEL);
8309542e6a6STrond Myklebust 	if (!l)
8319542e6a6STrond Myklebust 		return NULL;
8329542e6a6STrond Myklebust 	INIT_WORK(&l->work, nfsd_file_delayed_close);
8339542e6a6STrond Myklebust 	spin_lock_init(&l->lock);
8349542e6a6STrond Myklebust 	INIT_LIST_HEAD(&l->freeme);
8359542e6a6STrond Myklebust 	return l;
8369542e6a6STrond Myklebust }
8379542e6a6STrond Myklebust 
8389542e6a6STrond Myklebust static void
8399542e6a6STrond Myklebust nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
8409542e6a6STrond Myklebust {
8419542e6a6STrond Myklebust 	cancel_work_sync(&l->work);
8429542e6a6STrond Myklebust 	nfsd_file_dispose_list(&l->freeme);
8431463b38eSNeilBrown 	kfree(l);
8449542e6a6STrond Myklebust }
8459542e6a6STrond Myklebust 
8469542e6a6STrond Myklebust static void
8479542e6a6STrond Myklebust nfsd_free_fcache_disposal_net(struct net *net)
8489542e6a6STrond Myklebust {
8491463b38eSNeilBrown 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
8501463b38eSNeilBrown 	struct nfsd_fcache_disposal *l = nn->fcache_disposal;
8519542e6a6STrond Myklebust 
8529542e6a6STrond Myklebust 	nfsd_free_fcache_disposal(l);
8539542e6a6STrond Myklebust }
8549542e6a6STrond Myklebust 
8559542e6a6STrond Myklebust int
8569542e6a6STrond Myklebust nfsd_file_cache_start_net(struct net *net)
8579542e6a6STrond Myklebust {
8581463b38eSNeilBrown 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
8591463b38eSNeilBrown 
8601463b38eSNeilBrown 	nn->fcache_disposal = nfsd_alloc_fcache_disposal();
8611463b38eSNeilBrown 	return nn->fcache_disposal ? 0 : -ENOMEM;
8629542e6a6STrond Myklebust }
8639542e6a6STrond Myklebust 
864c7b824c3SChuck Lever /**
865c7b824c3SChuck Lever  * nfsd_file_cache_purge - Remove all cache items associated with @net
866c7b824c3SChuck Lever  * @net: target net namespace
867c7b824c3SChuck Lever  *
868c7b824c3SChuck Lever  */
869c7b824c3SChuck Lever void
870c7b824c3SChuck Lever nfsd_file_cache_purge(struct net *net)
871c7b824c3SChuck Lever {
872c7b824c3SChuck Lever 	lockdep_assert_held(&nfsd_mutex);
873c7b824c3SChuck Lever 	if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
874c7b824c3SChuck Lever 		__nfsd_file_cache_purge(net);
875c7b824c3SChuck Lever }
876c7b824c3SChuck Lever 
8779542e6a6STrond Myklebust void
8789542e6a6STrond Myklebust nfsd_file_cache_shutdown_net(struct net *net)
8799542e6a6STrond Myklebust {
8809542e6a6STrond Myklebust 	nfsd_file_cache_purge(net);
8819542e6a6STrond Myklebust 	nfsd_free_fcache_disposal_net(net);
8829542e6a6STrond Myklebust }
8839542e6a6STrond Myklebust 
88465294c1fSJeff Layton void
88565294c1fSJeff Layton nfsd_file_cache_shutdown(void)
88665294c1fSJeff Layton {
8878b330f78SChuck Lever 	int i;
8888b330f78SChuck Lever 
889c7b824c3SChuck Lever 	lockdep_assert_held(&nfsd_mutex);
890c7b824c3SChuck Lever 	if (test_and_clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0)
891c7b824c3SChuck Lever 		return;
89265294c1fSJeff Layton 
89365294c1fSJeff Layton 	lease_unregister_notifier(&nfsd_file_lease_notifier);
89465294c1fSJeff Layton 	unregister_shrinker(&nfsd_file_shrinker);
89565294c1fSJeff Layton 	/*
89665294c1fSJeff Layton 	 * make sure all callers of nfsd_file_lru_cb are done before
89765294c1fSJeff Layton 	 * calling nfsd_file_cache_purge
89865294c1fSJeff Layton 	 */
89965294c1fSJeff Layton 	cancel_delayed_work_sync(&nfsd_filecache_laundrette);
900c7b824c3SChuck Lever 	__nfsd_file_cache_purge(NULL);
90165294c1fSJeff Layton 	list_lru_destroy(&nfsd_file_lru);
90265294c1fSJeff Layton 	rcu_barrier();
90365294c1fSJeff Layton 	fsnotify_put_group(nfsd_file_fsnotify_group);
90465294c1fSJeff Layton 	nfsd_file_fsnotify_group = NULL;
90565294c1fSJeff Layton 	kmem_cache_destroy(nfsd_file_slab);
90665294c1fSJeff Layton 	nfsd_file_slab = NULL;
90765294c1fSJeff Layton 	fsnotify_wait_marks_destroyed();
90865294c1fSJeff Layton 	kmem_cache_destroy(nfsd_file_mark_slab);
90965294c1fSJeff Layton 	nfsd_file_mark_slab = NULL;
9109542e6a6STrond Myklebust 	destroy_workqueue(nfsd_filecache_wq);
9119542e6a6STrond Myklebust 	nfsd_filecache_wq = NULL;
912c4c649abSChuck Lever 	rhltable_destroy(&nfsd_file_rhltable);
91365294c1fSJeff Layton 
9148b330f78SChuck Lever 	for_each_possible_cpu(i) {
9158b330f78SChuck Lever 		per_cpu(nfsd_file_cache_hits, i) = 0;
9168b330f78SChuck Lever 		per_cpu(nfsd_file_acquisitions, i) = 0;
9178b330f78SChuck Lever 		per_cpu(nfsd_file_releases, i) = 0;
9188b330f78SChuck Lever 		per_cpu(nfsd_file_total_age, i) = 0;
9198b330f78SChuck Lever 		per_cpu(nfsd_file_evictions, i) = 0;
92065294c1fSJeff Layton 	}
92165294c1fSJeff Layton }
92265294c1fSJeff Layton 
923c4c649abSChuck Lever static struct nfsd_file *
924c4c649abSChuck Lever nfsd_file_lookup_locked(const struct net *net, const struct cred *cred,
925c4c649abSChuck Lever 			struct inode *inode, unsigned char need,
926c4c649abSChuck Lever 			bool want_gc)
927c4c649abSChuck Lever {
928c4c649abSChuck Lever 	struct rhlist_head *tmp, *list;
929c4c649abSChuck Lever 	struct nfsd_file *nf;
930c4c649abSChuck Lever 
931c4c649abSChuck Lever 	list = rhltable_lookup(&nfsd_file_rhltable, &inode,
932c4c649abSChuck Lever 			       nfsd_file_rhash_params);
933c4c649abSChuck Lever 	rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) {
934c4c649abSChuck Lever 		if (nf->nf_may != need)
935c4c649abSChuck Lever 			continue;
936c4c649abSChuck Lever 		if (nf->nf_net != net)
937c4c649abSChuck Lever 			continue;
938c4c649abSChuck Lever 		if (!nfsd_match_cred(nf->nf_cred, cred))
939c4c649abSChuck Lever 			continue;
940c4c649abSChuck Lever 		if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != want_gc)
941c4c649abSChuck Lever 			continue;
942c4c649abSChuck Lever 		if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
943c4c649abSChuck Lever 			continue;
944c4c649abSChuck Lever 
945c4c649abSChuck Lever 		if (!nfsd_file_get(nf))
946c4c649abSChuck Lever 			continue;
947c4c649abSChuck Lever 		return nf;
948c4c649abSChuck Lever 	}
949c4c649abSChuck Lever 	return NULL;
950c4c649abSChuck Lever }
951c4c649abSChuck Lever 
95265294c1fSJeff Layton /**
953ce502f81SChuck Lever  * nfsd_file_is_cached - are there any cached open files for this inode?
954ce502f81SChuck Lever  * @inode: inode to check
95565294c1fSJeff Layton  *
956ce502f81SChuck Lever  * The lookup matches inodes in all net namespaces and is atomic wrt
957ce502f81SChuck Lever  * nfsd_file_acquire().
958ce502f81SChuck Lever  *
959ce502f81SChuck Lever  * Return values:
960ce502f81SChuck Lever  *   %true: filecache contains at least one file matching this inode
961ce502f81SChuck Lever  *   %false: filecache contains no files matching this inode
96265294c1fSJeff Layton  */
96365294c1fSJeff Layton bool
96465294c1fSJeff Layton nfsd_file_is_cached(struct inode *inode)
96565294c1fSJeff Layton {
966c4c649abSChuck Lever 	struct rhlist_head *tmp, *list;
967c4c649abSChuck Lever 	struct nfsd_file *nf;
96865294c1fSJeff Layton 	bool ret = false;
96965294c1fSJeff Layton 
970c4c649abSChuck Lever 	rcu_read_lock();
971c4c649abSChuck Lever 	list = rhltable_lookup(&nfsd_file_rhltable, &inode,
972c4c649abSChuck Lever 			       nfsd_file_rhash_params);
973c4c649abSChuck Lever 	rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist)
974c4c649abSChuck Lever 		if (test_bit(NFSD_FILE_GC, &nf->nf_flags)) {
97565294c1fSJeff Layton 			ret = true;
976c4c649abSChuck Lever 			break;
977c4c649abSChuck Lever 		}
978c4c649abSChuck Lever 	rcu_read_unlock();
979c4c649abSChuck Lever 
98054f7df70SChuck Lever 	trace_nfsd_file_is_cached(inode, (int)ret);
98165294c1fSJeff Layton 	return ret;
98265294c1fSJeff Layton }
98365294c1fSJeff Layton 
984fb70bf12SChuck Lever static __be32
985be023006SChuck Lever nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
9860b3a551fSJeff Layton 		     unsigned int may_flags, struct file *file,
9870b3a551fSJeff Layton 		     struct nfsd_file **pnf, bool want_gc)
98865294c1fSJeff Layton {
989c4c649abSChuck Lever 	unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
990c4c649abSChuck Lever 	struct net *net = SVC_NET(rqstp);
991c4c649abSChuck Lever 	struct nfsd_file *new, *nf;
992c4c649abSChuck Lever 	const struct cred *cred;
993243a5263SJeff Layton 	bool open_retry = true;
994c4c649abSChuck Lever 	struct inode *inode;
995ce502f81SChuck Lever 	__be32 status;
996243a5263SJeff Layton 	int ret;
99765294c1fSJeff Layton 
99865294c1fSJeff Layton 	status = fh_verify(rqstp, fhp, S_IFREG,
99965294c1fSJeff Layton 				may_flags|NFSD_MAY_OWNER_OVERRIDE);
100065294c1fSJeff Layton 	if (status != nfs_ok)
100165294c1fSJeff Layton 		return status;
1002c4c649abSChuck Lever 	inode = d_inode(fhp->fh_dentry);
1003c4c649abSChuck Lever 	cred = get_current_cred();
100465294c1fSJeff Layton 
100565294c1fSJeff Layton retry:
1006243a5263SJeff Layton 	rcu_read_lock();
1007c4c649abSChuck Lever 	nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
1008243a5263SJeff Layton 	rcu_read_unlock();
1009ac3a2585SJeff Layton 
1010ac3a2585SJeff Layton 	if (nf) {
1011b680cb9bSJeff Layton 		/*
1012b680cb9bSJeff Layton 		 * If the nf is on the LRU then it holds an extra reference
1013b680cb9bSJeff Layton 		 * that must be put if it's removed. It had better not be
1014b680cb9bSJeff Layton 		 * the last one however, since we should hold another.
1015b680cb9bSJeff Layton 		 */
1016ac3a2585SJeff Layton 		if (nfsd_file_lru_remove(nf))
1017ac3a2585SJeff Layton 			WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref));
101865294c1fSJeff Layton 		goto wait_for_construction;
1019ac3a2585SJeff Layton 	}
102065294c1fSJeff Layton 
1021c4c649abSChuck Lever 	new = nfsd_file_alloc(net, inode, need, want_gc);
1022c4c649abSChuck Lever 	if (!new) {
102354f7df70SChuck Lever 		status = nfserr_jukebox;
1024c6593366SJeff Layton 		goto out;
102565294c1fSJeff Layton 	}
102665294c1fSJeff Layton 
1027c4c649abSChuck Lever 	rcu_read_lock();
1028c4c649abSChuck Lever 	spin_lock(&inode->i_lock);
1029c4c649abSChuck Lever 	nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
1030c4c649abSChuck Lever 	if (unlikely(nf)) {
1031c4c649abSChuck Lever 		spin_unlock(&inode->i_lock);
1032c4c649abSChuck Lever 		rcu_read_unlock();
1033c4c649abSChuck Lever 		nfsd_file_slab_free(&new->nf_rcu);
1034c4c649abSChuck Lever 		goto wait_for_construction;
1035c4c649abSChuck Lever 	}
1036c4c649abSChuck Lever 	nf = new;
1037c4c649abSChuck Lever 	ret = rhltable_insert(&nfsd_file_rhltable, &nf->nf_rlist,
1038ce502f81SChuck Lever 			      nfsd_file_rhash_params);
1039c4c649abSChuck Lever 	spin_unlock(&inode->i_lock);
1040c4c649abSChuck Lever 	rcu_read_unlock();
1041243a5263SJeff Layton 	if (likely(ret == 0))
104265294c1fSJeff Layton 		goto open_file;
1043243a5263SJeff Layton 
1044243a5263SJeff Layton 	if (ret == -EEXIST)
1045243a5263SJeff Layton 		goto retry;
1046c4c649abSChuck Lever 	trace_nfsd_file_insert_err(rqstp, inode, may_flags, ret);
1047243a5263SJeff Layton 	status = nfserr_jukebox;
1048c6593366SJeff Layton 	goto construction_err;
104965294c1fSJeff Layton 
105065294c1fSJeff Layton wait_for_construction:
105165294c1fSJeff Layton 	wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);
105265294c1fSJeff Layton 
105365294c1fSJeff Layton 	/* Did construction of this file fail? */
105465294c1fSJeff Layton 	if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
1055c4c649abSChuck Lever 		trace_nfsd_file_cons_err(rqstp, inode, may_flags, nf);
1056243a5263SJeff Layton 		if (!open_retry) {
105728c7d86bSTrond Myklebust 			status = nfserr_jukebox;
1058c6593366SJeff Layton 			goto construction_err;
105928c7d86bSTrond Myklebust 		}
1060243a5263SJeff Layton 		open_retry = false;
106165294c1fSJeff Layton 		goto retry;
106265294c1fSJeff Layton 	}
106365294c1fSJeff Layton 	this_cpu_inc(nfsd_file_cache_hits);
106465294c1fSJeff Layton 
106523ba98deSJeff Layton 	status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
1066c6593366SJeff Layton 	if (status != nfs_ok) {
1067c6593366SJeff Layton 		nfsd_file_put(nf);
1068c6593366SJeff Layton 		nf = NULL;
1069c6593366SJeff Layton 	}
1070c6593366SJeff Layton 
107165294c1fSJeff Layton out:
107265294c1fSJeff Layton 	if (status == nfs_ok) {
107329d4bdbbSChuck Lever 		this_cpu_inc(nfsd_file_acquisitions);
10744c475eeeSJeff Layton 		nfsd_file_check_write_error(nf);
107565294c1fSJeff Layton 		*pnf = nf;
107665294c1fSJeff Layton 	}
1077c4c649abSChuck Lever 	put_cred(cred);
1078c4c649abSChuck Lever 	trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status);
107965294c1fSJeff Layton 	return status;
108065294c1fSJeff Layton 
108165294c1fSJeff Layton open_file:
1082b40a2839SChuck Lever 	trace_nfsd_file_alloc(nf);
1083c4c649abSChuck Lever 	nf->nf_mark = nfsd_file_mark_find_or_create(nf, inode);
1084fb70bf12SChuck Lever 	if (nf->nf_mark) {
10850b3a551fSJeff Layton 		if (file) {
10860b3a551fSJeff Layton 			get_file(file);
10870b3a551fSJeff Layton 			nf->nf_file = file;
10880b3a551fSJeff Layton 			status = nfs_ok;
10890b3a551fSJeff Layton 			trace_nfsd_file_opened(nf, status);
10900b3a551fSJeff Layton 		} else {
1091f4d84c52SChuck Lever 			status = nfsd_open_verified(rqstp, fhp, may_flags,
1092f4d84c52SChuck Lever 						    &nf->nf_file);
10930122e882SChuck Lever 			trace_nfsd_file_open(nf, status);
10940b3a551fSJeff Layton 		}
1095fb70bf12SChuck Lever 	} else
109665294c1fSJeff Layton 		status = nfserr_jukebox;
109765294c1fSJeff Layton 	/*
109865294c1fSJeff Layton 	 * If construction failed, or we raced with a call to unlink()
109965294c1fSJeff Layton 	 * then unhash.
110065294c1fSJeff Layton 	 */
1101c4c649abSChuck Lever 	if (status != nfs_ok || inode->i_nlink == 0)
1102ac3a2585SJeff Layton 		status = nfserr_jukebox;
1103ac3a2585SJeff Layton 	if (status != nfs_ok)
1104ac3a2585SJeff Layton 		nfsd_file_unhash(nf);
1105b8bea9f6SJeff Layton 	clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags);
1106c6593366SJeff Layton 	if (status == nfs_ok)
1107c6593366SJeff Layton 		goto out;
1108c6593366SJeff Layton 
1109c6593366SJeff Layton construction_err:
1110c6593366SJeff Layton 	if (refcount_dec_and_test(&nf->nf_ref))
1111c6593366SJeff Layton 		nfsd_file_free(nf);
1112c6593366SJeff Layton 	nf = NULL;
111365294c1fSJeff Layton 	goto out;
111465294c1fSJeff Layton }
111565294c1fSJeff Layton 
1116fb70bf12SChuck Lever /**
11174d1ea845SChuck Lever  * nfsd_file_acquire_gc - Get a struct nfsd_file with an open file
11184d1ea845SChuck Lever  * @rqstp: the RPC transaction being executed
11194d1ea845SChuck Lever  * @fhp: the NFS filehandle of the file to be opened
11204d1ea845SChuck Lever  * @may_flags: NFSD_MAY_ settings for the file
11214d1ea845SChuck Lever  * @pnf: OUT: new or found "struct nfsd_file" object
11224d1ea845SChuck Lever  *
11234d1ea845SChuck Lever  * The nfsd_file object returned by this API is reference-counted
11244d1ea845SChuck Lever  * and garbage-collected. The object is retained for a few
11254d1ea845SChuck Lever  * seconds after the final nfsd_file_put() in case the caller
11264d1ea845SChuck Lever  * wants to re-use it.
11274d1ea845SChuck Lever  *
1128c4c649abSChuck Lever  * Return values:
1129c4c649abSChuck Lever  *   %nfs_ok - @pnf points to an nfsd_file with its reference
1130c4c649abSChuck Lever  *   count boosted.
1131c4c649abSChuck Lever  *
1132c4c649abSChuck Lever  * On error, an nfsstat value in network byte order is returned.
11334d1ea845SChuck Lever  */
11344d1ea845SChuck Lever __be32
11354d1ea845SChuck Lever nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
11364d1ea845SChuck Lever 		     unsigned int may_flags, struct nfsd_file **pnf)
11374d1ea845SChuck Lever {
11380b3a551fSJeff Layton 	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true);
11394d1ea845SChuck Lever }
11404d1ea845SChuck Lever 
11414d1ea845SChuck Lever /**
1142fb70bf12SChuck Lever  * nfsd_file_acquire - Get a struct nfsd_file with an open file
1143fb70bf12SChuck Lever  * @rqstp: the RPC transaction being executed
1144fb70bf12SChuck Lever  * @fhp: the NFS filehandle of the file to be opened
1145fb70bf12SChuck Lever  * @may_flags: NFSD_MAY_ settings for the file
1146fb70bf12SChuck Lever  * @pnf: OUT: new or found "struct nfsd_file" object
1147fb70bf12SChuck Lever  *
11484d1ea845SChuck Lever  * The nfsd_file_object returned by this API is reference-counted
11494d1ea845SChuck Lever  * but not garbage-collected. The object is unhashed after the
11504d1ea845SChuck Lever  * final nfsd_file_put().
11514d1ea845SChuck Lever  *
1152c4c649abSChuck Lever  * Return values:
1153c4c649abSChuck Lever  *   %nfs_ok - @pnf points to an nfsd_file with its reference
1154c4c649abSChuck Lever  *   count boosted.
1155c4c649abSChuck Lever  *
1156c4c649abSChuck Lever  * On error, an nfsstat value in network byte order is returned.
1157fb70bf12SChuck Lever  */
1158fb70bf12SChuck Lever __be32
1159fb70bf12SChuck Lever nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
1160fb70bf12SChuck Lever 		  unsigned int may_flags, struct nfsd_file **pnf)
1161fb70bf12SChuck Lever {
11620b3a551fSJeff Layton 	return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false);
1163fb70bf12SChuck Lever }
1164fb70bf12SChuck Lever 
1165fb70bf12SChuck Lever /**
11660b3a551fSJeff Layton  * nfsd_file_acquire_opened - Get a struct nfsd_file using existing open file
1167fb70bf12SChuck Lever  * @rqstp: the RPC transaction being executed
1168fb70bf12SChuck Lever  * @fhp: the NFS filehandle of the file just created
1169fb70bf12SChuck Lever  * @may_flags: NFSD_MAY_ settings for the file
11700b3a551fSJeff Layton  * @file: cached, already-open file (may be NULL)
1171fb70bf12SChuck Lever  * @pnf: OUT: new or found "struct nfsd_file" object
1172fb70bf12SChuck Lever  *
11730b3a551fSJeff Layton  * Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist,
11740b3a551fSJeff Layton  * and @file is non-NULL, use it to instantiate a new nfsd_file instead of
11750b3a551fSJeff Layton  * opening a new one.
11764d1ea845SChuck Lever  *
1177c4c649abSChuck Lever  * Return values:
1178c4c649abSChuck Lever  *   %nfs_ok - @pnf points to an nfsd_file with its reference
1179c4c649abSChuck Lever  *   count boosted.
1180c4c649abSChuck Lever  *
1181c4c649abSChuck Lever  * On error, an nfsstat value in network byte order is returned.
1182fb70bf12SChuck Lever  */
1183fb70bf12SChuck Lever __be32
11840b3a551fSJeff Layton nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
11850b3a551fSJeff Layton 			 unsigned int may_flags, struct file *file,
11860b3a551fSJeff Layton 			 struct nfsd_file **pnf)
1187fb70bf12SChuck Lever {
11880b3a551fSJeff Layton 	return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false);
1189fb70bf12SChuck Lever }
1190fb70bf12SChuck Lever 
119165294c1fSJeff Layton /*
119265294c1fSJeff Layton  * Note that fields may be added, removed or reordered in the future. Programs
119365294c1fSJeff Layton  * scraping this file for info should test the labels to ensure they're
119465294c1fSJeff Layton  * getting the correct field.
119565294c1fSJeff Layton  */
11961342f9ddSChenXiaoSong int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
119765294c1fSJeff Layton {
11981f696e23SJeff Layton 	unsigned long releases = 0, evictions = 0;
1199df2aff52SChuck Lever 	unsigned long hits = 0, acquisitions = 0;
1200ce502f81SChuck Lever 	unsigned int i, count = 0, buckets = 0;
1201904940e9SChuck Lever 	unsigned long lru = 0, total_age = 0;
120265294c1fSJeff Layton 
1203ce502f81SChuck Lever 	/* Serialize with server shutdown */
120465294c1fSJeff Layton 	mutex_lock(&nfsd_mutex);
1205c7b824c3SChuck Lever 	if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) {
1206ce502f81SChuck Lever 		struct bucket_table *tbl;
1207ce502f81SChuck Lever 		struct rhashtable *ht;
1208ce502f81SChuck Lever 
12090fd244c1SChuck Lever 		lru = list_lru_count(&nfsd_file_lru);
1210ce502f81SChuck Lever 
1211ce502f81SChuck Lever 		rcu_read_lock();
1212c4c649abSChuck Lever 		ht = &nfsd_file_rhltable.ht;
1213ce502f81SChuck Lever 		count = atomic_read(&ht->nelems);
1214ce502f81SChuck Lever 		tbl = rht_dereference_rcu(ht->tbl, ht);
1215ce502f81SChuck Lever 		buckets = tbl->size;
1216ce502f81SChuck Lever 		rcu_read_unlock();
121765294c1fSJeff Layton 	}
121865294c1fSJeff Layton 	mutex_unlock(&nfsd_mutex);
121965294c1fSJeff Layton 
122029d4bdbbSChuck Lever 	for_each_possible_cpu(i) {
122165294c1fSJeff Layton 		hits += per_cpu(nfsd_file_cache_hits, i);
122229d4bdbbSChuck Lever 		acquisitions += per_cpu(nfsd_file_acquisitions, i);
1223d6329327SChuck Lever 		releases += per_cpu(nfsd_file_releases, i);
1224904940e9SChuck Lever 		total_age += per_cpu(nfsd_file_total_age, i);
122594660cc1SChuck Lever 		evictions += per_cpu(nfsd_file_evictions, i);
122629d4bdbbSChuck Lever 	}
122765294c1fSJeff Layton 
1228c4c649abSChuck Lever 	seq_printf(m, "total inodes:  %u\n", count);
1229ce502f81SChuck Lever 	seq_printf(m, "hash buckets:  %u\n", buckets);
12300fd244c1SChuck Lever 	seq_printf(m, "lru entries:   %lu\n", lru);
123165294c1fSJeff Layton 	seq_printf(m, "cache hits:    %lu\n", hits);
123229d4bdbbSChuck Lever 	seq_printf(m, "acquisitions:  %lu\n", acquisitions);
1233d6329327SChuck Lever 	seq_printf(m, "releases:      %lu\n", releases);
123494660cc1SChuck Lever 	seq_printf(m, "evictions:     %lu\n", evictions);
1235904940e9SChuck Lever 	if (releases)
1236904940e9SChuck Lever 		seq_printf(m, "mean age (ms): %ld\n", total_age / releases);
1237904940e9SChuck Lever 	else
1238904940e9SChuck Lever 		seq_printf(m, "mean age (ms): -\n");
123965294c1fSJeff Layton 	return 0;
124065294c1fSJeff Layton }
1241