Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / afs_user.c
CommitLineData
805e021f
CE
1/*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10/*
11 * Implements:
12 */
13#include <afsconfig.h>
14#include "afs/param.h"
15
16
17#include "afs/stds.h"
18#include "afs/sysincludes.h" /* Standard vendor system headers */
19
20#if !defined(UKERNEL)
21#if !defined(AFS_LINUX20_ENV)
22#include <net/if.h>
23#endif
24#include <netinet/in.h>
25
26#ifdef AFS_SGI62_ENV
27#include "h/hashing.h"
28#endif
29#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
30#include <netinet/in_var.h>
31#endif /* ! AFS_HPUX110_ENV */
32#endif /* !defined(UKERNEL) */
33
34#include "afsincludes.h" /* Afs-based standard headers */
35#include "afs/afs_stats.h" /* afs statistics */
36
37#if defined(AFS_SUN5_ENV)
38#include <inet/led.h>
39#include <inet/common.h>
40#include <netinet/ip6.h>
41#include <inet/ip.h>
42#endif
43
44#include "afs/afs_axscache.h"
45
46/* Exported variables */
47afs_rwlock_t afs_xuser;
48struct unixuser *afs_users[NUSERS];
49
50
51#ifndef AFS_PAG_MANAGER
52/* Forward declarations */
53void afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock);
54#endif /* !AFS_PAG_MANAGER */
55
56
57/* Called from afs_Daemon to garbage collect unixusers no longer using system,
58 * and their conns.
59 */
60void
61afs_GCUserData(void)
62{
63 struct unixuser *tu, **lu, *nu;
64 int i;
65 afs_int32 now, delFlag;
66
67 AFS_STATCNT(afs_GCUserData);
68 /* Obtain locks in valid order */
69 ObtainWriteLock(&afs_xuser, 95);
70#ifndef AFS_PAG_MANAGER
71 ObtainReadLock(&afs_xserver);
72 ObtainWriteLock(&afs_xconn, 96);
73#endif
74 now = osi_Time();
75 for (i = 0; i < NUSERS; i++) {
76 for (lu = &afs_users[i], tu = *lu; tu; tu = nu) {
77 delFlag = 0; /* should we delete this dude? */
78 /* Don't garbage collect users in use now (refCount) */
79 if (tu->refCount == 0) {
80 if (tu->tokens) {
81 /* Need to walk the token stack, and dispose of
82 * all expired tokens */
83 afs_DiscardExpiredTokens(&tu->tokens, now);
84 if (!afs_HasUsableTokens(tu->tokens, now))
85 delFlag = 1;
86 } else {
87 if (tu->tokenTime < now - NOTOKTIMEOUT)
88 delFlag = 1;
89 }
90 }
91 nu = tu->next;
92 if (delFlag) {
93 *lu = tu->next;
94#ifndef AFS_PAG_MANAGER
95 afs_ReleaseConnsUser(tu);
96#endif
97 afs_FreeTokens(&tu->tokens);
98
99 if (tu->exporter)
100 EXP_RELE(tu->exporter);
101 afs_osi_Free(tu, sizeof(struct unixuser));
102 } else {
103 lu = &tu->next;
104 }
105 }
106 }
107#ifndef AFS_PAG_MANAGER
108 ReleaseWriteLock(&afs_xconn);
109#endif
110#ifndef AFS_PAG_MANAGER
111 ReleaseReadLock(&afs_xserver);
112#endif
113 ReleaseWriteLock(&afs_xuser);
114
115} /*afs_GCUserData */
116
117static struct unixuser *
118afs_FindUserNoLock(afs_int32 auid, afs_int32 acell)
119{
120 struct unixuser *tu;
121 afs_int32 i;
122
123 AFS_STATCNT(afs_FindUser);
124 i = UHash(auid);
125 for (tu = afs_users[i]; tu; tu = tu->next) {
126 if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
127 tu->refCount++;
128 return tu;
129 }
130 }
131 return NULL;
132
133}
134
135#ifndef AFS_PAG_MANAGER
136/*
137 * Check for unixusers who encountered bad tokens, and reset the access
138 * cache for these guys. Can't do this when token expiration detected,
139 * since too many locks are set then.
140 */
141void
142afs_CheckTokenCache(void)
143{
144 int i;
145 struct unixuser *tu;
146 afs_int32 now;
147 struct vcache *tvc;
148 struct axscache *tofreelist;
149 int do_scan = 0;
150
151 AFS_STATCNT(afs_CheckCacheResets);
152 ObtainReadLock(&afs_xvcache);
153 ObtainReadLock(&afs_xuser);
154 now = osi_Time();
155 for (i = 0; i < NUSERS; i++) {
156 for (tu = afs_users[i]; tu; tu = tu->next) {
157 /*
158 * If tokens are still good and user has Kerberos tickets,
159 * check expiration
160 */
161 if ((tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
162 if (!afs_HasUsableTokens(tu->tokens, now)) {
163 /*
164 * This token has expired, warn users and reset access
165 * cache.
166 */
167 tu->states |= (UTokensBad | UNeedsReset);
168 }
169 }
170 if (tu->states & UNeedsReset)
171 do_scan = 1;
172 }
173 }
174 /* Skip the potentially expensive scan if nothing to do */
175 if (!do_scan)
176 goto done;
177
178 tofreelist = NULL;
179 for (i = 0; i < VCSIZE; i++) {
180 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
181 /* really should do this under cache write lock, but that.
182 * is hard to under locking hierarchy */
183 if (tvc->Access) {
184 struct axscache **ac, **nac;
185
186 for ( ac = &tvc->Access; *ac;) {
187 nac = &(*ac)->next;
188 tu = afs_FindUserNoLock((*ac)->uid, tvc->f.fid.Cell);
189 if (tu == NULL || (tu->states & UNeedsReset)) {
190 struct axscache *tmp;
191 tmp = *ac;
192 *ac = *nac;
193 tmp->next = tofreelist;
194 tofreelist = tmp;
195 } else
196 ac = nac;
197 if (tu != NULL)
198 tu->refCount--;
199 }
200 }
201 }
202 }
203 afs_FreeAllAxs(&tofreelist);
204 for (i = 0; i < NUSERS; i++) {
205 for (tu = afs_users[i]; tu; tu = tu->next) {
206 if (tu->states & UNeedsReset)
207 tu->states &= ~UNeedsReset;
208 }
209 }
210
211done:
212 ReleaseReadLock(&afs_xuser);
213 ReleaseReadLock(&afs_xvcache);
214} /*afs_CheckTokenCache */
215
216
217/* Remove any access caches associated with this uid+cell
218 * by scanning the entire vcache table. Specify cell=-1
219 * to remove all access caches associated with this uid
220 * regardless of cell.
221 */
222void
223afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock)
224{
225 int i;
226 struct vcache *tvc;
227 struct axscache *ac;
228
229 AFS_STATCNT(afs_ResetAccessCache);
230 if (alock)
231 ObtainReadLock(&afs_xvcache);
232 for (i = 0; i < VCSIZE; i++) {
233 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
234 /* really should do this under cache write lock, but that.
235 * is hard to under locking hierarchy */
236 if (tvc->Access && (cell == -1 || tvc->f.fid.Cell == cell)) {
237 ac = afs_FindAxs(tvc->Access, uid);
238 if (ac) {
239 afs_RemoveAxs(&tvc->Access, ac);
240 }
241 }
242 }
243 }
244 if (alock)
245 ReleaseReadLock(&afs_xvcache);
246
247} /*afs_ResetAccessCache */
248
249
250/*
251 * Ensure all connections make use of new tokens. Discard incorrectly-cached
252 * access info.
253 */
254void
255afs_ResetUserConns(struct unixuser *auser)
256{
257 int i, j;
258 struct srvAddr *sa;
259 struct sa_conn_vector *tcv;
260
261 AFS_STATCNT(afs_ResetUserConns);
262 ObtainReadLock(&afs_xsrvAddr);
263 ObtainWriteLock(&afs_xconn, 98);
264
265 for (i = 0; i < NSERVERS; i++) {
266 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
267 for (tcv = sa->conns; tcv; tcv = tcv->next) {
268 if (tcv->user == auser) {
269 for(j = 0; j < CVEC_LEN; ++j) {
270 (tcv->cvec[j]).forceConnectFS = 1;
271 }
272 }
273 }
274 }
275 }
276
277 ReleaseWriteLock(&afs_xconn);
278 ReleaseReadLock(&afs_xsrvAddr);
279 afs_ResetAccessCache(auser->uid, auser->cell, 1);
280 auser->states &= ~UNeedsReset;
281} /*afs_ResetUserConns */
282#endif /* !AFS_PAG_MANAGER */
283
284
285struct unixuser *
286afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
287{
288 struct unixuser *tu;
289
290 ObtainWriteLock(&afs_xuser, 99);
291 tu = afs_FindUserNoLock(auid, acell);
292 ReleaseWriteLock(&afs_xuser);
293 if (tu)
294 afs_LockUser(tu, locktype, 365);
295 return tu;
296} /*afs_FindUser */
297
298
299/*------------------------------------------------------------------------
300 * EXPORTED afs_ComputePAGStats
301 *
302 * Description:
303 * Compute a set of stats concerning PAGs used by this machine.
304 *
305 * Arguments:
306 * None.
307 *
308 * Returns:
309 * Nothing.
310 *
311 * Environment:
312 * The results are put in the structure responsible for keeping
313 * detailed CM stats. Note: entries corresponding to a single PAG
314 * will appear on the identical hash chain, so sweeping the chain
315 * will find all entries related to a single PAG.
316 *
317 * Side Effects:
318 * As advertised.
319 *------------------------------------------------------------------------*/
320
321void
322afs_ComputePAGStats(void)
323{
324 struct unixuser *currPAGP; /*Ptr to curr PAG */
325 struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
326 struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
327 int curr_Record; /*Curr record */
328 int currChain; /*Curr hash chain */
329 int currChainLen; /*Length of curr hash chain */
330 int currPAGRecords; /*# records in curr PAG */
331
332 /*
333 * Lock out everyone else from scribbling on the PAG entries.
334 */
335 ObtainReadLock(&afs_xuser);
336
337 /*
338 * Initialize the tallies, then sweep through each hash chain. We
339 * can't bzero the structure, since some fields are cumulative over
340 * the CM's lifetime.
341 */
342 curr_Record = 0;
343 authP = &(afs_stats_cmfullperf.authent);
344 authP->curr_PAGs = 0;
345 authP->curr_Records = 0;
346 authP->curr_AuthRecords = 0;
347 authP->curr_UnauthRecords = 0;
348 authP->curr_MaxRecordsInPAG = 0;
349 authP->curr_LongestChain = 0;
350
351 for (currChain = 0; currChain < NUSERS; currChain++) {
352 currChainLen = 0;
353 for (currPAGP = afs_users[currChain]; currPAGP;
354 currPAGP = currPAGP->next) {
355 /*
356 * Bump the number of records on this current chain, along with
357 * the total number of records in existence.
358 */
359 currChainLen++;
360 curr_Record++;
361 /*
362 * We've found a previously-uncounted PAG. If it's been deleted
363 * but just not garbage-collected yet, we step over it.
364 */
365 if (!(currPAGP->states & UHasTokens))
366 continue;
367
368 /*
369 * If this PAG record has already been ``counted', namely
370 * associated with a PAG and tallied, clear its bit and move on.
371 */
372 (authP->curr_Records)++;
373 if (currPAGP->states & UPAGCounted) {
374 currPAGP->states &= ~UPAGCounted;
375 continue;
376 }
377
378
379
380 /*We've counted this one already */
381 /*
382 * Jot initial info down, then sweep down the rest of the hash
383 * chain, looking for matching PAG entries. Note: to properly
384 * ``count'' the current record, we first compare it to itself
385 * in the following loop.
386 */
387 (authP->curr_PAGs)++;
388 currPAGRecords = 0;
389
390 for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) {
391 if (currPAGP->uid == cmpPAGP->uid) {
392 /*
393 * The records belong to the same PAG. First, mark the
394 * new record as ``counted'' and bump the PAG size.
395 * Then, record the state of its ticket, if any.
396 */
397 cmpPAGP->states |= UPAGCounted;
398 currPAGRecords++;
399 if ((cmpPAGP->states & UHasTokens)
400 && !(cmpPAGP->states & UTokensBad))
401 (authP->curr_AuthRecords)++;
402 else
403 (authP->curr_UnauthRecords)++;
404 } /*Records belong to same PAG */
405 } /*Compare to rest of PAG records in chain */
406
407 /*
408 * In the above comparisons, the current PAG record has been
409 * marked as counted. Erase this mark before moving on.
410 */
411 currPAGP->states &= ~UPAGCounted;
412
413 /*
414 * We've compared our current PAG record with all remaining
415 * PAG records in the hash chain. Update our tallies, and
416 * perhaps even our lifetime high water marks. After that,
417 * remove our search mark and advance to the next comparison
418 * pair.
419 */
420 if (currPAGRecords > authP->curr_MaxRecordsInPAG) {
421 authP->curr_MaxRecordsInPAG = currPAGRecords;
422 if (currPAGRecords > authP->HWM_MaxRecordsInPAG)
423 authP->HWM_MaxRecordsInPAG = currPAGRecords;
424 }
425 } /*Sweep a hash chain */
426
427 /*
428 * If the chain we just finished zipping through is the longest we've
429 * seen yet, remember this fact before advancing to the next chain.
430 */
431 if (currChainLen > authP->curr_LongestChain) {
432 authP->curr_LongestChain = currChainLen;
433 if (currChainLen > authP->HWM_LongestChain)
434 authP->HWM_LongestChain = currChainLen;
435 }
436
437 } /*For each hash chain in afs_user */
438
439 /*
440 * Now that we've counted everything up, we can consider all-time
441 * numbers.
442 */
443 if (authP->curr_PAGs > authP->HWM_PAGs)
444 authP->HWM_PAGs = authP->curr_PAGs;
445 if (authP->curr_Records > authP->HWM_Records)
446 authP->HWM_Records = authP->curr_Records;
447
448 /*
449 * People are free to manipulate the PAG structures now.
450 */
451 ReleaseReadLock(&afs_xuser);
452
453} /*afs_ComputePAGStats */
454
455/*!
456 * Obtain a unixuser for the specified uid and cell;
457 * if no existing match found, allocate a new one.
458 *
459 * \param[in] auid uid/PAG value
460 * \param[in] acell cell number; if -1, match on auid only
461 * \param[in] locktype locktype desired on returned unixuser
462 *
463 * \post unixuser is chained in afs_users[], returned with <locktype> held
464 *
465 * \note Maintain unixusers in sorted order within hash bucket to enable
466 * small lookup optimizations.
467 */
468
469struct unixuser *
470afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
471{
472 struct unixuser *tu, *xu = 0, *pu = 0;
473 afs_int32 i;
474 afs_int32 RmtUser = 0;
475
476 AFS_STATCNT(afs_GetUser);
477 i = UHash(auid);
478 ObtainWriteLock(&afs_xuser, 104);
479 /* unixusers are sorted by uid in each hash bucket */
480 for (tu = afs_users[i]; tu && (tu->uid <= auid) ; xu = tu, tu = tu->next) {
481 if (tu->uid == auid) {
482 RmtUser = 0;
483 pu = NULL;
484 if (tu->exporter) {
485 RmtUser = 1;
486 pu = tu;
487 }
488 if (tu->cell == -1 && acell != -1) {
489 /* Here we setup the real cell for the client */
490 tu->cell = acell;
491 tu->refCount++;
492 goto done;
493 } else if (tu->cell == acell || acell == -1) {
494 tu->refCount++;
495 goto done;
496 }
497 }
498 }
499 /* no matching unixuser found; repurpose the tu pointer to
500 * allocate a new unixuser.
501 * xu will be insertion point for our new unixuser.
502 */
503 tu = afs_osi_Alloc(sizeof(struct unixuser));
504 osi_Assert(tu != NULL);
505#ifndef AFS_NOSTATS
506 afs_stats_cmfullperf.authent.PAGCreations++;
507#endif /* AFS_NOSTATS */
508 memset(tu, 0, sizeof(struct unixuser));
509 AFS_RWLOCK_INIT(&tu->lock, "unixuser lock");
510 /* insert new nu in sorted order after xu */
511 if (xu == NULL) {
512 tu->next = afs_users[i];
513 afs_users[i] = tu;
514 } else {
515 tu->next = xu->next;
516 xu->next = tu;
517 }
518 if (RmtUser) {
519 /*
520 * This is for the case where an additional unixuser struct is
521 * created because the remote client is accessing a different cell;
522 * we simply rerecord relevant information from the original
523 * structure
524 */
525 if (pu && pu->exporter) {
526 tu->exporter = pu->exporter;
527 (void)EXP_HOLD(tu->exporter);
528 }
529 }
530 tu->uid = auid;
531 tu->cell = acell;
532 tu->viceId = UNDEFVID;
533 tu->refCount = 1;
534 tu->tokenTime = osi_Time();
535 /* fall through to return the new one */
536
537 done:
538 ReleaseWriteLock(&afs_xuser);
539 afs_LockUser(tu, locktype, 364);
540 return tu;
541
542} /*afs_GetUser */
543
544void
545afs_LockUser(struct unixuser *au, afs_int32 locktype,
546 unsigned int src_indicator)
547{
548 switch (locktype) {
549 case READ_LOCK:
550 ObtainReadLock(&au->lock);
551 break;
552 case WRITE_LOCK:
553 ObtainWriteLock(&au->lock, src_indicator);
554 break;
555 case SHARED_LOCK:
556 ObtainSharedLock(&au->lock, src_indicator);
557 break;
558 default:
559 /* noop */
560 break;
561 }
562}
563
564void
565afs_PutUser(struct unixuser *au, afs_int32 locktype)
566{
567 AFS_STATCNT(afs_PutUser);
568
569 switch (locktype) {
570 case READ_LOCK:
571 ReleaseReadLock(&au->lock);
572 break;
573 case WRITE_LOCK:
574 ReleaseWriteLock(&au->lock);
575 break;
576 case SHARED_LOCK:
577 ReleaseSharedLock(&au->lock);
578 break;
579 default:
580 /* noop */
581 break;
582 }
583
584 --au->refCount;
585} /*afs_PutUser */
586
587
588/*
589 * Set the primary flag on a unixuser structure, ensuring that exactly one
590 * dude has the flag set at any time for a particular unix uid.
591 */
592void
593afs_SetPrimary(struct unixuser *au, int aflag)
594{
595 struct unixuser *tu;
596 int i;
597 struct unixuser *pu;
598
599 AFS_STATCNT(afs_SetPrimary);
600 i = UHash(au->uid);
601 pu = NULL;
602 ObtainWriteLock(&afs_xuser, 105);
603 /*
604 * See if anyone is this uid's primary cell yet; recording in pu the
605 * corresponding user
606 */
607 for (tu = afs_users[i]; tu; tu = tu->next) {
608 if (tu->uid == au->uid && (tu->states & UPrimary)) {
609 pu = tu;
610 }
611 }
612 if (pu && !(pu->states & UHasTokens)) {
613 /*
614 * Primary user has unlogged, don't treat him as primary any longer;
615 * note that we want to treat him as primary until now, so that
616 * people see a primary identity until now.
617 */
618 pu->states &= ~UPrimary;
619 pu = NULL;
620 }
621 if (aflag == 1) {
622 /* setting au to be primary */
623 if (pu)
624 pu->states &= ~UPrimary;
625 au->states |= UPrimary;
626 } else if (aflag == 0) {
627 /* we don't know if we're supposed to be primary or not */
628 if (!pu || au == pu) {
629 au->states |= UPrimary;
630 } else
631 au->states &= ~UPrimary;
632 }
633 ReleaseWriteLock(&afs_xuser);
634
635} /*afs_SetPrimary */
636
637void
638afs_NotifyUser(struct unixuser *auser, int event)
639{
640#ifdef AFS_DARWIN_ENV
641 darwin_notify_perms(auser, event);
642#endif
643}
644
645/**
646 * Mark all of the unixuser records held for a particular PAG as
647 * expired
648 *
649 * @param[in] pag
650 * PAG to expire records for
651 */
652void
653afs_MarkUserExpired(afs_int32 pag)
654{
655 afs_int32 i;
656 struct unixuser *tu;
657
658 i = UHash(pag);
659 ObtainWriteLock(&afs_xuser, 9);
660 for (tu = afs_users[i]; tu; tu = tu->next) {
661 if (tu->uid == pag) {
662 tu->states &= ~UHasTokens;
663 tu->tokenTime = 0;
664 }
665 }
666 ReleaseWriteLock(&afs_xuser);
667}
668
669
670#if AFS_GCPAGS
671
672/*
673 * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
674 * process in the system.
675 * If the specified process uses a PAG, clear that PAG's temporary
676 * 'deleteme' flag.
677 */
678
679/*
680 * This variable keeps track of the number of UID-base
681 * tokens in the afs_users table. When it's zero
682 * the per process loop in GCPAGs doesn't have to
683 * check processes without pags against the afs_users table.
684 */
685static afs_int32 afs_GCPAGs_UIDBaseTokenCount = 0;
686
687/*
688 * These variables keep track of the number of times
689 * afs_GCPAGs_perproc_func() is called. If it is not called at all when
690 * walking the process table, there is something wrong and we should not
691 * prematurely expire any tokens.
692 */
693static size_t afs_GCPAGs_perproc_count = 0;
694static size_t afs_GCPAGs_cred_count = 0;
695
696/*
697 * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
698 */
699#if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_STRUCT_HAS_CRED) || defined(HAVE_LINUX_RCU_READ_LOCK))
700void
701afs_GCPAGs_perproc_func(afs_proc_t * pproc)
702{
703 afs_int32 pag, hash, uid;
704 const afs_ucred_t *pcred;
705
706 afs_GCPAGs_perproc_count++;
707
708 pcred = afs_osi_proc2cred(pproc);
709 if (!pcred)
710 return;
711
712 afs_GCPAGs_cred_count++;
713
714 pag = PagInCred(pcred);
715#if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_LINUX22_ENV)
716 uid = (pag != NOPAG ? pag : afs_cr_uid(pcred));
717#elif defined(AFS_SUN510_ENV)
718 uid = (pag != NOPAG ? pag : crgetruid(pcred));
719#else
720 uid = (pag != NOPAG ? pag : afs_cr_ruid(pcred));
721#endif
722 hash = UHash(uid);
723
724 /* if this token is PAG based, or it's UID based and
725 * UID-based tokens exist */
726 if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
727 /* find the entries for this uid in all cells and clear the not
728 * referenced flag. Can't use afs_FindUser, because it just returns
729 * the specific cell asked for, or the first one found.
730 */
731 struct unixuser *pu;
732 for (pu = afs_users[hash]; pu; pu = pu->next) {
733 if (pu->uid == uid) {
734 if (pu->states & TMP_UPAGNotReferenced) {
735 /* clear the 'deleteme' flag for this entry */
736 pu->states &= ~TMP_UPAGNotReferenced;
737 if (pag == NOPAG) {
738 /* This is a uid based token that hadn't
739 * previously been cleared, so decrement the
740 * outstanding uid based token count */
741 afs_GCPAGs_UIDBaseTokenCount--;
742 }
743 }
744 }
745 }
746 }
747}
748#endif
749
750/*
751 * Go through the process table, find all unused PAGs
752 * and cause them to be deleted during the next GC.
753 *
754 * returns the number of PAGs marked for deletion
755 *
756 * On AIX we free PAGs when the last accessing process exits,
757 * so this routine is not needed.
758 *
759 * In AFS WebSecure, we explicitly call unlog when we remove
760 * an entry in the login cache, so this routine is not needed.
761 */
762
763afs_int32
764afs_GCPAGs(afs_int32 * ReleasedCount)
765{
766 struct unixuser *pu;
767 int i;
768
769 if (afs_gcpags != AFS_GCPAGS_OK) {
770 return 0;
771 }
772
773 *ReleasedCount = 0;
774
775 /* first, loop through afs_users, setting the temporary 'deleteme' flag */
776 ObtainWriteLock(&afs_xuser, 419);
777 afs_GCPAGs_UIDBaseTokenCount = 0;
778 for (i = 0; i < NUSERS; i++) {
779 for (pu = afs_users[i]; pu; pu = pu->next) {
780 pu->states |= TMP_UPAGNotReferenced;
781 if (((pu->uid >> 24) & 0xff) != 'A') {
782 /* this is a uid-based token, */
783 /* increment the count */
784 afs_GCPAGs_UIDBaseTokenCount++;
785 }
786 }
787 }
788
789 /* Now, iterate through the systems process table,
790 * for each process, mark it's PAGs (if any) in use.
791 * i.e. clear the temporary deleteme flag.
792 */
793 afs_GCPAGs_perproc_count = 0;
794 afs_GCPAGs_cred_count = 0;
795
796 afs_osi_TraverseProcTable();
797
798 /* If there is an internal problem and afs_GCPAGs_perproc_func()
799 * does not get called, disable gcpags so that we do not
800 * accidentally expire all the tokens in the system.
801 */
802 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) {
803 afs_gcpags = AFS_GCPAGS_EPROCWALK;
804 }
805
806 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) {
807 afs_gcpags = AFS_GCPAGS_ECREDWALK;
808 }
809
810 /* Now, go through afs_users again, any that aren't in use
811 * (temp deleteme flag still set) will be marked for later deletion,
812 * by setting their expire times to 0.
813 */
814 for (i = 0; i < NUSERS; i++) {
815 for (pu = afs_users[i]; pu; pu = pu->next) {
816 if (pu->states & TMP_UPAGNotReferenced) {
817
818 /* clear the temp flag */
819 pu->states &= ~TMP_UPAGNotReferenced;
820
821 /* Is this entry on behalf of a 'remote' user ?
822 * i.e. nfs translator, etc.
823 */
824 if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
825 /* make afs_GCUserData remove this entry */
826 pu->states &= ~UHasTokens;
827 pu->tokenTime = 0;
828
829 (*ReleasedCount)++; /* remember how many we marked (info only) */
830 }
831 }
832 }
833 }
834
835 ReleaseWriteLock(&afs_xuser);
836
837 return 0;
838}
839
840#endif /* AFS_GCPAGS */