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