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>
21 * This next lock controls access to all cm_aclent structures in the system,
22 * in either the free list or in the LRU queue. A read lock prevents someone
23 * from modifying the list(s), and a write lock is required for modifying
24 * the list. The actual data stored in the randomUid and randomAccess fields
25 * is actually maintained as up-to-date or not via the scache lock.
26 * An aclent structure is free if it has no back vnode pointer.
28 osi_rwlock_t cm_aclLock; /* lock for system's aclents */
30 /* This must be called with cm_aclLock and the aclp->back->mx held */
31 static void CleanupACLEnt(cm_aclent_t * aclp)
37 if (aclp->backp->randomACLp) {
39 * Remove the entry from the vnode's list
41 lock_AssertWrite(&aclp->backp->rw);
42 laclpp = &aclp->backp->randomACLp;
43 for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) {
48 osi_panic("CleanupACLEnt race", __FILE__, __LINE__);
49 *laclpp = aclp->nextp; /* remove from vnode list */
54 /* release the old user */
56 cm_ReleaseUser(aclp->userp);
60 aclp->randomAccess = 0;
61 aclp->tgtLifetime = 0;
65 * Get an acl cache entry for a particular user and file, or return that it doesn't exist.
66 * Called with the scp locked.
68 long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 *rightsp)
73 lock_ObtainWrite(&cm_aclLock);
74 *rightsp = 0; /* get a new acl from server if we don't find a
78 for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
79 if (aclp->userp == userp) {
80 if (aclp->tgtLifetime && aclp->tgtLifetime <= time(NULL)) {
82 osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
85 /* move to the tail of the LRU queue */
86 osi_QAddT((osi_queue_t **) &cm_data.aclLRUp,
87 (osi_queue_t **) &cm_data.aclLRUEndp,
90 *rightsp = aclp->randomAccess;
91 if (cm_data.aclLRUp != aclp) {
92 /* move to the head of the LRU queue */
93 osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
94 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp,
95 (osi_queue_t **) &cm_data.aclLRUEndp,
98 retval = 0; /* success */
104 lock_ReleaseWrite(&cm_aclLock);
109 * This function returns a free (not in the LRU queue) acl cache entry.
110 * It must be called with the cm_aclLock lock held
112 static cm_aclent_t *GetFreeACLEnt(cm_scache_t * scp)
115 cm_scache_t *ascp = 0;
117 if (cm_data.aclLRUp == NULL)
118 osi_panic("empty aclent LRU", __FILE__, __LINE__);
120 if (cm_data.aclLRUEndp == NULL)
121 osi_panic("inconsistent aclent LRUEndp == NULL", __FILE__, __LINE__);
123 aclp = cm_data.aclLRUEndp;
124 osi_QRemoveHT((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
126 if (aclp->backp && scp != aclp->backp) {
128 lock_ReleaseWrite(&cm_aclLock);
129 lock_ObtainWrite(&ascp->rw);
130 lock_ObtainWrite(&cm_aclLock);
135 lock_ReleaseWrite(&ascp->rw);
141 * Add rights to an acl cache entry. Do the right thing if not present,
142 * including digging up an entry from the LRU queue.
144 * The scp must be locked when this function is called.
146 long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, afs_uint32 rights)
148 struct cm_aclent *aclp;
150 lock_ObtainWrite(&cm_aclLock);
151 for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) {
152 if (aclp->userp == userp) {
153 aclp->randomAccess = rights;
154 if (aclp->tgtLifetime == 0)
155 aclp->tgtLifetime = cm_TGTLifeTime(pag);
156 lock_ReleaseWrite(&cm_aclLock);
162 * Didn't find the dude we're looking for, so take someone from the LRUQ
163 * and reuse. But first try the free list and see if there's already
166 aclp = GetFreeACLEnt(scp); /* can't fail, panics instead */
167 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
169 aclp->nextp = scp->randomACLp;
170 scp->randomACLp = aclp;
173 aclp->randomAccess = rights;
174 aclp->tgtLifetime = cm_TGTLifeTime(userp);
175 lock_ReleaseWrite(&cm_aclLock);
180 long cm_ShutdownACLCache(void)
185 long cm_ValidateACLCache(void)
187 long size = cm_data.stats * 2;
191 if ( cm_data.aclLRUp == NULL && cm_data.aclLRUEndp != NULL ||
192 cm_data.aclLRUp != NULL && cm_data.aclLRUEndp == NULL) {
193 afsi_log("cm_ValidateACLCache failure: inconsistent LRU pointers");
194 fprintf(stderr, "cm_ValidateACLCache failure: inconsistent LRU pointers\n");
198 for ( aclp = cm_data.aclLRUp, count = 0; aclp;
199 aclp = (cm_aclent_t *) osi_QNext(&aclp->q), count++ ) {
200 if (aclp->magic != CM_ACLENT_MAGIC) {
201 afsi_log("cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC");
202 fprintf(stderr, "cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC\n");
205 if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
206 afsi_log("cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC");
207 fprintf(stderr,"cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC\n");
210 if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
211 afsi_log("cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC");
212 fprintf(stderr,"cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC\n");
215 if (count != 0 && aclp == cm_data.aclLRUp || count > size) {
216 afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUp list");
217 fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUp list\n");
222 for ( aclp = cm_data.aclLRUEndp, count = 0; aclp;
223 aclp = (cm_aclent_t *) osi_QPrev(&aclp->q), count++ ) {
224 if (aclp->magic != CM_ACLENT_MAGIC) {
225 afsi_log("cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC");
226 fprintf(stderr, "cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC\n");
229 if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) {
230 afsi_log("cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC");
231 fprintf(stderr, "cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC\n");
234 if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) {
235 afsi_log("cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC");
236 fprintf(stderr, "cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC\n");
240 if (count != 0 && aclp == cm_data.aclLRUEndp || count > size) {
241 afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list");
242 fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list\n");
251 * Initialize the cache to have an entries. Called during system startup.
253 long cm_InitACLCache(int newFile, long size)
257 static osi_once_t once;
259 if (osi_Once(&once)) {
260 lock_InitializeRWLock(&cm_aclLock, "cm_aclLock", LOCK_HIERARCHY_ACL_GLOBAL);
264 lock_ObtainWrite(&cm_aclLock);
266 cm_data.aclLRUp = cm_data.aclLRUEndp = NULL;
267 aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
268 memset(aclp, 0, size * sizeof(cm_aclent_t));
271 * Put all of these guys on the LRU queue
273 for (i = 0; i < size; i++) {
274 aclp->magic = CM_ACLENT_MAGIC;
275 osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q);
279 aclp = (cm_aclent_t *) cm_data.aclBaseAddress;
280 for (i = 0; i < size; i++) {
282 aclp->tgtLifetime = 0;
286 lock_ReleaseWrite(&cm_aclLock);
292 * Free all associated acl entries. We actually just clear the back pointer
293 * since the acl entries are already in the free list. The scp must be locked
294 * or completely unreferenced (such as when called while recycling the scp).
296 void cm_FreeAllACLEnts(cm_scache_t *scp)
301 lock_ObtainWrite(&cm_aclLock);
302 for (aclp = scp->randomACLp; aclp; aclp = taclp) {
305 cm_ReleaseUser(aclp->userp);
308 aclp->backp = (struct cm_scache *) 0;
311 scp->randomACLp = (struct cm_aclent *) 0;
312 scp->anyAccess = 0; /* reset this, too */
313 lock_ReleaseWrite(&cm_aclLock);
318 * Invalidate all ACL entries for particular user on this particular vnode.
320 * The scp must be locked.
322 void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp)
325 cm_aclent_t **laclpp;
327 lock_ObtainWrite(&cm_aclLock);
328 laclpp = &scp->randomACLp;
329 for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) {
330 if (userp == aclp->userp) { /* One for a given user/scache */
331 *laclpp = aclp->nextp;
332 cm_ReleaseUser(aclp->userp);
334 aclp->backp = (struct cm_scache *) 0;
338 lock_ReleaseWrite(&cm_aclLock);
342 * Invalidate ACL info for a user that has just obtained or lost tokens.
345 cm_ResetACLCache(cm_cell_t *cellp, cm_user_t *userp)
350 lock_ObtainWrite(&cm_scacheLock);
351 for (hash=0; hash < cm_data.scacheHashTableSize; hash++) {
352 for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
354 scp->fid.cell == cellp->cellID) {
355 cm_HoldSCacheNoLock(scp);
356 lock_ReleaseWrite(&cm_scacheLock);
357 lock_ObtainWrite(&scp->rw);
358 cm_InvalidateACLUser(scp, userp);
359 lock_ReleaseWrite(&scp->rw);
360 lock_ObtainWrite(&cm_scacheLock);
361 cm_ReleaseSCacheNoLock(scp);
365 lock_ReleaseWrite(&cm_scacheLock);