2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afs/param.h>
24 * This next lock controls access to all cm_aclent structures in the system,
25 * in either the free list or in the LRU queue. A read lock prevents someone
26 * from modifying the list(s), and a write lock is required for modifying
27 * the list. The actual data stored in the randomUid and randomAccess fields
28 * is actually maintained as up-to-date or not via the scache lock.
29 * An aclent structure is free if it has no back vnode pointer.
31 osi_rwlock_t cm_aclLock; /* lock for system's aclents */
33 /* This must be called with cm_aclLock and the aclp->back->mx held */
34 static void CleanupACLEnt(cm_aclent_t * aclp)
40 if (aclp->backp->randomACLp) {
42 * Remove the entry from the vnode's list
44 lock_AssertMutex(&aclp->backp->mx);
45 laclpp = &aclp->backp->randomACLp;
46 for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
51 osi_panic("CleanupACLEnt race", __FILE__, __LINE__);
52 *laclpp = aclp->nextp; /* remove from vnode list */
57 /* release the old user */
59 cm_ReleaseUser(aclp->userp);
63 aclp->randomAccess = 0;
64 aclp->tgtLifetime = 0;
68 * Get an acl cache entry for a particular user and file, or return that it doesn't exist.
69 * Called with the scp locked.
71 long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp)
76 lock_ObtainWrite(&cm_aclLock);
77 *rightsp = 0; /* get a new acl from server if we don't find a
81 for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
82 if (aclp->userp == userp) {
83 if (aclp->tgtLifetime && aclp->tgtLifetime <= osi_Time()) {
85 osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
88 /* move to the tail of the LRU queue */
89 osi_QAddT((osi_queue_t **) &cm_data.aclLRUp,
90 (osi_queue_t **) &cm_data.aclLRUEndp,
93 *rightsp = aclp->randomAccess;
94 if (cm_data.aclLRUEndp == aclp)
95 cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
97 /* move to the head of the LRU queue */
98 osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
99 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
100 (osi_queue_t **) &cm_data.aclLRUEndp,
102 retval = 0; /* success */
108 lock_ReleaseWrite(&cm_aclLock);
113 * This function returns a free (not in the LRU queue) acl cache entry.
114 * It must be called with the cm_aclLock lock held
116 static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp)
119 cm_scache_t *ascp = 0;
121 if (cm_data.aclLRUp == NULL)
122 osi_panic("empty aclent LRU", __FILE__, __LINE__);
124 aclp = cm_data.aclLRUEndp;
125 cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q);
126 osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q);
128 if (aclp->backp && scp != aclp->backp) {
130 lock_ReleaseWrite(&cm_aclLock);
131 lock_ObtainMutex(&ascp->mx);
132 lock_ObtainWrite(&cm_aclLock);
137 lock_ReleaseMutex(&ascp->mx);
143 * Add rights to an acl cache entry. Do the right thing if not present,
144 * including digging up an entry from the LRU queue.
146 * The scp must be locked when this function is called.
148 long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights)
150 register struct cm_aclent *aclp;
152 lock_ObtainWrite(&cm_aclLock);
153 for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
154 if (aclp->userp == userp) {
155 aclp->randomAccess = rights;
156 if (aclp->tgtLifetime == 0)
157 aclp->tgtLifetime = cm_TGTLifeTime(pag);
158 lock_ReleaseWrite(&cm_aclLock);
164 * Didn't find the dude we're looking for, so take someone from the LRUQ
165 * and reuse. But first try the free list and see if there's already
168 aclp = GetFreeACLEnt(scp); /* can't fail, panics instead */
169 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
171 aclp->nextp = scp->randomACLp;
172 scp->randomACLp = aclp;
175 aclp->randomAccess = rights;
176 aclp->tgtLifetime = cm_TGTLifeTime(userp);
177 lock_ReleaseWrite(&cm_aclLock);
182 long cm_ShutdownACLCache(void)
187 long cm_ValidateACLCache(void)
189 long size = cm_data.stats * 2;
193 if ( cm_data.aclLRUp == NULL && cm_data.aclLRUEndp != NULL ||
194 cm_data.aclLRUp != NULL && cm_data.aclLRUEndp == NULL) {
195 afsi_log("cm_ValidateACLCache failure: inconsistent LRU pointers");
196 fprintf(stderr, "cm_ValidateACLCache failure: inconsistent LRU pointers\n");
200 for ( aclp = cm_data.aclLRUp, count = 0; aclp;
201 aclp = (cm_aclent_t *) osi_QNext(&aclp->q), count++ ) {
202 if (aclp->magic != CM_ACLENT_MAGIC) {
203 afsi_log("cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC");
204 fprintf(stderr, "cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC\n");
207 if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
208 afsi_log("cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC");
209 fprintf(stderr,"cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC\n");
212 if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
213 afsi_log("cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC");
214 fprintf(stderr,"cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC\n");
217 if (count != 0 && aclp == cm_data.aclLRUp || count > size) {
218 afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUp list");
219 fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUp list\n");
224 for ( aclp = cm_data.aclLRUEndp, count = 0; aclp;
225 aclp = (cm_aclent_t *) osi_QPrev(&aclp->q), count++ ) {
226 if (aclp->magic != CM_ACLENT_MAGIC) {
227 afsi_log("cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC");
228 fprintf(stderr, "cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC\n");
231 if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
232 afsi_log("cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC");
233 fprintf(stderr, "cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC\n");
236 if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
237 afsi_log("cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC");
238 fprintf(stderr, "cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC\n");
242 if (count != 0 && aclp == cm_data.aclLRUEndp || count > size) {
243 afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list");
244 fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list\n");
253 * Initialize the cache to have an entries. Called during system startup.
255 long cm_InitACLCache(int newFile, long size)
259 static osi_once_t once;
261 if (osi_Once(&once)) {
262 lock_InitializeRWLock(&cm_aclLock, "cm_aclLock");
266 lock_ObtainWrite(&cm_aclLock);
268 cm_data.aclLRUp = cm_data.aclLRUEndp = NULL;
269 aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
270 memset(aclp, 0, size * sizeof(cm_aclent_t));
273 * Put all of these guys on the LRU queue
275 for (i = 0; i < size; i++) {
276 aclp->magic = CM_ACLENT_MAGIC;
277 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
281 aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
282 for (i = 0; i < size; i++) {
284 aclp->tgtLifetime = 0;
288 lock_ReleaseWrite(&cm_aclLock);
294 * Free all associated acl entries. We actually just clear the back pointer
295 * since the acl entries are already in the free list. The scp must be locked
296 * or completely unreferenced (such as when called while recycling the scp).
298 void cm_FreeAllACLEnts(cm_scache_t *scp)
303 lock_ObtainWrite(&cm_aclLock);
304 for (aclp = scp->randomACLp; aclp; aclp = taclp) {
307 cm_ReleaseUser(aclp->userp);
310 aclp->backp = (struct cm_scache *) 0;
313 scp->randomACLp = (struct cm_aclent *) 0;
314 scp->anyAccess = 0; /* reset this, too */
315 lock_ReleaseWrite(&cm_aclLock);
320 * Invalidate all ACL entries for particular user on this particular vnode.
322 * The scp must be locked.
324 void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
327 cm_aclent_t **laclpp;
329 lock_ObtainWrite(&cm_aclLock);
330 laclpp = &scp->randomACLp;
331 for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) {
332 if (userp == aclp->userp) { /* One for a given user/scache */
333 *laclpp = aclp->nextp;
334 cm_ReleaseUser(aclp->userp);
336 aclp->backp = (struct cm_scache *) 0;
340 lock_ReleaseWrite(&cm_aclLock);