4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <nfs/rnode4.h>
32 #include <nfs/nfs4_clnt.h>
33 #include <sys/bitmap.h>
38 static acache4_hash_t
*acache4
;
39 static long nacache
; /* used strictly to size the number of hash queues */
41 static int acache4size
;
42 static int acache4mask
;
43 static struct kmem_cache
*acache4_cache
;
44 static int acache4_hashlen
= 4;
47 * This probably needs to be larger than or equal to
48 * log2(sizeof (struct rnode)) due to the way that rnodes are
51 #define ACACHE4_SHIFT_BITS 9
54 acache4hash(rnode4_t
*rp
, cred_t
*cred
)
56 return ((((intptr_t)rp
>> ACACHE4_SHIFT_BITS
) + crgetuid(cred
)) &
61 static long nfs4_access_cache_hits
= 0;
62 static long nfs4_access_cache_misses
= 0;
66 nfs4_access_check(rnode4_t
*rp
, uint32_t acc
, cred_t
*cr
)
70 nfs4_access_type_t all
;
74 if (!ATTRCACHE4_VALID(vp
) || nfs4_waitfor_purge_complete(vp
))
75 return (NFS4_ACCESS_UNKNOWN
);
77 if (rp
->r_acache
!= NULL
) {
78 hp
= &acache4
[acache4hash(rp
, cr
)];
79 rw_enter(&hp
->lock
, RW_READER
);
81 while (ap
!= (acache4_t
*)hp
) {
82 if (crcmp(ap
->cred
, cr
) == 0 && ap
->rnode
== rp
) {
83 if ((ap
->known
& acc
) == acc
) {
85 nfs4_access_cache_hits
++;
87 if ((ap
->allowed
& acc
) == acc
)
88 all
= NFS4_ACCESS_ALLOWED
;
90 all
= NFS4_ACCESS_DENIED
;
93 nfs4_access_cache_misses
++;
95 all
= NFS4_ACCESS_UNKNOWN
;
106 nfs4_access_cache_misses
++;
108 return (NFS4_ACCESS_UNKNOWN
);
112 nfs4_access_cache(rnode4_t
*rp
, uint32_t acc
, uint32_t resacc
, cred_t
*cr
)
118 hp
= &acache4
[acache4hash(rp
, cr
)];
121 * Allocate now assuming that mostly an allocation will be
122 * required. This allows the allocation to happen without
123 * holding the hash bucket locked.
125 nap
= kmem_cache_alloc(acache4_cache
, KM_NOSLEEP
);
128 nap
->allowed
= resacc
;
135 rw_enter(&hp
->lock
, RW_WRITER
);
137 if (rp
->r_acache
!= NULL
) {
139 while (ap
!= (acache4_t
*)hp
) {
140 if (crcmp(ap
->cred
, cr
) == 0 && ap
->rnode
== rp
) {
143 ap
->allowed
|= resacc
;
147 kmem_cache_free(acache4_cache
, nap
);
157 clstat4_debug
.access
.value
.ui64
++;
159 nap
->next
= hp
->next
;
161 nap
->next
->prev
= nap
;
162 nap
->prev
= (acache4_t
*)hp
;
164 mutex_enter(&rp
->r_statelock
);
165 nap
->list
= rp
->r_acache
;
167 mutex_exit(&rp
->r_statelock
);
174 nfs4_access_purge_rp(rnode4_t
*rp
)
176 acache4_t
*ap
, *tmpap
, *rplist
;
179 * If there aren't any cached entries, then there is nothing
182 if (rp
->r_acache
== NULL
)
185 mutex_enter(&rp
->r_statelock
);
186 rplist
= rp
->r_acache
;
188 mutex_exit(&rp
->r_statelock
);
191 * Loop through each entry in the list pointed to in the
192 * rnode. Remove each of these entries from the hash
193 * queue that it is on and remove it from the list in
196 for (ap
= rplist
; ap
!= NULL
; ap
= tmpap
) {
197 rw_enter(&ap
->hashq
->lock
, RW_WRITER
);
198 ap
->prev
->next
= ap
->next
;
199 ap
->next
->prev
= ap
->prev
;
200 rw_exit(&ap
->hashq
->lock
);
204 kmem_cache_free(acache4_cache
, ap
);
206 clstat4_debug
.access
.value
.ui64
--;
214 nfs4_acache_init(void)
216 extern int rtable4size
;
220 * Initial guess is one access cache entry per rnode unless
221 * nacache is set to a non-zero value and then it is used to
222 * indicate a guess at the number of access cache entries.
225 acache4size
= 1 << highbit(nacache
/ acache4_hashlen
);
227 acache4size
= rtable4size
;
228 acache4mask
= acache4size
- 1;
229 acache4
= kmem_alloc(acache4size
* sizeof (*acache4
), KM_SLEEP
);
230 for (i
= 0; i
< acache4size
; i
++) {
231 acache4
[i
].next
= (acache4_t
*)&acache4
[i
];
232 acache4
[i
].prev
= (acache4_t
*)&acache4
[i
];
233 rw_init(&acache4
[i
].lock
, NULL
, RW_DEFAULT
, NULL
);
235 acache4_cache
= kmem_cache_create("nfs4_access_cache",
236 sizeof (acache4_t
), 0, NULL
, NULL
, NULL
, NULL
, NULL
, 0);
242 nfs4_acache_fini(void)
247 * Deallocated the access cache
249 kmem_cache_destroy(acache4_cache
);
251 for (i
= 0; i
< acache4size
; i
++)
252 rw_destroy(&acache4
[i
].lock
);
253 kmem_free(acache4
, acache4size
* sizeof (*acache4
));