^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Request reply cache. This is currently a global cache, but this may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * change in the future and be a per-client cache.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This code is heavily inspired by the 44BSD implementation, although
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * it does things a bit differently.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/sunrpc/svc_xprt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/sunrpc/addr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/highmem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/hash.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <net/checksum.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "nfsd.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "cache.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "trace.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * We use this value to determine the number of hash buckets from the max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * cache size, the idea being that when the cache is at its maximum number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * of entries, then this should be the average number of entries per bucket.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define TARGET_BUCKET_SIZE 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct nfsd_drc_bucket {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct rb_root rb_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct list_head lru_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) spinlock_t cache_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static struct kmem_cache *drc_slab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static unsigned long nfsd_reply_cache_count(struct shrinker *shrink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct shrink_control *sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct shrink_control *sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * Put a cap on the size of the DRC based on the amount of available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * low memory in the machine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * 64MB: 8192
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * 128MB: 11585
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * 256MB: 16384
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * 512MB: 23170
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * 1GB: 32768
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * 2GB: 46340
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * 4GB: 65536
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * 8GB: 92681
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * 16GB: 131072
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * ...with a hard cap of 256k entries. In the worst case, each entry will be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * ~1k, so the above numbers should give a rough max of the amount of memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * used in k.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * XXX: these limits are per-container, so memory used will increase
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * linearly with number of containers. Maybe that's OK.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static unsigned int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) nfsd_cache_size_limit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned int limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) unsigned long low_pages = totalram_pages() - totalhigh_pages();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) limit = (16 * int_sqrt(low_pages)) << (PAGE_SHIFT-10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return min_t(unsigned int, limit, 256*1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Compute the number of hash buckets we need. Divide the max cachesize by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * the "target" max bucket size, and round up to next power of two.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static unsigned int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) nfsd_hashsize(unsigned int limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return roundup_pow_of_two(limit / TARGET_BUCKET_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static u32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) nfsd_cache_hash(__be32 xid, struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return hash_32(be32_to_cpu(xid), nn->maskbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static struct svc_cacherep *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct svc_cacherep *rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) rp = kmem_cache_alloc(drc_slab, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (rp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) rp->c_state = RC_UNUSED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) rp->c_type = RC_NOCACHE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) RB_CLEAR_NODE(&rp->c_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) INIT_LIST_HEAD(&rp->c_lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) memset(&rp->c_key, 0, sizeof(rp->c_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) rp->c_key.k_xid = rqstp->rq_xid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) rp->c_key.k_proc = rqstp->rq_proc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) rpc_copy_addr((struct sockaddr *)&rp->c_key.k_addr, svc_addr(rqstp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) rpc_set_port((struct sockaddr *)&rp->c_key.k_addr, rpc_get_port(svc_addr(rqstp)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) rp->c_key.k_prot = rqstp->rq_prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) rp->c_key.k_vers = rqstp->rq_vers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) rp->c_key.k_len = rqstp->rq_arg.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) rp->c_key.k_csum = csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) nfsd_reply_cache_free_locked(struct nfsd_drc_bucket *b, struct svc_cacherep *rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) nn->drc_mem_usage -= rp->c_replvec.iov_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) kfree(rp->c_replvec.iov_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (rp->c_state != RC_UNUSED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) rb_erase(&rp->c_node, &b->rb_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) list_del(&rp->c_lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) atomic_dec(&nn->num_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) nn->drc_mem_usage -= sizeof(*rp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) kmem_cache_free(drc_slab, rp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) nfsd_reply_cache_free(struct nfsd_drc_bucket *b, struct svc_cacherep *rp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) spin_lock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) nfsd_reply_cache_free_locked(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) spin_unlock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int nfsd_drc_slab_create(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) drc_slab = kmem_cache_create("nfsd_drc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) sizeof(struct svc_cacherep), 0, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return drc_slab ? 0: -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) void nfsd_drc_slab_free(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) kmem_cache_destroy(drc_slab);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) int nfsd_reply_cache_init(struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) unsigned int hashsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) nn->max_drc_entries = nfsd_cache_size_limit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) atomic_set(&nn->num_drc_entries, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) hashsize = nfsd_hashsize(nn->max_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) nn->maskbits = ilog2(hashsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) nn->nfsd_reply_cache_shrinker.scan_objects = nfsd_reply_cache_scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) nn->nfsd_reply_cache_shrinker.count_objects = nfsd_reply_cache_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) nn->nfsd_reply_cache_shrinker.seeks = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) status = register_shrinker(&nn->nfsd_reply_cache_shrinker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) goto out_nomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) nn->drc_hashtbl = kvzalloc(array_size(hashsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sizeof(*nn->drc_hashtbl)), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (!nn->drc_hashtbl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) goto out_shrinker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) for (i = 0; i < hashsize; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) spin_lock_init(&nn->drc_hashtbl[i].cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) nn->drc_hashsize = hashsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) out_shrinker:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) unregister_shrinker(&nn->nfsd_reply_cache_shrinker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) out_nomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) void nfsd_reply_cache_shutdown(struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct svc_cacherep *rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) unregister_shrinker(&nn->nfsd_reply_cache_shrinker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) for (i = 0; i < nn->drc_hashsize; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct list_head *head = &nn->drc_hashtbl[i].lru_head;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) while (!list_empty(head)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) rp = list_first_entry(head, struct svc_cacherep, c_lru);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) nfsd_reply_cache_free_locked(&nn->drc_hashtbl[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) kvfree(nn->drc_hashtbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) nn->drc_hashtbl = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) nn->drc_hashsize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * Move cache entry to end of LRU list, and queue the cleaner to run if it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * not already scheduled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) rp->c_timestamp = jiffies;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) list_move_tail(&rp->c_lru, &b->lru_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct svc_cacherep *rp, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) long freed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) list_for_each_entry_safe(rp, tmp, &b->lru_head, c_lru) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * Don't free entries attached to calls that are still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * in-progress, but do keep scanning the list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (rp->c_state == RC_INPROG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (atomic_read(&nn->num_drc_entries) <= nn->max_drc_entries &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) time_before(jiffies, rp->c_timestamp + RC_EXPIRE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) nfsd_reply_cache_free_locked(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) freed++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return freed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * Walk the LRU list and prune off entries that are older than RC_EXPIRE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * Also prune the oldest ones when the total exceeds the max number of entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) prune_cache_entries(struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) long freed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) for (i = 0; i < nn->drc_hashsize; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct nfsd_drc_bucket *b = &nn->drc_hashtbl[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (list_empty(&b->lru_head))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) spin_lock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) freed += prune_bucket(b, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) spin_unlock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return freed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) struct nfsd_net *nn = container_of(shrink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) struct nfsd_net, nfsd_reply_cache_shrinker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return atomic_read(&nn->num_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct nfsd_net *nn = container_of(shrink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct nfsd_net, nfsd_reply_cache_shrinker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return prune_cache_entries(nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * Walk an xdr_buf and get a CRC for at most the first RC_CSUMLEN bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static __wsum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) nfsd_cache_csum(struct svc_rqst *rqstp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) unsigned int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) __wsum csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct xdr_buf *buf = &rqstp->rq_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) const unsigned char *p = buf->head[0].iov_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) size_t csum_len = min_t(size_t, buf->head[0].iov_len + buf->page_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) RC_CSUMLEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) size_t len = min(buf->head[0].iov_len, csum_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* rq_arg.head first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) csum = csum_partial(p, len, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) csum_len -= len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* Continue into page array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) idx = buf->page_base / PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) base = buf->page_base & ~PAGE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) while (csum_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) p = page_address(buf->pages[idx]) + base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) len = min_t(size_t, PAGE_SIZE - base, csum_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) csum = csum_partial(p, len, csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) csum_len -= len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) base = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ++idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) nfsd_cache_key_cmp(const struct svc_cacherep *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) const struct svc_cacherep *rp, struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (key->c_key.k_xid == rp->c_key.k_xid &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) key->c_key.k_csum != rp->c_key.k_csum) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ++nn->payload_misses;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) trace_nfsd_drc_mismatch(nn, key, rp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return memcmp(&key->c_key, &rp->c_key, sizeof(key->c_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * Search the request hash for an entry that matches the given rqstp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * Must be called with cache_lock held. Returns the found entry or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * inserts an empty key on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static struct svc_cacherep *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct nfsd_net *nn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) struct svc_cacherep *rp, *ret = key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct rb_node **p = &b->rb_head.rb_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) *parent = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) unsigned int entries = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) int cmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) while (*p != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) ++entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) parent = *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) rp = rb_entry(parent, struct svc_cacherep, c_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) cmp = nfsd_cache_key_cmp(key, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (cmp < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) p = &parent->rb_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) else if (cmp > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) p = &parent->rb_right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) rb_link_node(&key->c_node, parent, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) rb_insert_color(&key->c_node, &b->rb_head);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /* tally hash chain length stats */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (entries > nn->longest_chain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) nn->longest_chain = entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) nn->longest_chain_cachesize = atomic_read(&nn->num_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) } else if (entries == nn->longest_chain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* prefer to keep the smallest cachesize possible here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) nn->longest_chain_cachesize = min_t(unsigned int,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) nn->longest_chain_cachesize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) atomic_read(&nn->num_drc_entries));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) lru_put_end(b, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * nfsd_cache_lookup - Find an entry in the duplicate reply cache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * @rqstp: Incoming Call to find
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * Try to find an entry matching the current call in the cache. When none
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * is found, we try to grab the oldest expired entry off the LRU list. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * a suitable one isn't there, then drop the cache_lock and allocate a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * new one, then search again in case one got inserted while this thread
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * didn't hold the lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * Return values:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) * %RC_DOIT: Process the request normally
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * %RC_REPLY: Reply from cache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * %RC_DROPIT: Do not process the request further
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int nfsd_cache_lookup(struct svc_rqst *rqstp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct svc_cacherep *rp, *found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) __be32 xid = rqstp->rq_xid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) __wsum csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) u32 hash = nfsd_cache_hash(xid, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct nfsd_drc_bucket *b = &nn->drc_hashtbl[hash];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int type = rqstp->rq_cachetype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) int rtn = RC_DOIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) rqstp->rq_cacherep = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (type == RC_NOCACHE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) nfsdstats.rcnocache++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) csum = nfsd_cache_csum(rqstp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) * Since the common case is a cache miss followed by an insert,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * preallocate an entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) rp = nfsd_reply_cache_alloc(rqstp, csum, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (!rp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) spin_lock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) found = nfsd_cache_insert(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (found != rp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) nfsd_reply_cache_free_locked(NULL, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) rp = found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) goto found_entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) nfsdstats.rcmisses++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) rqstp->rq_cacherep = rp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) rp->c_state = RC_INPROG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) atomic_inc(&nn->num_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) nn->drc_mem_usage += sizeof(*rp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /* go ahead and prune the cache */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) prune_bucket(b, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) spin_unlock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return rtn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) found_entry:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) /* We found a matching entry which is either in progress or done. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) nfsdstats.rchits++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) rtn = RC_DROPIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) /* Request being processed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (rp->c_state == RC_INPROG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) goto out_trace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) /* From the hall of fame of impractical attacks:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * Is this a user who tries to snoop on the cache? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) rtn = RC_DOIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (!test_bit(RQ_SECURE, &rqstp->rq_flags) && rp->c_secure)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) goto out_trace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* Compose RPC reply header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) switch (rp->c_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) case RC_NOCACHE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) case RC_REPLSTAT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) svc_putu32(&rqstp->rq_res.head[0], rp->c_replstat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) rtn = RC_REPLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) case RC_REPLBUFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (!nfsd_cache_append(rqstp, &rp->c_replvec))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) goto out_unlock; /* should not happen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) rtn = RC_REPLY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) WARN_ONCE(1, "nfsd: bad repcache type %d\n", rp->c_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) out_trace:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) trace_nfsd_drc_found(nn, rqstp, rtn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * nfsd_cache_update - Update an entry in the duplicate reply cache.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * @rqstp: svc_rqst with a finished Reply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * @cachetype: which cache to update
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * @statp: Reply's status code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * This is called from nfsd_dispatch when the procedure has been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) * executed and the complete reply is in rqstp->rq_res.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * We're copying around data here rather than swapping buffers because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * the toplevel loop requires max-sized buffers, which would be a waste
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * of memory for a cache with a max reply size of 100 bytes (diropokres).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * If we should start to use different types of cache entries tailored
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * specifically for attrstat and fh's, we may save even more space.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * Also note that a cachetype of RC_NOCACHE can legally be passed when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * nfsd failed to encode a reply that otherwise would have been cached.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * In this case, nfsd_cache_update is called with statp == NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct svc_cacherep *rp = rqstp->rq_cacherep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct kvec *resv = &rqstp->rq_res.head[0], *cachv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) u32 hash;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct nfsd_drc_bucket *b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) size_t bufsize = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (!rp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) hash = nfsd_cache_hash(rp->c_key.k_xid, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) b = &nn->drc_hashtbl[hash];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) len = resv->iov_len - ((char*)statp - (char*)resv->iov_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) len >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* Don't cache excessive amounts of data and XDR failures */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (!statp || len > (256 >> 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) nfsd_reply_cache_free(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) switch (cachetype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) case RC_REPLSTAT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (len != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) printk("nfsd: RC_REPLSTAT/reply len %d!\n",len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) rp->c_replstat = *statp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) case RC_REPLBUFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) cachv = &rp->c_replvec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) bufsize = len << 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) cachv->iov_base = kmalloc(bufsize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (!cachv->iov_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) nfsd_reply_cache_free(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) cachv->iov_len = bufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) memcpy(cachv->iov_base, statp, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) case RC_NOCACHE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) nfsd_reply_cache_free(b, rp, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) spin_lock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) nn->drc_mem_usage += bufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) lru_put_end(b, rp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) rp->c_secure = test_bit(RQ_SECURE, &rqstp->rq_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) rp->c_type = cachetype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) rp->c_state = RC_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) spin_unlock(&b->cache_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * Copy cached reply to current reply buffer. Should always fit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * FIXME as reply is in a page, we should just attach the page, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * keep a refcount....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) struct kvec *vec = &rqstp->rq_res.head[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (vec->iov_len + data->iov_len > PAGE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) printk(KERN_WARNING "nfsd: cached reply too large (%zd).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) data->iov_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) memcpy((char*)vec->iov_base + vec->iov_len, data->iov_base, data->iov_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) vec->iov_len += data->iov_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * Note that fields may be added, removed or reordered in the future. Programs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) * scraping this file for info should test the labels to ensure they're
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) * getting the correct field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) struct nfsd_net *nn = m->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) seq_printf(m, "max entries: %u\n", nn->max_drc_entries);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) seq_printf(m, "num entries: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) atomic_read(&nn->num_drc_entries));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) seq_printf(m, "hash buckets: %u\n", 1 << nn->maskbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) seq_printf(m, "mem usage: %u\n", nn->drc_mem_usage);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) seq_printf(m, "cache hits: %u\n", nfsdstats.rchits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) seq_printf(m, "cache misses: %u\n", nfsdstats.rcmisses);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) seq_printf(m, "not cached: %u\n", nfsdstats.rcnocache);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) seq_printf(m, "payload misses: %u\n", nn->payload_misses);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) seq_printf(m, "longest chain len: %u\n", nn->longest_chain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) seq_printf(m, "cachesize at longest: %u\n", nn->longest_chain_cachesize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) int nfsd_reply_cache_stats_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct nfsd_net *nn = net_generic(file_inode(file)->i_sb->s_fs_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) nfsd_net_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return single_open(file, nfsd_reply_cache_stats_show, nn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }