xref: /openbmc/linux/fs/nfs/nfs42xattr.c (revision 95ad37f90c338e3fd4abf61cecfe02b6f3e080f0)
1*95ad37f9SFrank van der Linden // SPDX-License-Identifier: GPL-2.0
2*95ad37f9SFrank van der Linden 
3*95ad37f9SFrank van der Linden /*
4*95ad37f9SFrank van der Linden  * Copyright 2019, 2020 Amazon.com, Inc. or its affiliates. All rights reserved.
5*95ad37f9SFrank van der Linden  *
6*95ad37f9SFrank van der Linden  * User extended attribute client side cache functions.
7*95ad37f9SFrank van der Linden  *
8*95ad37f9SFrank van der Linden  * Author: Frank van der Linden <fllinden@amazon.com>
9*95ad37f9SFrank van der Linden  */
10*95ad37f9SFrank van der Linden #include <linux/errno.h>
11*95ad37f9SFrank van der Linden #include <linux/nfs_fs.h>
12*95ad37f9SFrank van der Linden #include <linux/hashtable.h>
13*95ad37f9SFrank van der Linden #include <linux/refcount.h>
14*95ad37f9SFrank van der Linden #include <uapi/linux/xattr.h>
15*95ad37f9SFrank van der Linden 
16*95ad37f9SFrank van der Linden #include "nfs4_fs.h"
17*95ad37f9SFrank van der Linden #include "internal.h"
18*95ad37f9SFrank van der Linden 
19*95ad37f9SFrank van der Linden /*
20*95ad37f9SFrank van der Linden  * User extended attributes client side caching is implemented by having
21*95ad37f9SFrank van der Linden  * a cache structure attached to NFS inodes. This structure is allocated
22*95ad37f9SFrank van der Linden  * when needed, and freed when the cache is zapped.
23*95ad37f9SFrank van der Linden  *
24*95ad37f9SFrank van der Linden  * The cache structure contains as hash table of entries, and a pointer
25*95ad37f9SFrank van der Linden  * to a special-cased entry for the listxattr cache.
26*95ad37f9SFrank van der Linden  *
27*95ad37f9SFrank van der Linden  * Accessing and allocating / freeing the caches is done via reference
28*95ad37f9SFrank van der Linden  * counting. The cache entries use a similar refcounting scheme.
29*95ad37f9SFrank van der Linden  *
30*95ad37f9SFrank van der Linden  * This makes freeing a cache, both from the shrinker and from the
31*95ad37f9SFrank van der Linden  * zap cache path, easy. It also means that, in current use cases,
32*95ad37f9SFrank van der Linden  * the large majority of inodes will not waste any memory, as they
33*95ad37f9SFrank van der Linden  * will never have any user extended attributes assigned to them.
34*95ad37f9SFrank van der Linden  *
35*95ad37f9SFrank van der Linden  * Attribute entries are hashed in to a simple hash table. They are
36*95ad37f9SFrank van der Linden  * also part of an LRU.
37*95ad37f9SFrank van der Linden  *
38*95ad37f9SFrank van der Linden  * There are three shrinkers.
39*95ad37f9SFrank van der Linden  *
40*95ad37f9SFrank van der Linden  * Two shrinkers deal with the cache entries themselves: one for
41*95ad37f9SFrank van der Linden  * large entries (> PAGE_SIZE), and one for smaller entries. The
42*95ad37f9SFrank van der Linden  * shrinker for the larger entries works more aggressively than
43*95ad37f9SFrank van der Linden  * those for the smaller entries.
44*95ad37f9SFrank van der Linden  *
45*95ad37f9SFrank van der Linden  * The other shrinker frees the cache structures themselves.
46*95ad37f9SFrank van der Linden  */
47*95ad37f9SFrank van der Linden 
48*95ad37f9SFrank van der Linden /*
49*95ad37f9SFrank van der Linden  * 64 buckets is a good default. There is likely no reasonable
50*95ad37f9SFrank van der Linden  * workload that uses more than even 64 user extended attributes.
51*95ad37f9SFrank van der Linden  * You can certainly add a lot more - but you get what you ask for
52*95ad37f9SFrank van der Linden  * in those circumstances.
53*95ad37f9SFrank van der Linden  */
54*95ad37f9SFrank van der Linden #define NFS4_XATTR_HASH_SIZE	64
55*95ad37f9SFrank van der Linden 
56*95ad37f9SFrank van der Linden #define NFSDBG_FACILITY	NFSDBG_XATTRCACHE
57*95ad37f9SFrank van der Linden 
58*95ad37f9SFrank van der Linden struct nfs4_xattr_cache;
59*95ad37f9SFrank van der Linden struct nfs4_xattr_entry;
60*95ad37f9SFrank van der Linden 
61*95ad37f9SFrank van der Linden struct nfs4_xattr_bucket {
62*95ad37f9SFrank van der Linden 	spinlock_t lock;
63*95ad37f9SFrank van der Linden 	struct hlist_head hlist;
64*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
65*95ad37f9SFrank van der Linden 	bool draining;
66*95ad37f9SFrank van der Linden };
67*95ad37f9SFrank van der Linden 
68*95ad37f9SFrank van der Linden struct nfs4_xattr_cache {
69*95ad37f9SFrank van der Linden 	struct kref ref;
70*95ad37f9SFrank van der Linden 	spinlock_t hash_lock;	/* protects hashtable and lru */
71*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket buckets[NFS4_XATTR_HASH_SIZE];
72*95ad37f9SFrank van der Linden 	struct list_head lru;
73*95ad37f9SFrank van der Linden 	struct list_head dispose;
74*95ad37f9SFrank van der Linden 	atomic_long_t nent;
75*95ad37f9SFrank van der Linden 	spinlock_t listxattr_lock;
76*95ad37f9SFrank van der Linden 	struct inode *inode;
77*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *listxattr;
78*95ad37f9SFrank van der Linden 	struct work_struct work;
79*95ad37f9SFrank van der Linden };
80*95ad37f9SFrank van der Linden 
81*95ad37f9SFrank van der Linden struct nfs4_xattr_entry {
82*95ad37f9SFrank van der Linden 	struct kref ref;
83*95ad37f9SFrank van der Linden 	struct hlist_node hnode;
84*95ad37f9SFrank van der Linden 	struct list_head lru;
85*95ad37f9SFrank van der Linden 	struct list_head dispose;
86*95ad37f9SFrank van der Linden 	char *xattr_name;
87*95ad37f9SFrank van der Linden 	void *xattr_value;
88*95ad37f9SFrank van der Linden 	size_t xattr_size;
89*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
90*95ad37f9SFrank van der Linden 	uint32_t flags;
91*95ad37f9SFrank van der Linden };
92*95ad37f9SFrank van der Linden 
93*95ad37f9SFrank van der Linden #define	NFS4_XATTR_ENTRY_EXTVAL	0x0001
94*95ad37f9SFrank van der Linden 
95*95ad37f9SFrank van der Linden /*
96*95ad37f9SFrank van der Linden  * LRU list of NFS inodes that have xattr caches.
97*95ad37f9SFrank van der Linden  */
98*95ad37f9SFrank van der Linden static struct list_lru nfs4_xattr_cache_lru;
99*95ad37f9SFrank van der Linden static struct list_lru nfs4_xattr_entry_lru;
100*95ad37f9SFrank van der Linden static struct list_lru nfs4_xattr_large_entry_lru;
101*95ad37f9SFrank van der Linden 
102*95ad37f9SFrank van der Linden static struct kmem_cache *nfs4_xattr_cache_cachep;
103*95ad37f9SFrank van der Linden 
104*95ad37f9SFrank van der Linden static struct workqueue_struct *nfs4_xattr_cache_wq;
105*95ad37f9SFrank van der Linden 
106*95ad37f9SFrank van der Linden /*
107*95ad37f9SFrank van der Linden  * Hashing helper functions.
108*95ad37f9SFrank van der Linden  */
109*95ad37f9SFrank van der Linden static void
110*95ad37f9SFrank van der Linden nfs4_xattr_hash_init(struct nfs4_xattr_cache *cache)
111*95ad37f9SFrank van der Linden {
112*95ad37f9SFrank van der Linden 	unsigned int i;
113*95ad37f9SFrank van der Linden 
114*95ad37f9SFrank van der Linden 	for (i = 0; i < NFS4_XATTR_HASH_SIZE; i++) {
115*95ad37f9SFrank van der Linden 		INIT_HLIST_HEAD(&cache->buckets[i].hlist);
116*95ad37f9SFrank van der Linden 		spin_lock_init(&cache->buckets[i].lock);
117*95ad37f9SFrank van der Linden 		cache->buckets[i].cache = cache;
118*95ad37f9SFrank van der Linden 		cache->buckets[i].draining = false;
119*95ad37f9SFrank van der Linden 	}
120*95ad37f9SFrank van der Linden }
121*95ad37f9SFrank van der Linden 
122*95ad37f9SFrank van der Linden /*
123*95ad37f9SFrank van der Linden  * Locking order:
124*95ad37f9SFrank van der Linden  * 1. inode i_lock or bucket lock
125*95ad37f9SFrank van der Linden  * 2. list_lru lock (taken by list_lru_* functions)
126*95ad37f9SFrank van der Linden  */
127*95ad37f9SFrank van der Linden 
128*95ad37f9SFrank van der Linden /*
129*95ad37f9SFrank van der Linden  * Wrapper functions to add a cache entry to the right LRU.
130*95ad37f9SFrank van der Linden  */
131*95ad37f9SFrank van der Linden static bool
132*95ad37f9SFrank van der Linden nfs4_xattr_entry_lru_add(struct nfs4_xattr_entry *entry)
133*95ad37f9SFrank van der Linden {
134*95ad37f9SFrank van der Linden 	struct list_lru *lru;
135*95ad37f9SFrank van der Linden 
136*95ad37f9SFrank van der Linden 	lru = (entry->flags & NFS4_XATTR_ENTRY_EXTVAL) ?
137*95ad37f9SFrank van der Linden 	    &nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
138*95ad37f9SFrank van der Linden 
139*95ad37f9SFrank van der Linden 	return list_lru_add(lru, &entry->lru);
140*95ad37f9SFrank van der Linden }
141*95ad37f9SFrank van der Linden 
142*95ad37f9SFrank van der Linden static bool
143*95ad37f9SFrank van der Linden nfs4_xattr_entry_lru_del(struct nfs4_xattr_entry *entry)
144*95ad37f9SFrank van der Linden {
145*95ad37f9SFrank van der Linden 	struct list_lru *lru;
146*95ad37f9SFrank van der Linden 
147*95ad37f9SFrank van der Linden 	lru = (entry->flags & NFS4_XATTR_ENTRY_EXTVAL) ?
148*95ad37f9SFrank van der Linden 	    &nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
149*95ad37f9SFrank van der Linden 
150*95ad37f9SFrank van der Linden 	return list_lru_del(lru, &entry->lru);
151*95ad37f9SFrank van der Linden }
152*95ad37f9SFrank van der Linden 
153*95ad37f9SFrank van der Linden /*
154*95ad37f9SFrank van der Linden  * This function allocates cache entries. They are the normal
155*95ad37f9SFrank van der Linden  * extended attribute name/value pairs, but may also be a listxattr
156*95ad37f9SFrank van der Linden  * cache. Those allocations use the same entry so that they can be
157*95ad37f9SFrank van der Linden  * treated as one by the memory shrinker.
158*95ad37f9SFrank van der Linden  *
159*95ad37f9SFrank van der Linden  * xattr cache entries are allocated together with names. If the
160*95ad37f9SFrank van der Linden  * value fits in to one page with the entry structure and the name,
161*95ad37f9SFrank van der Linden  * it will also be part of the same allocation (kmalloc). This is
162*95ad37f9SFrank van der Linden  * expected to be the vast majority of cases. Larger allocations
163*95ad37f9SFrank van der Linden  * have a value pointer that is allocated separately by kvmalloc.
164*95ad37f9SFrank van der Linden  *
165*95ad37f9SFrank van der Linden  * Parameters:
166*95ad37f9SFrank van der Linden  *
167*95ad37f9SFrank van der Linden  * @name:  Name of the extended attribute. NULL for listxattr cache
168*95ad37f9SFrank van der Linden  *         entry.
169*95ad37f9SFrank van der Linden  * @value: Value of attribute, or listxattr cache. NULL if the
170*95ad37f9SFrank van der Linden  *         value is to be copied from pages instead.
171*95ad37f9SFrank van der Linden  * @pages: Pages to copy the value from, if not NULL. Passed in to
172*95ad37f9SFrank van der Linden  *	   make it easier to copy the value after an RPC, even if
173*95ad37f9SFrank van der Linden  *	   the value will not be passed up to application (e.g.
174*95ad37f9SFrank van der Linden  *	   for a 'query' getxattr with NULL buffer).
175*95ad37f9SFrank van der Linden  * @len:   Length of the value. Can be 0 for zero-length attribues.
176*95ad37f9SFrank van der Linden  *         @value and @pages will be NULL if @len is 0.
177*95ad37f9SFrank van der Linden  */
178*95ad37f9SFrank van der Linden static struct nfs4_xattr_entry *
179*95ad37f9SFrank van der Linden nfs4_xattr_alloc_entry(const char *name, const void *value,
180*95ad37f9SFrank van der Linden 		       struct page **pages, size_t len)
181*95ad37f9SFrank van der Linden {
182*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
183*95ad37f9SFrank van der Linden 	void *valp;
184*95ad37f9SFrank van der Linden 	char *namep;
185*95ad37f9SFrank van der Linden 	size_t alloclen, slen;
186*95ad37f9SFrank van der Linden 	char *buf;
187*95ad37f9SFrank van der Linden 	uint32_t flags;
188*95ad37f9SFrank van der Linden 
189*95ad37f9SFrank van der Linden 	BUILD_BUG_ON(sizeof(struct nfs4_xattr_entry) +
190*95ad37f9SFrank van der Linden 	    XATTR_NAME_MAX + 1 > PAGE_SIZE);
191*95ad37f9SFrank van der Linden 
192*95ad37f9SFrank van der Linden 	alloclen = sizeof(struct nfs4_xattr_entry);
193*95ad37f9SFrank van der Linden 	if (name != NULL) {
194*95ad37f9SFrank van der Linden 		slen = strlen(name) + 1;
195*95ad37f9SFrank van der Linden 		alloclen += slen;
196*95ad37f9SFrank van der Linden 	} else
197*95ad37f9SFrank van der Linden 		slen = 0;
198*95ad37f9SFrank van der Linden 
199*95ad37f9SFrank van der Linden 	if (alloclen + len <= PAGE_SIZE) {
200*95ad37f9SFrank van der Linden 		alloclen += len;
201*95ad37f9SFrank van der Linden 		flags = 0;
202*95ad37f9SFrank van der Linden 	} else {
203*95ad37f9SFrank van der Linden 		flags = NFS4_XATTR_ENTRY_EXTVAL;
204*95ad37f9SFrank van der Linden 	}
205*95ad37f9SFrank van der Linden 
206*95ad37f9SFrank van der Linden 	buf = kmalloc(alloclen, GFP_KERNEL_ACCOUNT | GFP_NOFS);
207*95ad37f9SFrank van der Linden 	if (buf == NULL)
208*95ad37f9SFrank van der Linden 		return NULL;
209*95ad37f9SFrank van der Linden 	entry = (struct nfs4_xattr_entry *)buf;
210*95ad37f9SFrank van der Linden 
211*95ad37f9SFrank van der Linden 	if (name != NULL) {
212*95ad37f9SFrank van der Linden 		namep = buf + sizeof(struct nfs4_xattr_entry);
213*95ad37f9SFrank van der Linden 		memcpy(namep, name, slen);
214*95ad37f9SFrank van der Linden 	} else {
215*95ad37f9SFrank van der Linden 		namep = NULL;
216*95ad37f9SFrank van der Linden 	}
217*95ad37f9SFrank van der Linden 
218*95ad37f9SFrank van der Linden 
219*95ad37f9SFrank van der Linden 	if (flags & NFS4_XATTR_ENTRY_EXTVAL) {
220*95ad37f9SFrank van der Linden 		valp = kvmalloc(len, GFP_KERNEL_ACCOUNT | GFP_NOFS);
221*95ad37f9SFrank van der Linden 		if (valp == NULL) {
222*95ad37f9SFrank van der Linden 			kfree(buf);
223*95ad37f9SFrank van der Linden 			return NULL;
224*95ad37f9SFrank van der Linden 		}
225*95ad37f9SFrank van der Linden 	} else if (len != 0) {
226*95ad37f9SFrank van der Linden 		valp = buf + sizeof(struct nfs4_xattr_entry) + slen;
227*95ad37f9SFrank van der Linden 	} else
228*95ad37f9SFrank van der Linden 		valp = NULL;
229*95ad37f9SFrank van der Linden 
230*95ad37f9SFrank van der Linden 	if (valp != NULL) {
231*95ad37f9SFrank van der Linden 		if (value != NULL)
232*95ad37f9SFrank van der Linden 			memcpy(valp, value, len);
233*95ad37f9SFrank van der Linden 		else
234*95ad37f9SFrank van der Linden 			_copy_from_pages(valp, pages, 0, len);
235*95ad37f9SFrank van der Linden 	}
236*95ad37f9SFrank van der Linden 
237*95ad37f9SFrank van der Linden 	entry->flags = flags;
238*95ad37f9SFrank van der Linden 	entry->xattr_value = valp;
239*95ad37f9SFrank van der Linden 	kref_init(&entry->ref);
240*95ad37f9SFrank van der Linden 	entry->xattr_name = namep;
241*95ad37f9SFrank van der Linden 	entry->xattr_size = len;
242*95ad37f9SFrank van der Linden 	entry->bucket = NULL;
243*95ad37f9SFrank van der Linden 	INIT_LIST_HEAD(&entry->lru);
244*95ad37f9SFrank van der Linden 	INIT_LIST_HEAD(&entry->dispose);
245*95ad37f9SFrank van der Linden 	INIT_HLIST_NODE(&entry->hnode);
246*95ad37f9SFrank van der Linden 
247*95ad37f9SFrank van der Linden 	return entry;
248*95ad37f9SFrank van der Linden }
249*95ad37f9SFrank van der Linden 
250*95ad37f9SFrank van der Linden static void
251*95ad37f9SFrank van der Linden nfs4_xattr_free_entry(struct nfs4_xattr_entry *entry)
252*95ad37f9SFrank van der Linden {
253*95ad37f9SFrank van der Linden 	if (entry->flags & NFS4_XATTR_ENTRY_EXTVAL)
254*95ad37f9SFrank van der Linden 		kvfree(entry->xattr_value);
255*95ad37f9SFrank van der Linden 	kfree(entry);
256*95ad37f9SFrank van der Linden }
257*95ad37f9SFrank van der Linden 
258*95ad37f9SFrank van der Linden static void
259*95ad37f9SFrank van der Linden nfs4_xattr_free_entry_cb(struct kref *kref)
260*95ad37f9SFrank van der Linden {
261*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
262*95ad37f9SFrank van der Linden 
263*95ad37f9SFrank van der Linden 	entry = container_of(kref, struct nfs4_xattr_entry, ref);
264*95ad37f9SFrank van der Linden 
265*95ad37f9SFrank van der Linden 	if (WARN_ON(!list_empty(&entry->lru)))
266*95ad37f9SFrank van der Linden 		return;
267*95ad37f9SFrank van der Linden 
268*95ad37f9SFrank van der Linden 	nfs4_xattr_free_entry(entry);
269*95ad37f9SFrank van der Linden }
270*95ad37f9SFrank van der Linden 
271*95ad37f9SFrank van der Linden static void
272*95ad37f9SFrank van der Linden nfs4_xattr_free_cache_cb(struct kref *kref)
273*95ad37f9SFrank van der Linden {
274*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
275*95ad37f9SFrank van der Linden 	int i;
276*95ad37f9SFrank van der Linden 
277*95ad37f9SFrank van der Linden 	cache = container_of(kref, struct nfs4_xattr_cache, ref);
278*95ad37f9SFrank van der Linden 
279*95ad37f9SFrank van der Linden 	for (i = 0; i < NFS4_XATTR_HASH_SIZE; i++) {
280*95ad37f9SFrank van der Linden 		if (WARN_ON(!hlist_empty(&cache->buckets[i].hlist)))
281*95ad37f9SFrank van der Linden 			return;
282*95ad37f9SFrank van der Linden 		cache->buckets[i].draining = false;
283*95ad37f9SFrank van der Linden 	}
284*95ad37f9SFrank van der Linden 
285*95ad37f9SFrank van der Linden 	cache->listxattr = NULL;
286*95ad37f9SFrank van der Linden 
287*95ad37f9SFrank van der Linden 	kmem_cache_free(nfs4_xattr_cache_cachep, cache);
288*95ad37f9SFrank van der Linden 
289*95ad37f9SFrank van der Linden }
290*95ad37f9SFrank van der Linden 
291*95ad37f9SFrank van der Linden static struct nfs4_xattr_cache *
292*95ad37f9SFrank van der Linden nfs4_xattr_alloc_cache(void)
293*95ad37f9SFrank van der Linden {
294*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
295*95ad37f9SFrank van der Linden 
296*95ad37f9SFrank van der Linden 	cache = kmem_cache_alloc(nfs4_xattr_cache_cachep,
297*95ad37f9SFrank van der Linden 	    GFP_KERNEL_ACCOUNT | GFP_NOFS);
298*95ad37f9SFrank van der Linden 	if (cache == NULL)
299*95ad37f9SFrank van der Linden 		return NULL;
300*95ad37f9SFrank van der Linden 
301*95ad37f9SFrank van der Linden 	kref_init(&cache->ref);
302*95ad37f9SFrank van der Linden 	atomic_long_set(&cache->nent, 0);
303*95ad37f9SFrank van der Linden 
304*95ad37f9SFrank van der Linden 	return cache;
305*95ad37f9SFrank van der Linden }
306*95ad37f9SFrank van der Linden 
307*95ad37f9SFrank van der Linden /*
308*95ad37f9SFrank van der Linden  * Set the listxattr cache, which is a special-cased cache entry.
309*95ad37f9SFrank van der Linden  * The special value ERR_PTR(-ESTALE) is used to indicate that
310*95ad37f9SFrank van der Linden  * the cache is being drained - this prevents a new listxattr
311*95ad37f9SFrank van der Linden  * cache from being added to what is now a stale cache.
312*95ad37f9SFrank van der Linden  */
313*95ad37f9SFrank van der Linden static int
314*95ad37f9SFrank van der Linden nfs4_xattr_set_listcache(struct nfs4_xattr_cache *cache,
315*95ad37f9SFrank van der Linden 			 struct nfs4_xattr_entry *new)
316*95ad37f9SFrank van der Linden {
317*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *old;
318*95ad37f9SFrank van der Linden 	int ret = 1;
319*95ad37f9SFrank van der Linden 
320*95ad37f9SFrank van der Linden 	spin_lock(&cache->listxattr_lock);
321*95ad37f9SFrank van der Linden 
322*95ad37f9SFrank van der Linden 	old = cache->listxattr;
323*95ad37f9SFrank van der Linden 
324*95ad37f9SFrank van der Linden 	if (old == ERR_PTR(-ESTALE)) {
325*95ad37f9SFrank van der Linden 		ret = 0;
326*95ad37f9SFrank van der Linden 		goto out;
327*95ad37f9SFrank van der Linden 	}
328*95ad37f9SFrank van der Linden 
329*95ad37f9SFrank van der Linden 	cache->listxattr = new;
330*95ad37f9SFrank van der Linden 	if (new != NULL && new != ERR_PTR(-ESTALE))
331*95ad37f9SFrank van der Linden 		nfs4_xattr_entry_lru_add(new);
332*95ad37f9SFrank van der Linden 
333*95ad37f9SFrank van der Linden 	if (old != NULL) {
334*95ad37f9SFrank van der Linden 		nfs4_xattr_entry_lru_del(old);
335*95ad37f9SFrank van der Linden 		kref_put(&old->ref, nfs4_xattr_free_entry_cb);
336*95ad37f9SFrank van der Linden 	}
337*95ad37f9SFrank van der Linden out:
338*95ad37f9SFrank van der Linden 	spin_unlock(&cache->listxattr_lock);
339*95ad37f9SFrank van der Linden 
340*95ad37f9SFrank van der Linden 	return ret;
341*95ad37f9SFrank van der Linden }
342*95ad37f9SFrank van der Linden 
343*95ad37f9SFrank van der Linden /*
344*95ad37f9SFrank van der Linden  * Unlink a cache from its parent inode, clearing out an invalid
345*95ad37f9SFrank van der Linden  * cache. Must be called with i_lock held.
346*95ad37f9SFrank van der Linden  */
347*95ad37f9SFrank van der Linden static struct nfs4_xattr_cache *
348*95ad37f9SFrank van der Linden nfs4_xattr_cache_unlink(struct inode *inode)
349*95ad37f9SFrank van der Linden {
350*95ad37f9SFrank van der Linden 	struct nfs_inode *nfsi;
351*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *oldcache;
352*95ad37f9SFrank van der Linden 
353*95ad37f9SFrank van der Linden 	nfsi = NFS_I(inode);
354*95ad37f9SFrank van der Linden 
355*95ad37f9SFrank van der Linden 	oldcache = nfsi->xattr_cache;
356*95ad37f9SFrank van der Linden 	if (oldcache != NULL) {
357*95ad37f9SFrank van der Linden 		list_lru_del(&nfs4_xattr_cache_lru, &oldcache->lru);
358*95ad37f9SFrank van der Linden 		oldcache->inode = NULL;
359*95ad37f9SFrank van der Linden 	}
360*95ad37f9SFrank van der Linden 	nfsi->xattr_cache = NULL;
361*95ad37f9SFrank van der Linden 	nfsi->cache_validity &= ~NFS_INO_INVALID_XATTR;
362*95ad37f9SFrank van der Linden 
363*95ad37f9SFrank van der Linden 	return oldcache;
364*95ad37f9SFrank van der Linden 
365*95ad37f9SFrank van der Linden }
366*95ad37f9SFrank van der Linden 
367*95ad37f9SFrank van der Linden /*
368*95ad37f9SFrank van der Linden  * Discard a cache. Usually called by a worker, since walking all
369*95ad37f9SFrank van der Linden  * the entries can take up some cycles that we don't want to waste
370*95ad37f9SFrank van der Linden  * in the I/O path. Can also be called from the shrinker callback.
371*95ad37f9SFrank van der Linden  *
372*95ad37f9SFrank van der Linden  * The cache is dead, it has already been unlinked from its inode,
373*95ad37f9SFrank van der Linden  * and no longer appears on the cache LRU list.
374*95ad37f9SFrank van der Linden  *
375*95ad37f9SFrank van der Linden  * Mark all buckets as draining, so that no new entries are added. This
376*95ad37f9SFrank van der Linden  * could still happen in the unlikely, but possible case that another
377*95ad37f9SFrank van der Linden  * thread had grabbed a reference before it was unlinked from the inode,
378*95ad37f9SFrank van der Linden  * and is still holding it for an add operation.
379*95ad37f9SFrank van der Linden  *
380*95ad37f9SFrank van der Linden  * Remove all entries from the LRU lists, so that there is no longer
381*95ad37f9SFrank van der Linden  * any way to 'find' this cache. Then, remove the entries from the hash
382*95ad37f9SFrank van der Linden  * table.
383*95ad37f9SFrank van der Linden  *
384*95ad37f9SFrank van der Linden  * At that point, the cache will remain empty and can be freed when the final
385*95ad37f9SFrank van der Linden  * reference drops, which is very likely the kref_put at the end of
386*95ad37f9SFrank van der Linden  * this function, or the one called immediately afterwards in the
387*95ad37f9SFrank van der Linden  * shrinker callback.
388*95ad37f9SFrank van der Linden  */
389*95ad37f9SFrank van der Linden static void
390*95ad37f9SFrank van der Linden nfs4_xattr_discard_cache(struct nfs4_xattr_cache *cache)
391*95ad37f9SFrank van der Linden {
392*95ad37f9SFrank van der Linden 	unsigned int i;
393*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
394*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
395*95ad37f9SFrank van der Linden 	struct hlist_node *n;
396*95ad37f9SFrank van der Linden 
397*95ad37f9SFrank van der Linden 	nfs4_xattr_set_listcache(cache, ERR_PTR(-ESTALE));
398*95ad37f9SFrank van der Linden 
399*95ad37f9SFrank van der Linden 	for (i = 0; i < NFS4_XATTR_HASH_SIZE; i++) {
400*95ad37f9SFrank van der Linden 		bucket = &cache->buckets[i];
401*95ad37f9SFrank van der Linden 
402*95ad37f9SFrank van der Linden 		spin_lock(&bucket->lock);
403*95ad37f9SFrank van der Linden 		bucket->draining = true;
404*95ad37f9SFrank van der Linden 		hlist_for_each_entry_safe(entry, n, &bucket->hlist, hnode) {
405*95ad37f9SFrank van der Linden 			nfs4_xattr_entry_lru_del(entry);
406*95ad37f9SFrank van der Linden 			hlist_del_init(&entry->hnode);
407*95ad37f9SFrank van der Linden 			kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
408*95ad37f9SFrank van der Linden 		}
409*95ad37f9SFrank van der Linden 		spin_unlock(&bucket->lock);
410*95ad37f9SFrank van der Linden 	}
411*95ad37f9SFrank van der Linden 
412*95ad37f9SFrank van der Linden 	atomic_long_set(&cache->nent, 0);
413*95ad37f9SFrank van der Linden 
414*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
415*95ad37f9SFrank van der Linden }
416*95ad37f9SFrank van der Linden 
417*95ad37f9SFrank van der Linden static void
418*95ad37f9SFrank van der Linden nfs4_xattr_discard_cache_worker(struct work_struct *work)
419*95ad37f9SFrank van der Linden {
420*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache = container_of(work,
421*95ad37f9SFrank van der Linden 	    struct nfs4_xattr_cache, work);
422*95ad37f9SFrank van der Linden 
423*95ad37f9SFrank van der Linden 	nfs4_xattr_discard_cache(cache);
424*95ad37f9SFrank van der Linden }
425*95ad37f9SFrank van der Linden 
426*95ad37f9SFrank van der Linden static void
427*95ad37f9SFrank van der Linden nfs4_xattr_reap_cache(struct nfs4_xattr_cache *cache)
428*95ad37f9SFrank van der Linden {
429*95ad37f9SFrank van der Linden 	queue_work(nfs4_xattr_cache_wq, &cache->work);
430*95ad37f9SFrank van der Linden }
431*95ad37f9SFrank van der Linden 
432*95ad37f9SFrank van der Linden /*
433*95ad37f9SFrank van der Linden  * Get a referenced copy of the cache structure. Avoid doing allocs
434*95ad37f9SFrank van der Linden  * while holding i_lock. Which means that we do some optimistic allocation,
435*95ad37f9SFrank van der Linden  * and might have to free the result in rare cases.
436*95ad37f9SFrank van der Linden  *
437*95ad37f9SFrank van der Linden  * This function only checks the NFS_INO_INVALID_XATTR cache validity bit
438*95ad37f9SFrank van der Linden  * and acts accordingly, replacing the cache when needed. For the read case
439*95ad37f9SFrank van der Linden  * (!add), this means that the caller must make sure that the cache
440*95ad37f9SFrank van der Linden  * is valid before caling this function. getxattr and listxattr call
441*95ad37f9SFrank van der Linden  * revalidate_inode to do this. The attribute cache timeout (for the
442*95ad37f9SFrank van der Linden  * non-delegated case) is expected to be dealt with in the revalidate
443*95ad37f9SFrank van der Linden  * call.
444*95ad37f9SFrank van der Linden  */
445*95ad37f9SFrank van der Linden 
446*95ad37f9SFrank van der Linden static struct nfs4_xattr_cache *
447*95ad37f9SFrank van der Linden nfs4_xattr_get_cache(struct inode *inode, int add)
448*95ad37f9SFrank van der Linden {
449*95ad37f9SFrank van der Linden 	struct nfs_inode *nfsi;
450*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache, *oldcache, *newcache;
451*95ad37f9SFrank van der Linden 
452*95ad37f9SFrank van der Linden 	nfsi = NFS_I(inode);
453*95ad37f9SFrank van der Linden 
454*95ad37f9SFrank van der Linden 	cache = oldcache = NULL;
455*95ad37f9SFrank van der Linden 
456*95ad37f9SFrank van der Linden 	spin_lock(&inode->i_lock);
457*95ad37f9SFrank van der Linden 
458*95ad37f9SFrank van der Linden 	if (nfsi->cache_validity & NFS_INO_INVALID_XATTR)
459*95ad37f9SFrank van der Linden 		oldcache = nfs4_xattr_cache_unlink(inode);
460*95ad37f9SFrank van der Linden 	else
461*95ad37f9SFrank van der Linden 		cache = nfsi->xattr_cache;
462*95ad37f9SFrank van der Linden 
463*95ad37f9SFrank van der Linden 	if (cache != NULL)
464*95ad37f9SFrank van der Linden 		kref_get(&cache->ref);
465*95ad37f9SFrank van der Linden 
466*95ad37f9SFrank van der Linden 	spin_unlock(&inode->i_lock);
467*95ad37f9SFrank van der Linden 
468*95ad37f9SFrank van der Linden 	if (add && cache == NULL) {
469*95ad37f9SFrank van der Linden 		newcache = NULL;
470*95ad37f9SFrank van der Linden 
471*95ad37f9SFrank van der Linden 		cache = nfs4_xattr_alloc_cache();
472*95ad37f9SFrank van der Linden 		if (cache == NULL)
473*95ad37f9SFrank van der Linden 			goto out;
474*95ad37f9SFrank van der Linden 
475*95ad37f9SFrank van der Linden 		spin_lock(&inode->i_lock);
476*95ad37f9SFrank van der Linden 		if (nfsi->cache_validity & NFS_INO_INVALID_XATTR) {
477*95ad37f9SFrank van der Linden 			/*
478*95ad37f9SFrank van der Linden 			 * The cache was invalidated again. Give up,
479*95ad37f9SFrank van der Linden 			 * since what we want to enter is now likely
480*95ad37f9SFrank van der Linden 			 * outdated anyway.
481*95ad37f9SFrank van der Linden 			 */
482*95ad37f9SFrank van der Linden 			spin_unlock(&inode->i_lock);
483*95ad37f9SFrank van der Linden 			kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
484*95ad37f9SFrank van der Linden 			cache = NULL;
485*95ad37f9SFrank van der Linden 			goto out;
486*95ad37f9SFrank van der Linden 		}
487*95ad37f9SFrank van der Linden 
488*95ad37f9SFrank van der Linden 		/*
489*95ad37f9SFrank van der Linden 		 * Check if someone beat us to it.
490*95ad37f9SFrank van der Linden 		 */
491*95ad37f9SFrank van der Linden 		if (nfsi->xattr_cache != NULL) {
492*95ad37f9SFrank van der Linden 			newcache = nfsi->xattr_cache;
493*95ad37f9SFrank van der Linden 			kref_get(&newcache->ref);
494*95ad37f9SFrank van der Linden 		} else {
495*95ad37f9SFrank van der Linden 			kref_get(&cache->ref);
496*95ad37f9SFrank van der Linden 			nfsi->xattr_cache = cache;
497*95ad37f9SFrank van der Linden 			cache->inode = inode;
498*95ad37f9SFrank van der Linden 			list_lru_add(&nfs4_xattr_cache_lru, &cache->lru);
499*95ad37f9SFrank van der Linden 		}
500*95ad37f9SFrank van der Linden 
501*95ad37f9SFrank van der Linden 		spin_unlock(&inode->i_lock);
502*95ad37f9SFrank van der Linden 
503*95ad37f9SFrank van der Linden 		/*
504*95ad37f9SFrank van der Linden 		 * If there was a race, throw away the cache we just
505*95ad37f9SFrank van der Linden 		 * allocated, and use the new one allocated by someone
506*95ad37f9SFrank van der Linden 		 * else.
507*95ad37f9SFrank van der Linden 		 */
508*95ad37f9SFrank van der Linden 		if (newcache != NULL) {
509*95ad37f9SFrank van der Linden 			kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
510*95ad37f9SFrank van der Linden 			cache = newcache;
511*95ad37f9SFrank van der Linden 		}
512*95ad37f9SFrank van der Linden 	}
513*95ad37f9SFrank van der Linden 
514*95ad37f9SFrank van der Linden out:
515*95ad37f9SFrank van der Linden 	/*
516*95ad37f9SFrank van der Linden 	 * Discarding an old cache is done via a workqueue.
517*95ad37f9SFrank van der Linden 	 */
518*95ad37f9SFrank van der Linden 	if (oldcache != NULL)
519*95ad37f9SFrank van der Linden 		nfs4_xattr_reap_cache(oldcache);
520*95ad37f9SFrank van der Linden 
521*95ad37f9SFrank van der Linden 	return cache;
522*95ad37f9SFrank van der Linden }
523*95ad37f9SFrank van der Linden 
524*95ad37f9SFrank van der Linden static inline struct nfs4_xattr_bucket *
525*95ad37f9SFrank van der Linden nfs4_xattr_hash_bucket(struct nfs4_xattr_cache *cache, const char *name)
526*95ad37f9SFrank van der Linden {
527*95ad37f9SFrank van der Linden 	return &cache->buckets[jhash(name, strlen(name), 0) &
528*95ad37f9SFrank van der Linden 	    (ARRAY_SIZE(cache->buckets) - 1)];
529*95ad37f9SFrank van der Linden }
530*95ad37f9SFrank van der Linden 
531*95ad37f9SFrank van der Linden static struct nfs4_xattr_entry *
532*95ad37f9SFrank van der Linden nfs4_xattr_get_entry(struct nfs4_xattr_bucket *bucket, const char *name)
533*95ad37f9SFrank van der Linden {
534*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
535*95ad37f9SFrank van der Linden 
536*95ad37f9SFrank van der Linden 	entry = NULL;
537*95ad37f9SFrank van der Linden 
538*95ad37f9SFrank van der Linden 	hlist_for_each_entry(entry, &bucket->hlist, hnode) {
539*95ad37f9SFrank van der Linden 		if (!strcmp(entry->xattr_name, name))
540*95ad37f9SFrank van der Linden 			break;
541*95ad37f9SFrank van der Linden 	}
542*95ad37f9SFrank van der Linden 
543*95ad37f9SFrank van der Linden 	return entry;
544*95ad37f9SFrank van der Linden }
545*95ad37f9SFrank van der Linden 
546*95ad37f9SFrank van der Linden static int
547*95ad37f9SFrank van der Linden nfs4_xattr_hash_add(struct nfs4_xattr_cache *cache,
548*95ad37f9SFrank van der Linden 		    struct nfs4_xattr_entry *entry)
549*95ad37f9SFrank van der Linden {
550*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
551*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *oldentry = NULL;
552*95ad37f9SFrank van der Linden 	int ret = 1;
553*95ad37f9SFrank van der Linden 
554*95ad37f9SFrank van der Linden 	bucket = nfs4_xattr_hash_bucket(cache, entry->xattr_name);
555*95ad37f9SFrank van der Linden 	entry->bucket = bucket;
556*95ad37f9SFrank van der Linden 
557*95ad37f9SFrank van der Linden 	spin_lock(&bucket->lock);
558*95ad37f9SFrank van der Linden 
559*95ad37f9SFrank van der Linden 	if (bucket->draining) {
560*95ad37f9SFrank van der Linden 		ret = 0;
561*95ad37f9SFrank van der Linden 		goto out;
562*95ad37f9SFrank van der Linden 	}
563*95ad37f9SFrank van der Linden 
564*95ad37f9SFrank van der Linden 	oldentry = nfs4_xattr_get_entry(bucket, entry->xattr_name);
565*95ad37f9SFrank van der Linden 	if (oldentry != NULL) {
566*95ad37f9SFrank van der Linden 		hlist_del_init(&oldentry->hnode);
567*95ad37f9SFrank van der Linden 		nfs4_xattr_entry_lru_del(oldentry);
568*95ad37f9SFrank van der Linden 	} else {
569*95ad37f9SFrank van der Linden 		atomic_long_inc(&cache->nent);
570*95ad37f9SFrank van der Linden 	}
571*95ad37f9SFrank van der Linden 
572*95ad37f9SFrank van der Linden 	hlist_add_head(&entry->hnode, &bucket->hlist);
573*95ad37f9SFrank van der Linden 	nfs4_xattr_entry_lru_add(entry);
574*95ad37f9SFrank van der Linden 
575*95ad37f9SFrank van der Linden out:
576*95ad37f9SFrank van der Linden 	spin_unlock(&bucket->lock);
577*95ad37f9SFrank van der Linden 
578*95ad37f9SFrank van der Linden 	if (oldentry != NULL)
579*95ad37f9SFrank van der Linden 		kref_put(&oldentry->ref, nfs4_xattr_free_entry_cb);
580*95ad37f9SFrank van der Linden 
581*95ad37f9SFrank van der Linden 	return ret;
582*95ad37f9SFrank van der Linden }
583*95ad37f9SFrank van der Linden 
584*95ad37f9SFrank van der Linden static void
585*95ad37f9SFrank van der Linden nfs4_xattr_hash_remove(struct nfs4_xattr_cache *cache, const char *name)
586*95ad37f9SFrank van der Linden {
587*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
588*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
589*95ad37f9SFrank van der Linden 
590*95ad37f9SFrank van der Linden 	bucket = nfs4_xattr_hash_bucket(cache, name);
591*95ad37f9SFrank van der Linden 
592*95ad37f9SFrank van der Linden 	spin_lock(&bucket->lock);
593*95ad37f9SFrank van der Linden 
594*95ad37f9SFrank van der Linden 	entry = nfs4_xattr_get_entry(bucket, name);
595*95ad37f9SFrank van der Linden 	if (entry != NULL) {
596*95ad37f9SFrank van der Linden 		hlist_del_init(&entry->hnode);
597*95ad37f9SFrank van der Linden 		nfs4_xattr_entry_lru_del(entry);
598*95ad37f9SFrank van der Linden 		atomic_long_dec(&cache->nent);
599*95ad37f9SFrank van der Linden 	}
600*95ad37f9SFrank van der Linden 
601*95ad37f9SFrank van der Linden 	spin_unlock(&bucket->lock);
602*95ad37f9SFrank van der Linden 
603*95ad37f9SFrank van der Linden 	if (entry != NULL)
604*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
605*95ad37f9SFrank van der Linden }
606*95ad37f9SFrank van der Linden 
607*95ad37f9SFrank van der Linden static struct nfs4_xattr_entry *
608*95ad37f9SFrank van der Linden nfs4_xattr_hash_find(struct nfs4_xattr_cache *cache, const char *name)
609*95ad37f9SFrank van der Linden {
610*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
611*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
612*95ad37f9SFrank van der Linden 
613*95ad37f9SFrank van der Linden 	bucket = nfs4_xattr_hash_bucket(cache, name);
614*95ad37f9SFrank van der Linden 
615*95ad37f9SFrank van der Linden 	spin_lock(&bucket->lock);
616*95ad37f9SFrank van der Linden 
617*95ad37f9SFrank van der Linden 	entry = nfs4_xattr_get_entry(bucket, name);
618*95ad37f9SFrank van der Linden 	if (entry != NULL)
619*95ad37f9SFrank van der Linden 		kref_get(&entry->ref);
620*95ad37f9SFrank van der Linden 
621*95ad37f9SFrank van der Linden 	spin_unlock(&bucket->lock);
622*95ad37f9SFrank van der Linden 
623*95ad37f9SFrank van der Linden 	return entry;
624*95ad37f9SFrank van der Linden }
625*95ad37f9SFrank van der Linden 
626*95ad37f9SFrank van der Linden /*
627*95ad37f9SFrank van der Linden  * Entry point to retrieve an entry from the cache.
628*95ad37f9SFrank van der Linden  */
629*95ad37f9SFrank van der Linden ssize_t nfs4_xattr_cache_get(struct inode *inode, const char *name, char *buf,
630*95ad37f9SFrank van der Linden 			 ssize_t buflen)
631*95ad37f9SFrank van der Linden {
632*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
633*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
634*95ad37f9SFrank van der Linden 	ssize_t ret;
635*95ad37f9SFrank van der Linden 
636*95ad37f9SFrank van der Linden 	cache = nfs4_xattr_get_cache(inode, 0);
637*95ad37f9SFrank van der Linden 	if (cache == NULL)
638*95ad37f9SFrank van der Linden 		return -ENOENT;
639*95ad37f9SFrank van der Linden 
640*95ad37f9SFrank van der Linden 	ret = 0;
641*95ad37f9SFrank van der Linden 	entry = nfs4_xattr_hash_find(cache, name);
642*95ad37f9SFrank van der Linden 
643*95ad37f9SFrank van der Linden 	if (entry != NULL) {
644*95ad37f9SFrank van der Linden 		dprintk("%s: cache hit '%s', len %lu\n", __func__,
645*95ad37f9SFrank van der Linden 		    entry->xattr_name, (unsigned long)entry->xattr_size);
646*95ad37f9SFrank van der Linden 		if (buflen == 0) {
647*95ad37f9SFrank van der Linden 			/* Length probe only */
648*95ad37f9SFrank van der Linden 			ret = entry->xattr_size;
649*95ad37f9SFrank van der Linden 		} else if (buflen < entry->xattr_size)
650*95ad37f9SFrank van der Linden 			ret = -ERANGE;
651*95ad37f9SFrank van der Linden 		else {
652*95ad37f9SFrank van der Linden 			memcpy(buf, entry->xattr_value, entry->xattr_size);
653*95ad37f9SFrank van der Linden 			ret = entry->xattr_size;
654*95ad37f9SFrank van der Linden 		}
655*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
656*95ad37f9SFrank van der Linden 	} else {
657*95ad37f9SFrank van der Linden 		dprintk("%s: cache miss '%s'\n", __func__, name);
658*95ad37f9SFrank van der Linden 		ret = -ENOENT;
659*95ad37f9SFrank van der Linden 	}
660*95ad37f9SFrank van der Linden 
661*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
662*95ad37f9SFrank van der Linden 
663*95ad37f9SFrank van der Linden 	return ret;
664*95ad37f9SFrank van der Linden }
665*95ad37f9SFrank van der Linden 
666*95ad37f9SFrank van der Linden /*
667*95ad37f9SFrank van der Linden  * Retrieve a cached list of xattrs from the cache.
668*95ad37f9SFrank van der Linden  */
669*95ad37f9SFrank van der Linden ssize_t nfs4_xattr_cache_list(struct inode *inode, char *buf, ssize_t buflen)
670*95ad37f9SFrank van der Linden {
671*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
672*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
673*95ad37f9SFrank van der Linden 	ssize_t ret;
674*95ad37f9SFrank van der Linden 
675*95ad37f9SFrank van der Linden 	cache = nfs4_xattr_get_cache(inode, 0);
676*95ad37f9SFrank van der Linden 	if (cache == NULL)
677*95ad37f9SFrank van der Linden 		return -ENOENT;
678*95ad37f9SFrank van der Linden 
679*95ad37f9SFrank van der Linden 	spin_lock(&cache->listxattr_lock);
680*95ad37f9SFrank van der Linden 
681*95ad37f9SFrank van der Linden 	entry = cache->listxattr;
682*95ad37f9SFrank van der Linden 
683*95ad37f9SFrank van der Linden 	if (entry != NULL && entry != ERR_PTR(-ESTALE)) {
684*95ad37f9SFrank van der Linden 		if (buflen == 0) {
685*95ad37f9SFrank van der Linden 			/* Length probe only */
686*95ad37f9SFrank van der Linden 			ret = entry->xattr_size;
687*95ad37f9SFrank van der Linden 		} else if (entry->xattr_size > buflen)
688*95ad37f9SFrank van der Linden 			ret = -ERANGE;
689*95ad37f9SFrank van der Linden 		else {
690*95ad37f9SFrank van der Linden 			memcpy(buf, entry->xattr_value, entry->xattr_size);
691*95ad37f9SFrank van der Linden 			ret = entry->xattr_size;
692*95ad37f9SFrank van der Linden 		}
693*95ad37f9SFrank van der Linden 	} else {
694*95ad37f9SFrank van der Linden 		ret = -ENOENT;
695*95ad37f9SFrank van der Linden 	}
696*95ad37f9SFrank van der Linden 
697*95ad37f9SFrank van der Linden 	spin_unlock(&cache->listxattr_lock);
698*95ad37f9SFrank van der Linden 
699*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
700*95ad37f9SFrank van der Linden 
701*95ad37f9SFrank van der Linden 	return ret;
702*95ad37f9SFrank van der Linden }
703*95ad37f9SFrank van der Linden 
704*95ad37f9SFrank van der Linden /*
705*95ad37f9SFrank van der Linden  * Add an xattr to the cache.
706*95ad37f9SFrank van der Linden  *
707*95ad37f9SFrank van der Linden  * This also invalidates the xattr list cache.
708*95ad37f9SFrank van der Linden  */
709*95ad37f9SFrank van der Linden void nfs4_xattr_cache_add(struct inode *inode, const char *name,
710*95ad37f9SFrank van der Linden 			  const char *buf, struct page **pages, ssize_t buflen)
711*95ad37f9SFrank van der Linden {
712*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
713*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
714*95ad37f9SFrank van der Linden 
715*95ad37f9SFrank van der Linden 	dprintk("%s: add '%s' len %lu\n", __func__,
716*95ad37f9SFrank van der Linden 	    name, (unsigned long)buflen);
717*95ad37f9SFrank van der Linden 
718*95ad37f9SFrank van der Linden 	cache = nfs4_xattr_get_cache(inode, 1);
719*95ad37f9SFrank van der Linden 	if (cache == NULL)
720*95ad37f9SFrank van der Linden 		return;
721*95ad37f9SFrank van der Linden 
722*95ad37f9SFrank van der Linden 	entry = nfs4_xattr_alloc_entry(name, buf, pages, buflen);
723*95ad37f9SFrank van der Linden 	if (entry == NULL)
724*95ad37f9SFrank van der Linden 		goto out;
725*95ad37f9SFrank van der Linden 
726*95ad37f9SFrank van der Linden 	(void)nfs4_xattr_set_listcache(cache, NULL);
727*95ad37f9SFrank van der Linden 
728*95ad37f9SFrank van der Linden 	if (!nfs4_xattr_hash_add(cache, entry))
729*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
730*95ad37f9SFrank van der Linden 
731*95ad37f9SFrank van der Linden out:
732*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
733*95ad37f9SFrank van der Linden }
734*95ad37f9SFrank van der Linden 
735*95ad37f9SFrank van der Linden 
736*95ad37f9SFrank van der Linden /*
737*95ad37f9SFrank van der Linden  * Remove an xattr from the cache.
738*95ad37f9SFrank van der Linden  *
739*95ad37f9SFrank van der Linden  * This also invalidates the xattr list cache.
740*95ad37f9SFrank van der Linden  */
741*95ad37f9SFrank van der Linden void nfs4_xattr_cache_remove(struct inode *inode, const char *name)
742*95ad37f9SFrank van der Linden {
743*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
744*95ad37f9SFrank van der Linden 
745*95ad37f9SFrank van der Linden 	dprintk("%s: remove '%s'\n", __func__, name);
746*95ad37f9SFrank van der Linden 
747*95ad37f9SFrank van der Linden 	cache = nfs4_xattr_get_cache(inode, 0);
748*95ad37f9SFrank van der Linden 	if (cache == NULL)
749*95ad37f9SFrank van der Linden 		return;
750*95ad37f9SFrank van der Linden 
751*95ad37f9SFrank van der Linden 	(void)nfs4_xattr_set_listcache(cache, NULL);
752*95ad37f9SFrank van der Linden 	nfs4_xattr_hash_remove(cache, name);
753*95ad37f9SFrank van der Linden 
754*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
755*95ad37f9SFrank van der Linden }
756*95ad37f9SFrank van der Linden 
757*95ad37f9SFrank van der Linden /*
758*95ad37f9SFrank van der Linden  * Cache listxattr output, replacing any possible old one.
759*95ad37f9SFrank van der Linden  */
760*95ad37f9SFrank van der Linden void nfs4_xattr_cache_set_list(struct inode *inode, const char *buf,
761*95ad37f9SFrank van der Linden 			       ssize_t buflen)
762*95ad37f9SFrank van der Linden {
763*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
764*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
765*95ad37f9SFrank van der Linden 
766*95ad37f9SFrank van der Linden 	cache = nfs4_xattr_get_cache(inode, 1);
767*95ad37f9SFrank van der Linden 	if (cache == NULL)
768*95ad37f9SFrank van der Linden 		return;
769*95ad37f9SFrank van der Linden 
770*95ad37f9SFrank van der Linden 	entry = nfs4_xattr_alloc_entry(NULL, buf, NULL, buflen);
771*95ad37f9SFrank van der Linden 	if (entry == NULL)
772*95ad37f9SFrank van der Linden 		goto out;
773*95ad37f9SFrank van der Linden 
774*95ad37f9SFrank van der Linden 	/*
775*95ad37f9SFrank van der Linden 	 * This is just there to be able to get to bucket->cache,
776*95ad37f9SFrank van der Linden 	 * which is obviously the same for all buckets, so just
777*95ad37f9SFrank van der Linden 	 * use bucket 0.
778*95ad37f9SFrank van der Linden 	 */
779*95ad37f9SFrank van der Linden 	entry->bucket = &cache->buckets[0];
780*95ad37f9SFrank van der Linden 
781*95ad37f9SFrank van der Linden 	if (!nfs4_xattr_set_listcache(cache, entry))
782*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
783*95ad37f9SFrank van der Linden 
784*95ad37f9SFrank van der Linden out:
785*95ad37f9SFrank van der Linden 	kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
786*95ad37f9SFrank van der Linden }
787*95ad37f9SFrank van der Linden 
788*95ad37f9SFrank van der Linden /*
789*95ad37f9SFrank van der Linden  * Zap the entire cache. Called when an inode is evicted.
790*95ad37f9SFrank van der Linden  */
791*95ad37f9SFrank van der Linden void nfs4_xattr_cache_zap(struct inode *inode)
792*95ad37f9SFrank van der Linden {
793*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *oldcache;
794*95ad37f9SFrank van der Linden 
795*95ad37f9SFrank van der Linden 	spin_lock(&inode->i_lock);
796*95ad37f9SFrank van der Linden 	oldcache = nfs4_xattr_cache_unlink(inode);
797*95ad37f9SFrank van der Linden 	spin_unlock(&inode->i_lock);
798*95ad37f9SFrank van der Linden 
799*95ad37f9SFrank van der Linden 	if (oldcache)
800*95ad37f9SFrank van der Linden 		nfs4_xattr_discard_cache(oldcache);
801*95ad37f9SFrank van der Linden }
802*95ad37f9SFrank van der Linden 
803*95ad37f9SFrank van der Linden /*
804*95ad37f9SFrank van der Linden  * The entry LRU is shrunk more aggressively than the cache LRU,
805*95ad37f9SFrank van der Linden  * by settings @seeks to 1.
806*95ad37f9SFrank van der Linden  *
807*95ad37f9SFrank van der Linden  * Cache structures are freed only when they've become empty, after
808*95ad37f9SFrank van der Linden  * pruning all but one entry.
809*95ad37f9SFrank van der Linden  */
810*95ad37f9SFrank van der Linden 
811*95ad37f9SFrank van der Linden static unsigned long nfs4_xattr_cache_count(struct shrinker *shrink,
812*95ad37f9SFrank van der Linden 					    struct shrink_control *sc);
813*95ad37f9SFrank van der Linden static unsigned long nfs4_xattr_entry_count(struct shrinker *shrink,
814*95ad37f9SFrank van der Linden 					    struct shrink_control *sc);
815*95ad37f9SFrank van der Linden static unsigned long nfs4_xattr_cache_scan(struct shrinker *shrink,
816*95ad37f9SFrank van der Linden 					   struct shrink_control *sc);
817*95ad37f9SFrank van der Linden static unsigned long nfs4_xattr_entry_scan(struct shrinker *shrink,
818*95ad37f9SFrank van der Linden 					   struct shrink_control *sc);
819*95ad37f9SFrank van der Linden 
820*95ad37f9SFrank van der Linden static struct shrinker nfs4_xattr_cache_shrinker = {
821*95ad37f9SFrank van der Linden 	.count_objects	= nfs4_xattr_cache_count,
822*95ad37f9SFrank van der Linden 	.scan_objects	= nfs4_xattr_cache_scan,
823*95ad37f9SFrank van der Linden 	.seeks		= DEFAULT_SEEKS,
824*95ad37f9SFrank van der Linden 	.flags		= SHRINKER_MEMCG_AWARE,
825*95ad37f9SFrank van der Linden };
826*95ad37f9SFrank van der Linden 
827*95ad37f9SFrank van der Linden static struct shrinker nfs4_xattr_entry_shrinker = {
828*95ad37f9SFrank van der Linden 	.count_objects	= nfs4_xattr_entry_count,
829*95ad37f9SFrank van der Linden 	.scan_objects	= nfs4_xattr_entry_scan,
830*95ad37f9SFrank van der Linden 	.seeks		= DEFAULT_SEEKS,
831*95ad37f9SFrank van der Linden 	.batch		= 512,
832*95ad37f9SFrank van der Linden 	.flags		= SHRINKER_MEMCG_AWARE,
833*95ad37f9SFrank van der Linden };
834*95ad37f9SFrank van der Linden 
835*95ad37f9SFrank van der Linden static struct shrinker nfs4_xattr_large_entry_shrinker = {
836*95ad37f9SFrank van der Linden 	.count_objects	= nfs4_xattr_entry_count,
837*95ad37f9SFrank van der Linden 	.scan_objects	= nfs4_xattr_entry_scan,
838*95ad37f9SFrank van der Linden 	.seeks		= 1,
839*95ad37f9SFrank van der Linden 	.batch		= 512,
840*95ad37f9SFrank van der Linden 	.flags		= SHRINKER_MEMCG_AWARE,
841*95ad37f9SFrank van der Linden };
842*95ad37f9SFrank van der Linden 
843*95ad37f9SFrank van der Linden static enum lru_status
844*95ad37f9SFrank van der Linden cache_lru_isolate(struct list_head *item,
845*95ad37f9SFrank van der Linden 	struct list_lru_one *lru, spinlock_t *lru_lock, void *arg)
846*95ad37f9SFrank van der Linden {
847*95ad37f9SFrank van der Linden 	struct list_head *dispose = arg;
848*95ad37f9SFrank van der Linden 	struct inode *inode;
849*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache = container_of(item,
850*95ad37f9SFrank van der Linden 	    struct nfs4_xattr_cache, lru);
851*95ad37f9SFrank van der Linden 
852*95ad37f9SFrank van der Linden 	if (atomic_long_read(&cache->nent) > 1)
853*95ad37f9SFrank van der Linden 		return LRU_SKIP;
854*95ad37f9SFrank van der Linden 
855*95ad37f9SFrank van der Linden 	/*
856*95ad37f9SFrank van der Linden 	 * If a cache structure is on the LRU list, we know that
857*95ad37f9SFrank van der Linden 	 * its inode is valid. Try to lock it to break the link.
858*95ad37f9SFrank van der Linden 	 * Since we're inverting the lock order here, only try.
859*95ad37f9SFrank van der Linden 	 */
860*95ad37f9SFrank van der Linden 	inode = cache->inode;
861*95ad37f9SFrank van der Linden 
862*95ad37f9SFrank van der Linden 	if (!spin_trylock(&inode->i_lock))
863*95ad37f9SFrank van der Linden 		return LRU_SKIP;
864*95ad37f9SFrank van der Linden 
865*95ad37f9SFrank van der Linden 	kref_get(&cache->ref);
866*95ad37f9SFrank van der Linden 
867*95ad37f9SFrank van der Linden 	cache->inode = NULL;
868*95ad37f9SFrank van der Linden 	NFS_I(inode)->xattr_cache = NULL;
869*95ad37f9SFrank van der Linden 	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_XATTR;
870*95ad37f9SFrank van der Linden 	list_lru_isolate(lru, &cache->lru);
871*95ad37f9SFrank van der Linden 
872*95ad37f9SFrank van der Linden 	spin_unlock(&inode->i_lock);
873*95ad37f9SFrank van der Linden 
874*95ad37f9SFrank van der Linden 	list_add_tail(&cache->dispose, dispose);
875*95ad37f9SFrank van der Linden 	return LRU_REMOVED;
876*95ad37f9SFrank van der Linden }
877*95ad37f9SFrank van der Linden 
878*95ad37f9SFrank van der Linden static unsigned long
879*95ad37f9SFrank van der Linden nfs4_xattr_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
880*95ad37f9SFrank van der Linden {
881*95ad37f9SFrank van der Linden 	LIST_HEAD(dispose);
882*95ad37f9SFrank van der Linden 	unsigned long freed;
883*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
884*95ad37f9SFrank van der Linden 
885*95ad37f9SFrank van der Linden 	freed = list_lru_shrink_walk(&nfs4_xattr_cache_lru, sc,
886*95ad37f9SFrank van der Linden 	    cache_lru_isolate, &dispose);
887*95ad37f9SFrank van der Linden 	while (!list_empty(&dispose)) {
888*95ad37f9SFrank van der Linden 		cache = list_first_entry(&dispose, struct nfs4_xattr_cache,
889*95ad37f9SFrank van der Linden 		    dispose);
890*95ad37f9SFrank van der Linden 		list_del_init(&cache->dispose);
891*95ad37f9SFrank van der Linden 		nfs4_xattr_discard_cache(cache);
892*95ad37f9SFrank van der Linden 		kref_put(&cache->ref, nfs4_xattr_free_cache_cb);
893*95ad37f9SFrank van der Linden 	}
894*95ad37f9SFrank van der Linden 
895*95ad37f9SFrank van der Linden 	return freed;
896*95ad37f9SFrank van der Linden }
897*95ad37f9SFrank van der Linden 
898*95ad37f9SFrank van der Linden 
899*95ad37f9SFrank van der Linden static unsigned long
900*95ad37f9SFrank van der Linden nfs4_xattr_cache_count(struct shrinker *shrink, struct shrink_control *sc)
901*95ad37f9SFrank van der Linden {
902*95ad37f9SFrank van der Linden 	unsigned long count;
903*95ad37f9SFrank van der Linden 
904*95ad37f9SFrank van der Linden 	count = list_lru_count(&nfs4_xattr_cache_lru);
905*95ad37f9SFrank van der Linden 	return vfs_pressure_ratio(count);
906*95ad37f9SFrank van der Linden }
907*95ad37f9SFrank van der Linden 
908*95ad37f9SFrank van der Linden static enum lru_status
909*95ad37f9SFrank van der Linden entry_lru_isolate(struct list_head *item,
910*95ad37f9SFrank van der Linden 	struct list_lru_one *lru, spinlock_t *lru_lock, void *arg)
911*95ad37f9SFrank van der Linden {
912*95ad37f9SFrank van der Linden 	struct list_head *dispose = arg;
913*95ad37f9SFrank van der Linden 	struct nfs4_xattr_bucket *bucket;
914*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache;
915*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry = container_of(item,
916*95ad37f9SFrank van der Linden 	    struct nfs4_xattr_entry, lru);
917*95ad37f9SFrank van der Linden 
918*95ad37f9SFrank van der Linden 	bucket = entry->bucket;
919*95ad37f9SFrank van der Linden 	cache = bucket->cache;
920*95ad37f9SFrank van der Linden 
921*95ad37f9SFrank van der Linden 	/*
922*95ad37f9SFrank van der Linden 	 * Unhook the entry from its parent (either a cache bucket
923*95ad37f9SFrank van der Linden 	 * or a cache structure if it's a listxattr buf), so that
924*95ad37f9SFrank van der Linden 	 * it's no longer found. Then add it to the isolate list,
925*95ad37f9SFrank van der Linden 	 * to be freed later.
926*95ad37f9SFrank van der Linden 	 *
927*95ad37f9SFrank van der Linden 	 * In both cases, we're reverting lock order, so use
928*95ad37f9SFrank van der Linden 	 * trylock and skip the entry if we can't get the lock.
929*95ad37f9SFrank van der Linden 	 */
930*95ad37f9SFrank van der Linden 	if (entry->xattr_name != NULL) {
931*95ad37f9SFrank van der Linden 		/* Regular cache entry */
932*95ad37f9SFrank van der Linden 		if (!spin_trylock(&bucket->lock))
933*95ad37f9SFrank van der Linden 			return LRU_SKIP;
934*95ad37f9SFrank van der Linden 
935*95ad37f9SFrank van der Linden 		kref_get(&entry->ref);
936*95ad37f9SFrank van der Linden 
937*95ad37f9SFrank van der Linden 		hlist_del_init(&entry->hnode);
938*95ad37f9SFrank van der Linden 		atomic_long_dec(&cache->nent);
939*95ad37f9SFrank van der Linden 		list_lru_isolate(lru, &entry->lru);
940*95ad37f9SFrank van der Linden 
941*95ad37f9SFrank van der Linden 		spin_unlock(&bucket->lock);
942*95ad37f9SFrank van der Linden 	} else {
943*95ad37f9SFrank van der Linden 		/* Listxattr cache entry */
944*95ad37f9SFrank van der Linden 		if (!spin_trylock(&cache->listxattr_lock))
945*95ad37f9SFrank van der Linden 			return LRU_SKIP;
946*95ad37f9SFrank van der Linden 
947*95ad37f9SFrank van der Linden 		kref_get(&entry->ref);
948*95ad37f9SFrank van der Linden 
949*95ad37f9SFrank van der Linden 		cache->listxattr = NULL;
950*95ad37f9SFrank van der Linden 		list_lru_isolate(lru, &entry->lru);
951*95ad37f9SFrank van der Linden 
952*95ad37f9SFrank van der Linden 		spin_unlock(&cache->listxattr_lock);
953*95ad37f9SFrank van der Linden 	}
954*95ad37f9SFrank van der Linden 
955*95ad37f9SFrank van der Linden 	list_add_tail(&entry->dispose, dispose);
956*95ad37f9SFrank van der Linden 	return LRU_REMOVED;
957*95ad37f9SFrank van der Linden }
958*95ad37f9SFrank van der Linden 
959*95ad37f9SFrank van der Linden static unsigned long
960*95ad37f9SFrank van der Linden nfs4_xattr_entry_scan(struct shrinker *shrink, struct shrink_control *sc)
961*95ad37f9SFrank van der Linden {
962*95ad37f9SFrank van der Linden 	LIST_HEAD(dispose);
963*95ad37f9SFrank van der Linden 	unsigned long freed;
964*95ad37f9SFrank van der Linden 	struct nfs4_xattr_entry *entry;
965*95ad37f9SFrank van der Linden 	struct list_lru *lru;
966*95ad37f9SFrank van der Linden 
967*95ad37f9SFrank van der Linden 	lru = (shrink == &nfs4_xattr_large_entry_shrinker) ?
968*95ad37f9SFrank van der Linden 	    &nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
969*95ad37f9SFrank van der Linden 
970*95ad37f9SFrank van der Linden 	freed = list_lru_shrink_walk(lru, sc, entry_lru_isolate, &dispose);
971*95ad37f9SFrank van der Linden 
972*95ad37f9SFrank van der Linden 	while (!list_empty(&dispose)) {
973*95ad37f9SFrank van der Linden 		entry = list_first_entry(&dispose, struct nfs4_xattr_entry,
974*95ad37f9SFrank van der Linden 		    dispose);
975*95ad37f9SFrank van der Linden 		list_del_init(&entry->dispose);
976*95ad37f9SFrank van der Linden 
977*95ad37f9SFrank van der Linden 		/*
978*95ad37f9SFrank van der Linden 		 * Drop two references: the one that we just grabbed
979*95ad37f9SFrank van der Linden 		 * in entry_lru_isolate, and the one that was set
980*95ad37f9SFrank van der Linden 		 * when the entry was first allocated.
981*95ad37f9SFrank van der Linden 		 */
982*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
983*95ad37f9SFrank van der Linden 		kref_put(&entry->ref, nfs4_xattr_free_entry_cb);
984*95ad37f9SFrank van der Linden 	}
985*95ad37f9SFrank van der Linden 
986*95ad37f9SFrank van der Linden 	return freed;
987*95ad37f9SFrank van der Linden }
988*95ad37f9SFrank van der Linden 
989*95ad37f9SFrank van der Linden static unsigned long
990*95ad37f9SFrank van der Linden nfs4_xattr_entry_count(struct shrinker *shrink, struct shrink_control *sc)
991*95ad37f9SFrank van der Linden {
992*95ad37f9SFrank van der Linden 	unsigned long count;
993*95ad37f9SFrank van der Linden 	struct list_lru *lru;
994*95ad37f9SFrank van der Linden 
995*95ad37f9SFrank van der Linden 	lru = (shrink == &nfs4_xattr_large_entry_shrinker) ?
996*95ad37f9SFrank van der Linden 	    &nfs4_xattr_large_entry_lru : &nfs4_xattr_entry_lru;
997*95ad37f9SFrank van der Linden 
998*95ad37f9SFrank van der Linden 	count = list_lru_count(lru);
999*95ad37f9SFrank van der Linden 	return vfs_pressure_ratio(count);
1000*95ad37f9SFrank van der Linden }
1001*95ad37f9SFrank van der Linden 
1002*95ad37f9SFrank van der Linden 
1003*95ad37f9SFrank van der Linden static void nfs4_xattr_cache_init_once(void *p)
1004*95ad37f9SFrank van der Linden {
1005*95ad37f9SFrank van der Linden 	struct nfs4_xattr_cache *cache = (struct nfs4_xattr_cache *)p;
1006*95ad37f9SFrank van der Linden 
1007*95ad37f9SFrank van der Linden 	spin_lock_init(&cache->listxattr_lock);
1008*95ad37f9SFrank van der Linden 	atomic_long_set(&cache->nent, 0);
1009*95ad37f9SFrank van der Linden 	nfs4_xattr_hash_init(cache);
1010*95ad37f9SFrank van der Linden 	cache->listxattr = NULL;
1011*95ad37f9SFrank van der Linden 	INIT_WORK(&cache->work, nfs4_xattr_discard_cache_worker);
1012*95ad37f9SFrank van der Linden 	INIT_LIST_HEAD(&cache->lru);
1013*95ad37f9SFrank van der Linden 	INIT_LIST_HEAD(&cache->dispose);
1014*95ad37f9SFrank van der Linden }
1015*95ad37f9SFrank van der Linden 
1016*95ad37f9SFrank van der Linden int __init nfs4_xattr_cache_init(void)
1017*95ad37f9SFrank van der Linden {
1018*95ad37f9SFrank van der Linden 	int ret = 0;
1019*95ad37f9SFrank van der Linden 
1020*95ad37f9SFrank van der Linden 	nfs4_xattr_cache_cachep = kmem_cache_create("nfs4_xattr_cache_cache",
1021*95ad37f9SFrank van der Linden 	    sizeof(struct nfs4_xattr_cache), 0,
1022*95ad37f9SFrank van der Linden 	    (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|SLAB_ACCOUNT),
1023*95ad37f9SFrank van der Linden 	    nfs4_xattr_cache_init_once);
1024*95ad37f9SFrank van der Linden 	if (nfs4_xattr_cache_cachep == NULL)
1025*95ad37f9SFrank van der Linden 		return -ENOMEM;
1026*95ad37f9SFrank van der Linden 
1027*95ad37f9SFrank van der Linden 	ret = list_lru_init_memcg(&nfs4_xattr_large_entry_lru,
1028*95ad37f9SFrank van der Linden 	    &nfs4_xattr_large_entry_shrinker);
1029*95ad37f9SFrank van der Linden 	if (ret)
1030*95ad37f9SFrank van der Linden 		goto out4;
1031*95ad37f9SFrank van der Linden 
1032*95ad37f9SFrank van der Linden 	ret = list_lru_init_memcg(&nfs4_xattr_entry_lru,
1033*95ad37f9SFrank van der Linden 	    &nfs4_xattr_entry_shrinker);
1034*95ad37f9SFrank van der Linden 	if (ret)
1035*95ad37f9SFrank van der Linden 		goto out3;
1036*95ad37f9SFrank van der Linden 
1037*95ad37f9SFrank van der Linden 	ret = list_lru_init_memcg(&nfs4_xattr_cache_lru,
1038*95ad37f9SFrank van der Linden 	    &nfs4_xattr_cache_shrinker);
1039*95ad37f9SFrank van der Linden 	if (ret)
1040*95ad37f9SFrank van der Linden 		goto out2;
1041*95ad37f9SFrank van der Linden 
1042*95ad37f9SFrank van der Linden 	nfs4_xattr_cache_wq = alloc_workqueue("nfs4_xattr", WQ_MEM_RECLAIM, 0);
1043*95ad37f9SFrank van der Linden 	if (nfs4_xattr_cache_wq == NULL)
1044*95ad37f9SFrank van der Linden 		goto out1;
1045*95ad37f9SFrank van der Linden 
1046*95ad37f9SFrank van der Linden 	ret = register_shrinker(&nfs4_xattr_cache_shrinker);
1047*95ad37f9SFrank van der Linden 	if (ret)
1048*95ad37f9SFrank van der Linden 		goto out0;
1049*95ad37f9SFrank van der Linden 
1050*95ad37f9SFrank van der Linden 	ret = register_shrinker(&nfs4_xattr_entry_shrinker);
1051*95ad37f9SFrank van der Linden 	if (ret)
1052*95ad37f9SFrank van der Linden 		goto out;
1053*95ad37f9SFrank van der Linden 
1054*95ad37f9SFrank van der Linden 	ret = register_shrinker(&nfs4_xattr_large_entry_shrinker);
1055*95ad37f9SFrank van der Linden 	if (!ret)
1056*95ad37f9SFrank van der Linden 		return 0;
1057*95ad37f9SFrank van der Linden 
1058*95ad37f9SFrank van der Linden 	unregister_shrinker(&nfs4_xattr_entry_shrinker);
1059*95ad37f9SFrank van der Linden out:
1060*95ad37f9SFrank van der Linden 	unregister_shrinker(&nfs4_xattr_cache_shrinker);
1061*95ad37f9SFrank van der Linden out0:
1062*95ad37f9SFrank van der Linden 	destroy_workqueue(nfs4_xattr_cache_wq);
1063*95ad37f9SFrank van der Linden out1:
1064*95ad37f9SFrank van der Linden 	list_lru_destroy(&nfs4_xattr_cache_lru);
1065*95ad37f9SFrank van der Linden out2:
1066*95ad37f9SFrank van der Linden 	list_lru_destroy(&nfs4_xattr_entry_lru);
1067*95ad37f9SFrank van der Linden out3:
1068*95ad37f9SFrank van der Linden 	list_lru_destroy(&nfs4_xattr_large_entry_lru);
1069*95ad37f9SFrank van der Linden out4:
1070*95ad37f9SFrank van der Linden 	kmem_cache_destroy(nfs4_xattr_cache_cachep);
1071*95ad37f9SFrank van der Linden 
1072*95ad37f9SFrank van der Linden 	return ret;
1073*95ad37f9SFrank van der Linden }
1074*95ad37f9SFrank van der Linden 
1075*95ad37f9SFrank van der Linden void nfs4_xattr_cache_exit(void)
1076*95ad37f9SFrank van der Linden {
1077*95ad37f9SFrank van der Linden 	unregister_shrinker(&nfs4_xattr_entry_shrinker);
1078*95ad37f9SFrank van der Linden 	unregister_shrinker(&nfs4_xattr_cache_shrinker);
1079*95ad37f9SFrank van der Linden 	list_lru_destroy(&nfs4_xattr_entry_lru);
1080*95ad37f9SFrank van der Linden 	list_lru_destroy(&nfs4_xattr_cache_lru);
1081*95ad37f9SFrank van der Linden 	kmem_cache_destroy(nfs4_xattr_cache_cachep);
1082*95ad37f9SFrank van der Linden 	destroy_workqueue(nfs4_xattr_cache_wq);
1083*95ad37f9SFrank van der Linden }
1084