1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 30*7c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h> 31*7c478bd9Sstevel@tonic-gate #include <nfs/rnode4.h> 32*7c478bd9Sstevel@tonic-gate #include <nfs/nfs4_clnt.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* 36*7c478bd9Sstevel@tonic-gate * Access cache 37*7c478bd9Sstevel@tonic-gate */ 38*7c478bd9Sstevel@tonic-gate static acache4_hash_t *acache4; 39*7c478bd9Sstevel@tonic-gate static long nacache; /* used strictly to size the number of hash queues */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate static int acache4size; 42*7c478bd9Sstevel@tonic-gate static int acache4mask; 43*7c478bd9Sstevel@tonic-gate static struct kmem_cache *acache4_cache; 44*7c478bd9Sstevel@tonic-gate static int acache4_hashlen = 4; 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * This probably needs to be larger than or equal to 48*7c478bd9Sstevel@tonic-gate * log2(sizeof (struct rnode)) due to the way that rnodes are 49*7c478bd9Sstevel@tonic-gate * allocated. 50*7c478bd9Sstevel@tonic-gate */ 51*7c478bd9Sstevel@tonic-gate #define ACACHE4_SHIFT_BITS 9 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate static int 54*7c478bd9Sstevel@tonic-gate acache4hash(rnode4_t *rp, cred_t *cred) 55*7c478bd9Sstevel@tonic-gate { 56*7c478bd9Sstevel@tonic-gate return ((((intptr_t)rp >> ACACHE4_SHIFT_BITS) + crgetuid(cred)) & 57*7c478bd9Sstevel@tonic-gate acache4mask); 58*7c478bd9Sstevel@tonic-gate } 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 61*7c478bd9Sstevel@tonic-gate static long nfs4_access_cache_hits = 0; 62*7c478bd9Sstevel@tonic-gate static long nfs4_access_cache_misses = 0; 63*7c478bd9Sstevel@tonic-gate #endif 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate nfs4_access_type_t 66*7c478bd9Sstevel@tonic-gate nfs4_access_check(rnode4_t *rp, uint32_t acc, cred_t *cr) 67*7c478bd9Sstevel@tonic-gate { 68*7c478bd9Sstevel@tonic-gate acache4_t *ap; 69*7c478bd9Sstevel@tonic-gate acache4_hash_t *hp; 70*7c478bd9Sstevel@tonic-gate nfs4_access_type_t all; 71*7c478bd9Sstevel@tonic-gate vnode_t *vp; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate vp = RTOV4(rp); 74*7c478bd9Sstevel@tonic-gate if (!ATTRCACHE4_VALID(vp) || nfs4_waitfor_purge_complete(vp)) 75*7c478bd9Sstevel@tonic-gate return (NFS4_ACCESS_UNKNOWN); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate if (rp->r_acache != NULL) { 78*7c478bd9Sstevel@tonic-gate hp = &acache4[acache4hash(rp, cr)]; 79*7c478bd9Sstevel@tonic-gate rw_enter(&hp->lock, RW_READER); 80*7c478bd9Sstevel@tonic-gate ap = hp->next; 81*7c478bd9Sstevel@tonic-gate while (ap != (acache4_t *)hp) { 82*7c478bd9Sstevel@tonic-gate if (crcmp(ap->cred, cr) == 0 && ap->rnode == rp) { 83*7c478bd9Sstevel@tonic-gate if ((ap->known & acc) == acc) { 84*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 85*7c478bd9Sstevel@tonic-gate nfs4_access_cache_hits++; 86*7c478bd9Sstevel@tonic-gate #endif 87*7c478bd9Sstevel@tonic-gate if ((ap->allowed & acc) == acc) 88*7c478bd9Sstevel@tonic-gate all = NFS4_ACCESS_ALLOWED; 89*7c478bd9Sstevel@tonic-gate else 90*7c478bd9Sstevel@tonic-gate all = NFS4_ACCESS_DENIED; 91*7c478bd9Sstevel@tonic-gate } else { 92*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 93*7c478bd9Sstevel@tonic-gate nfs4_access_cache_misses++; 94*7c478bd9Sstevel@tonic-gate #endif 95*7c478bd9Sstevel@tonic-gate all = NFS4_ACCESS_UNKNOWN; 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate rw_exit(&hp->lock); 98*7c478bd9Sstevel@tonic-gate return (all); 99*7c478bd9Sstevel@tonic-gate } 100*7c478bd9Sstevel@tonic-gate ap = ap->next; 101*7c478bd9Sstevel@tonic-gate } 102*7c478bd9Sstevel@tonic-gate rw_exit(&hp->lock); 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 106*7c478bd9Sstevel@tonic-gate nfs4_access_cache_misses++; 107*7c478bd9Sstevel@tonic-gate #endif 108*7c478bd9Sstevel@tonic-gate return (NFS4_ACCESS_UNKNOWN); 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate void 112*7c478bd9Sstevel@tonic-gate nfs4_access_cache(rnode4_t *rp, uint32_t acc, uint32_t resacc, cred_t *cr) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate acache4_t *ap; 115*7c478bd9Sstevel@tonic-gate acache4_t *nap; 116*7c478bd9Sstevel@tonic-gate acache4_hash_t *hp; 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate hp = &acache4[acache4hash(rp, cr)]; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* 121*7c478bd9Sstevel@tonic-gate * Allocate now assuming that mostly an allocation will be 122*7c478bd9Sstevel@tonic-gate * required. This allows the allocation to happen without 123*7c478bd9Sstevel@tonic-gate * holding the hash bucket locked. 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate nap = kmem_cache_alloc(acache4_cache, KM_NOSLEEP); 126*7c478bd9Sstevel@tonic-gate if (nap != NULL) { 127*7c478bd9Sstevel@tonic-gate nap->known = acc; 128*7c478bd9Sstevel@tonic-gate nap->allowed = resacc; 129*7c478bd9Sstevel@tonic-gate nap->rnode = rp; 130*7c478bd9Sstevel@tonic-gate crhold(cr); 131*7c478bd9Sstevel@tonic-gate nap->cred = cr; 132*7c478bd9Sstevel@tonic-gate nap->hashq = hp; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate rw_enter(&hp->lock, RW_WRITER); 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate if (rp->r_acache != NULL) { 138*7c478bd9Sstevel@tonic-gate ap = hp->next; 139*7c478bd9Sstevel@tonic-gate while (ap != (acache4_t *)hp) { 140*7c478bd9Sstevel@tonic-gate if (crcmp(ap->cred, cr) == 0 && ap->rnode == rp) { 141*7c478bd9Sstevel@tonic-gate ap->known |= acc; 142*7c478bd9Sstevel@tonic-gate ap->allowed &= ~acc; 143*7c478bd9Sstevel@tonic-gate ap->allowed |= resacc; 144*7c478bd9Sstevel@tonic-gate rw_exit(&hp->lock); 145*7c478bd9Sstevel@tonic-gate if (nap != NULL) { 146*7c478bd9Sstevel@tonic-gate crfree(nap->cred); 147*7c478bd9Sstevel@tonic-gate kmem_cache_free(acache4_cache, nap); 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate return; 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate ap = ap->next; 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate if (nap != NULL) { 156*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 157*7c478bd9Sstevel@tonic-gate clstat4_debug.access.value.ui64++; 158*7c478bd9Sstevel@tonic-gate #endif 159*7c478bd9Sstevel@tonic-gate nap->next = hp->next; 160*7c478bd9Sstevel@tonic-gate hp->next = nap; 161*7c478bd9Sstevel@tonic-gate nap->next->prev = nap; 162*7c478bd9Sstevel@tonic-gate nap->prev = (acache4_t *)hp; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock); 165*7c478bd9Sstevel@tonic-gate nap->list = rp->r_acache; 166*7c478bd9Sstevel@tonic-gate rp->r_acache = nap; 167*7c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate rw_exit(&hp->lock); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate int 174*7c478bd9Sstevel@tonic-gate nfs4_access_purge_rp(rnode4_t *rp) 175*7c478bd9Sstevel@tonic-gate { 176*7c478bd9Sstevel@tonic-gate acache4_t *ap, *tmpap, *rplist; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* 179*7c478bd9Sstevel@tonic-gate * If there aren't any cached entries, then there is nothing 180*7c478bd9Sstevel@tonic-gate * to free. 181*7c478bd9Sstevel@tonic-gate */ 182*7c478bd9Sstevel@tonic-gate if (rp->r_acache == NULL) 183*7c478bd9Sstevel@tonic-gate return (0); 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate mutex_enter(&rp->r_statelock); 186*7c478bd9Sstevel@tonic-gate rplist = rp->r_acache; 187*7c478bd9Sstevel@tonic-gate rp->r_acache = NULL; 188*7c478bd9Sstevel@tonic-gate mutex_exit(&rp->r_statelock); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate /* 191*7c478bd9Sstevel@tonic-gate * Loop through each entry in the list pointed to in the 192*7c478bd9Sstevel@tonic-gate * rnode. Remove each of these entries from the hash 193*7c478bd9Sstevel@tonic-gate * queue that it is on and remove it from the list in 194*7c478bd9Sstevel@tonic-gate * the rnode. 195*7c478bd9Sstevel@tonic-gate */ 196*7c478bd9Sstevel@tonic-gate for (ap = rplist; ap != NULL; ap = tmpap) { 197*7c478bd9Sstevel@tonic-gate rw_enter(&ap->hashq->lock, RW_WRITER); 198*7c478bd9Sstevel@tonic-gate ap->prev->next = ap->next; 199*7c478bd9Sstevel@tonic-gate ap->next->prev = ap->prev; 200*7c478bd9Sstevel@tonic-gate rw_exit(&ap->hashq->lock); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate tmpap = ap->list; 203*7c478bd9Sstevel@tonic-gate crfree(ap->cred); 204*7c478bd9Sstevel@tonic-gate kmem_cache_free(acache4_cache, ap); 205*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 206*7c478bd9Sstevel@tonic-gate clstat4_debug.access.value.ui64--; 207*7c478bd9Sstevel@tonic-gate #endif 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate return (1); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate int 214*7c478bd9Sstevel@tonic-gate nfs4_acache_init(void) 215*7c478bd9Sstevel@tonic-gate { 216*7c478bd9Sstevel@tonic-gate extern int rtable4size; 217*7c478bd9Sstevel@tonic-gate int i; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate /* 220*7c478bd9Sstevel@tonic-gate * Initial guess is one access cache entry per rnode unless 221*7c478bd9Sstevel@tonic-gate * nacache is set to a non-zero value and then it is used to 222*7c478bd9Sstevel@tonic-gate * indicate a guess at the number of access cache entries. 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate if (nacache > 0) 225*7c478bd9Sstevel@tonic-gate acache4size = 1 << highbit(nacache / acache4_hashlen); 226*7c478bd9Sstevel@tonic-gate else 227*7c478bd9Sstevel@tonic-gate acache4size = rtable4size; 228*7c478bd9Sstevel@tonic-gate acache4mask = acache4size - 1; 229*7c478bd9Sstevel@tonic-gate acache4 = kmem_alloc(acache4size * sizeof (*acache4), KM_SLEEP); 230*7c478bd9Sstevel@tonic-gate for (i = 0; i < acache4size; i++) { 231*7c478bd9Sstevel@tonic-gate acache4[i].next = (acache4_t *)&acache4[i]; 232*7c478bd9Sstevel@tonic-gate acache4[i].prev = (acache4_t *)&acache4[i]; 233*7c478bd9Sstevel@tonic-gate rw_init(&acache4[i].lock, NULL, RW_DEFAULT, NULL); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate acache4_cache = kmem_cache_create("nfs4_access_cache", 236*7c478bd9Sstevel@tonic-gate sizeof (acache4_t), 0, NULL, NULL, NULL, NULL, NULL, 0); 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate return (0); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate int 242*7c478bd9Sstevel@tonic-gate nfs4_acache_fini(void) 243*7c478bd9Sstevel@tonic-gate { 244*7c478bd9Sstevel@tonic-gate int i; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* 247*7c478bd9Sstevel@tonic-gate * Deallocated the access cache 248*7c478bd9Sstevel@tonic-gate */ 249*7c478bd9Sstevel@tonic-gate kmem_cache_destroy(acache4_cache); 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate for (i = 0; i < acache4size; i++) 252*7c478bd9Sstevel@tonic-gate rw_destroy(&acache4[i].lock); 253*7c478bd9Sstevel@tonic-gate kmem_free(acache4, acache4size * sizeof (*acache4)); 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate return (0); 256*7c478bd9Sstevel@tonic-gate } 257