be9b5021035fb5288b85c432992259b97f5c72d0
[openafs.git] / src / afs / afs_icl.c
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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"
17 #include "rx/rx_globals.h"
18 #if !defined(UKERNEL) && !defined(AFS_LINUX20_ENV)
19 #include "net/if.h"
20 #ifdef AFS_SGI62_ENV
21 #include "h/hashing.h"
22 #endif
23 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_DARWIN_ENV)
24 #include "netinet/in_var.h"
25 #endif
26 #endif /* !defined(UKERNEL) */
27
28
29 struct afs_icl_set *afs_iclSetp = (struct afs_icl_set *)0;
30 struct afs_icl_set *afs_iclLongTermSetp = (struct afs_icl_set *)0;
31
32 /* Matches below where ICL_APPENDLONG is 2 INT32s */
33 #if (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)) || defined(AFS_DARWIN_ENV) && defined(__amd64__)
34 #define ICL_LONG 2
35 #else
36 #define ICL_LONG 1
37 #endif
38
39 int afs_icl_sizeofLong = ICL_LONG;
40
41 int afs_icl_inited = 0;
42
43 /* init function, called once, under afs_icl_lock */
44 int
45 afs_icl_Init(void)
46 {
47     afs_icl_inited = 1;
48     return 0;
49 }
50
51 /* Function called at shutdown - zap everything */
52 void
53 shutdown_icl(void)
54 {
55     struct afs_icl_log *logp;
56     struct afs_icl_set *setp;
57
58     setp = afs_icl_FindSet("cm");
59     if (setp) {
60         /* Release the reference from Find, and the initial one */
61         afs_icl_SetFree(setp);
62         afs_icl_SetFree(setp);
63     }
64     setp = afs_icl_FindSet("cmlongterm");
65     if (setp) {
66         /* Release the reference from Find, and the initial one */
67         afs_icl_SetFree(setp);
68         afs_icl_SetFree(setp);
69     }
70     logp = afs_icl_FindLog("cmfx");
71     if (logp) {
72         /* Release the reference from Find, and the initial one */
73         afs_icl_LogFree(logp);
74         afs_icl_LogFree(logp);
75     }
76 }
77
78 int
79 afs_icl_InitLogs(void)
80 {
81     struct afs_icl_log *logp;
82     int code;
83
84     /* initialize the ICL system */
85     code = afs_icl_CreateLog("cmfx", 60 * 1024, &logp);
86     if (code == 0)
87         code =
88             afs_icl_CreateSetWithFlags("cm", logp, NULL,
89                                        ICL_CRSET_FLAG_DEFAULT_OFF,
90                                        &afs_iclSetp);
91     code =
92         afs_icl_CreateSet("cmlongterm", logp, NULL,
93                           &afs_iclLongTermSetp);
94     return code;
95 }
96
97
98 struct afs_icl_log *afs_icl_FindLog(char *);
99 struct afs_icl_set *afs_icl_FindSet(char *);
100
101
102 #ifdef AFS_DARWIN100_ENV
103 #define AFSKPTR(X) k ## X
104 int
105 Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
106 {
107     return Afscall64_icl(opcode,
108                          CAST_USER_ADDR_T((p1)),
109                          CAST_USER_ADDR_T((p2)),
110                          CAST_USER_ADDR_T((p3)),
111                          CAST_USER_ADDR_T((p4)),
112                          retval);
113 }
114 #else
115 #define AFSKPTR(X) ((caddr_t)X)
116 #endif
117
118 int
119 #ifdef AFS_DARWIN100_ENV
120 Afscall64_icl(int opcode, user_addr_t kp1, user_addr_t kp2, user_addr_t kp3, user_addr_t kp4, int *retval)
121 #else
122 Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
123 #endif
124 {
125     afs_int32 *lp, elts, flags;
126     afs_int32 code;
127     struct afs_icl_log *logp;
128     struct afs_icl_set *setp;
129 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN57_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
130     size_t temp;
131 #else /* AFS_SGI61_ENV */
132 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
133     afs_uint64 temp;
134 #else
135     afs_uint32 temp;
136 #endif
137 #endif /* AFS_SGI61_ENV */
138     char tname[65];
139     afs_int32 startCookie;
140     afs_int32 allocated;
141     struct afs_icl_log *tlp;
142 #ifdef AFS_DARWIN100_ENV
143     afs_uint32 p1 = (afs_uint32)kp1;
144     afs_uint32 p2 = (afs_uint32)kp2;
145     afs_uint32 p3 = (afs_uint32)kp3;
146     afs_uint32 p4 = (afs_uint32)kp4;
147 #endif
148
149 #ifdef  AFS_SUN5_ENV
150     if (!afs_suser(CRED())) {   /* only root can run this code */
151         return (EACCES);
152     }
153 #else
154     if (!afs_suser(NULL)) {     /* only root can run this code */
155 #if defined(KERNEL_HAVE_UERROR)
156         setuerror(EACCES);
157         return EACCES;
158 #else
159         return EPERM;
160 #endif
161     }
162 #endif
163     switch (opcode) {
164     case ICL_OP_COPYOUTCLR:     /* copy out data then clear */
165     case ICL_OP_COPYOUT:        /* copy ouy data */
166         /* copyout: p1=logname, p2=&buffer, p3=size(words), p4=&cookie
167          * return flags<<24 + nwords.
168          * updates cookie to updated start (not end) if we had to
169          * skip some records.
170          */
171         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
172         if (code)
173             return code;
174         AFS_COPYIN(AFSKPTR(p4), (char *)&startCookie, sizeof(afs_int32), code);
175         if (code)
176             return code;
177         logp = afs_icl_FindLog(tname);
178         if (!logp)
179             return ENOENT;
180 #define BUFFERSIZE      AFS_LRALLOCSIZ
181         lp = (afs_int32 *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
182         elts = BUFFERSIZE / sizeof(afs_int32);
183         if (p3 < elts)
184             elts = p3;
185         flags = (opcode == ICL_OP_COPYOUT) ? 0 : ICL_COPYOUTF_CLRAFTERREAD;
186         code =
187             afs_icl_CopyOut(logp, lp, &elts, (afs_uint32 *) & startCookie,
188                             &flags);
189         if (code) {
190             osi_FreeLargeSpace((struct osi_buffer *)lp);
191             break;
192         }
193         AFS_COPYOUT((char *)lp, AFSKPTR(p2), elts * sizeof(afs_int32), code);
194         if (code)
195             goto done;
196         AFS_COPYOUT((char *)&startCookie, AFSKPTR(p4), sizeof(afs_int32),
197                     code);
198         if (code)
199             goto done;
200 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
201         if (!(IS64U))
202             *retval = ((long)((flags << 24) | (elts & 0xffffff))) << 32;
203         else
204 #endif
205             *retval = (flags << 24) | (elts & 0xffffff);
206       done:
207         afs_icl_LogRele(logp);
208         osi_FreeLargeSpace((struct osi_buffer *)lp);
209         break;
210
211     case ICL_OP_ENUMLOGS:       /* enumerate logs */
212         /* enumerate logs: p1=index, p2=&name, p3=sizeof(name), p4=&size.
213          * return 0 for success, otherwise error.
214          */
215         for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
216             if (p1-- == 0)
217                 break;
218         }
219         if (!tlp)
220             return ENOENT;      /* past the end of file */
221         temp = strlen(tlp->name) + 1;
222         if (temp > p3)
223             return EINVAL;
224         AFS_COPYOUT(tlp->name, AFSKPTR(p2), temp, code);
225         if (!code)              /* copy out size of log */
226             AFS_COPYOUT((char *)&tlp->logSize, AFSKPTR(p4), sizeof(afs_int32),
227                         code);
228         break;
229
230     case ICL_OP_ENUMLOGSBYSET:  /* enumerate logs by set name */
231         /* enumerate logs: p1=setname, p2=index, p3=&name, p4=sizeof(name).
232          * return 0 for success, otherwise error.
233          */
234         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
235         if (code)
236             return code;
237         setp = afs_icl_FindSet(tname);
238         if (!setp)
239             return ENOENT;
240         if (p2 > ICL_LOGSPERSET)
241             return EINVAL;
242         if (!(tlp = setp->logs[p2]))
243             return EBADF;
244         temp = strlen(tlp->name) + 1;
245         if (temp > p4)
246             return EINVAL;
247         AFS_COPYOUT(tlp->name, AFSKPTR(p3), temp, code);
248         break;
249
250     case ICL_OP_CLRLOG: /* clear specified log */
251         /* zero out the specified log: p1=logname */
252         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
253         if (code)
254             return code;
255         logp = afs_icl_FindLog(tname);
256         if (!logp)
257             return ENOENT;
258         code = afs_icl_ZeroLog(logp);
259         afs_icl_LogRele(logp);
260         break;
261
262     case ICL_OP_CLRSET: /* clear specified set */
263         /* zero out the specified set: p1=setname */
264         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
265         if (code)
266             return code;
267         setp = afs_icl_FindSet(tname);
268         if (!setp)
269             return ENOENT;
270         code = afs_icl_ZeroSet(setp);
271         afs_icl_SetRele(setp);
272         break;
273
274     case ICL_OP_CLRALL: /* clear all logs */
275         /* zero out all logs -- no args */
276         code = 0;
277         ObtainWriteLock(&afs_icl_lock, 178);
278         for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
279             tlp->refCount++;    /* hold this guy */
280             ReleaseWriteLock(&afs_icl_lock);
281             /* don't clear persistent logs */
282             if ((tlp->states & ICL_LOGF_PERSISTENT) == 0)
283                 code = afs_icl_ZeroLog(tlp);
284             ObtainWriteLock(&afs_icl_lock, 179);
285             if (--tlp->refCount == 0)
286                 afs_icl_ZapLog(tlp);
287             if (code)
288                 break;
289         }
290         ReleaseWriteLock(&afs_icl_lock);
291         break;
292
293     case ICL_OP_ENUMSETS:       /* enumerate all sets */
294         /* enumerate sets: p1=index, p2=&name, p3=sizeof(name), p4=&states.
295          * return 0 for success, otherwise error.
296          */
297         for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
298             if (p1-- == 0)
299                 break;
300         }
301         if (!setp)
302             return ENOENT;      /* past the end of file */
303         temp = strlen(setp->name) + 1;
304         if (temp > p3)
305             return EINVAL;
306         AFS_COPYOUT(setp->name, AFSKPTR(p2), temp, code);
307         if (!code)              /* copy out size of log */
308             AFS_COPYOUT((char *)&setp->states, AFSKPTR(p4), sizeof(afs_int32),
309                         code);
310         break;
311
312     case ICL_OP_SETSTAT:        /* set status on a set */
313         /* activate the specified set: p1=setname, p2=op */
314         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
315         if (code)
316             return code;
317         setp = afs_icl_FindSet(tname);
318         if (!setp)
319             return ENOENT;
320         code = afs_icl_SetSetStat(setp, p2);
321         afs_icl_SetRele(setp);
322         break;
323
324     case ICL_OP_SETSTATALL:     /* set status on all sets */
325         /* activate the specified set: p1=op */
326         code = 0;
327         ObtainWriteLock(&afs_icl_lock, 180);
328         for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
329             setp->refCount++;   /* hold this guy */
330             ReleaseWriteLock(&afs_icl_lock);
331             /* don't set states on persistent sets */
332             if ((setp->states & ICL_SETF_PERSISTENT) == 0)
333                 code = afs_icl_SetSetStat(setp, p1);
334             ObtainWriteLock(&afs_icl_lock, 181);
335             if (--setp->refCount == 0)
336                 afs_icl_ZapSet(setp);
337             if (code)
338                 break;
339         }
340         ReleaseWriteLock(&afs_icl_lock);
341         break;
342
343     case ICL_OP_SETLOGSIZE:     /* set size of log */
344         /* set the size of the specified log: p1=logname, p2=size (in words) */
345         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
346         if (code)
347             return code;
348         logp = afs_icl_FindLog(tname);
349         if (!logp)
350             return ENOENT;
351         code = afs_icl_LogSetSize(logp, p2);
352         afs_icl_LogRele(logp);
353         break;
354
355     case ICL_OP_GETLOGINFO:     /* get size of log */
356         /* zero out the specified log: p1=logname, p2=&logSize, p3=&allocated */
357         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
358         if (code)
359             return code;
360         logp = afs_icl_FindLog(tname);
361         if (!logp)
362             return ENOENT;
363         allocated = !!logp->datap;
364         AFS_COPYOUT((char *)&logp->logSize, AFSKPTR(p2), sizeof(afs_int32),
365                     code);
366         if (!code)
367             AFS_COPYOUT((char *)&allocated, AFSKPTR(p3), sizeof(afs_int32),
368                         code);
369         afs_icl_LogRele(logp);
370         break;
371
372     case ICL_OP_GETSETINFO:     /* get state of set */
373         /* zero out the specified set: p1=setname, p2=&state */
374         AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
375         if (code)
376             return code;
377         setp = afs_icl_FindSet(tname);
378         if (!setp)
379             return ENOENT;
380         AFS_COPYOUT((char *)&setp->states, AFSKPTR(p2), sizeof(afs_int32),
381                     code);
382         afs_icl_SetRele(setp);
383         break;
384
385     default:
386         code = EINVAL;
387     }
388
389     return code;
390 }
391
392
393 afs_lock_t afs_icl_lock;
394
395 /* exported routine: a 4 parameter event */
396 int
397 afs_icl_Event4(struct afs_icl_set *setp, afs_int32 eventID,
398                afs_int32 lAndT, long p1, long p2, long p3, long p4)
399 {
400     afs_int32 mask;
401     int i;
402     afs_int32 tmask;
403     int ix;
404
405     /* If things aren't init'ed yet (or the set is inactive), don't panic */
406     if (!ICL_SETACTIVE(setp))
407         return 0;
408
409     AFS_ASSERT_GLOCK();
410     mask = lAndT >> 24 & 0xff;  /* mask of which logs to log to */
411     ix = ICL_EVENTBYTE(eventID);
412     ObtainReadLock(&setp->lock);
413     if (setp->eventFlags[ix] & ICL_EVENTMASK(eventID)) {
414         for (i = 0, tmask = 1; i < ICL_LOGSPERSET; i++, tmask <<= 1) {
415             if (mask & tmask) {
416                 afs_icl_AppendRecord(setp->logs[i], eventID, lAndT & 0xffffff,
417                                      p1, p2, p3, p4);
418             }
419             mask &= ~tmask;
420             if (mask == 0)
421                 break;          /* break early */
422         }
423     }
424     ReleaseReadLock(&setp->lock);
425     return 0;
426 }
427
428 /* Next 4 routines should be implemented via var-args or something.
429  * Whole purpose is to avoid compiler warnings about parameter # mismatches.
430  * Otherwise, could call afs_icl_Event4 directly.
431  */
432 int
433 afs_icl_Event3(struct afs_icl_set *setp, afs_int32 eventID,
434                afs_int32 lAndT, long p1, long p2, long p3)
435 {
436     return afs_icl_Event4(setp, eventID, lAndT, p1, p2, p3, (long)0);
437 }
438
439 int
440 afs_icl_Event2(struct afs_icl_set *setp, afs_int32 eventID,
441                afs_int32 lAndT, long p1, long p2)
442 {
443     return afs_icl_Event4(setp, eventID, lAndT, p1, p2, (long)0, (long)0);
444 }
445
446 int
447 afs_icl_Event1(struct afs_icl_set *setp, afs_int32 eventID,
448                afs_int32 lAndT, long p1)
449 {
450     return afs_icl_Event4(setp, eventID, lAndT, p1, (long)0, (long)0,
451                           (long)0);
452 }
453
454 int
455 afs_icl_Event0(struct afs_icl_set *setp, afs_int32 eventID,
456                afs_int32 lAndT)
457 {
458     return afs_icl_Event4(setp, eventID, lAndT, (long)0, (long)0, (long)0,
459                           (long)0);
460 }
461
462 struct afs_icl_log *afs_icl_allLogs = 0;
463
464 /* function to purge records from the start of the log, until there
465  * is at least minSpace long's worth of space available without
466  * making the head and the tail point to the same word.
467  *
468  * Log must be write-locked.
469  */
470 static void
471 afs_icl_GetLogSpace(struct afs_icl_log *logp, afs_int32 minSpace)
472 {
473     unsigned int tsize;
474
475     while (logp->logSize - logp->logElements <= minSpace) {
476         /* eat a record */
477         tsize = ((logp->datap[logp->firstUsed]) >> 24) & 0xff;
478         logp->logElements -= tsize;
479         logp->firstUsed += tsize;
480         if (logp->firstUsed >= logp->logSize)
481             logp->firstUsed -= logp->logSize;
482         logp->baseCookie += tsize;
483     }
484 }
485
486 /* append string astr to buffer, including terminating null char.
487  *
488  * log must be write-locked.
489  */
490 #define ICL_CHARSPERLONG        4
491 static void
492 afs_icl_AppendString(struct afs_icl_log *logp, char *astr)
493 {
494     char *op;                   /* ptr to char to write */
495     int tc;
496     int bib;            /* bytes in buffer */
497
498     bib = 0;
499     op = (char *)&(logp->datap[logp->firstFree]);
500     while (1) {
501         tc = *astr++;
502         *op++ = tc;
503         if (++bib >= ICL_CHARSPERLONG) {
504             /* new word */
505             bib = 0;
506             if (++(logp->firstFree) >= logp->logSize) {
507                 logp->firstFree = 0;
508                 op = (char *)&(logp->datap[0]);
509             }
510             logp->logElements++;
511         }
512         if (tc == 0)
513             break;
514     }
515     if (bib > 0) {
516         /* if we've used this word at all, allocate it */
517         if (++(logp->firstFree) >= logp->logSize) {
518             logp->firstFree = 0;
519         }
520         logp->logElements++;
521     }
522 }
523
524 /* add a long to the log, ignoring overflow (checked already) */
525 #define ICL_APPENDINT32(lp, x) \
526     MACRO_BEGIN \
527         (lp)->datap[(lp)->firstFree] = (x); \
528         if (++((lp)->firstFree) >= (lp)->logSize) { \
529                 (lp)->firstFree = 0; \
530         } \
531         (lp)->logElements++; \
532     MACRO_END
533
534 #if ICL_LONG == 2
535 #define ICL_APPENDLONG(lp, x) \
536     MACRO_BEGIN \
537         ICL_APPENDINT32((lp), ((x) >> 32) & 0xffffffffL); \
538         ICL_APPENDINT32((lp), (x) & 0xffffffffL); \
539     MACRO_END
540
541 #else
542 #define ICL_APPENDLONG(lp, x) ICL_APPENDINT32((lp), (x))
543 #endif
544
545 /* routine to tell whether we're dealing with the address or the
546  * object itself
547  */
548 int
549 afs_icl_UseAddr(int type)
550 {
551     if (type == ICL_TYPE_HYPER || type == ICL_TYPE_STRING
552         || type == ICL_TYPE_FID || type == ICL_TYPE_INT64)
553         return 1;
554     else
555         return 0;
556 }
557
558 void
559 afs_icl_AppendOne(struct afs_icl_log *logp, int type, long parm)
560 {
561     if (type) {
562         /* marshall parameter 3 now */
563         if (type == ICL_TYPE_STRING)
564             afs_icl_AppendString(logp, (char *)parm);
565         else if (type == ICL_TYPE_HYPER) {
566             ICL_APPENDINT32(logp,
567                             (afs_int32) ((struct afs_hyper_t *)parm)->high);
568             ICL_APPENDINT32(logp,
569                             (afs_int32) ((struct afs_hyper_t *)parm)->low);
570         } else if (type == ICL_TYPE_INT64) {
571 #ifndef WORDS_BIGENDIAN
572 #ifdef AFS_64BIT_CLIENT
573             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
574             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
575 #else /* AFS_64BIT_CLIENT */
576             ICL_APPENDINT32(logp, (afs_int32) parm);
577             ICL_APPENDINT32(logp, (afs_int32) 0);
578 #endif /* AFS_64BIT_CLIENT */
579 #else /* AFSLITTLE_ENDIAN */
580 #ifdef AFS_64BIT_CLIENT
581             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
582             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
583 #else /* AFS_64BIT_CLIENT */
584             ICL_APPENDINT32(logp, (afs_int32) 0);
585             ICL_APPENDINT32(logp, (afs_int32) parm);
586 #endif /* AFS_64BIT_CLIENT */
587 #endif /* AFSLITTLE_ENDIAN */
588         } else if (type == ICL_TYPE_FID) {
589             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
590             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
591             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[2]);
592             ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[3]);
593         }
594 #if ICL_LONG == 2
595         else if (type == ICL_TYPE_INT32)
596             ICL_APPENDINT32(logp, (afs_int32) parm);
597 #endif
598         else
599             ICL_APPENDLONG(logp, parm);
600     }
601 }
602
603 /* Function to append a record to the log.  Written for speed
604  * since we know that we're going to have to make this work fast
605  * pretty soon, anyway.  The log must be unlocked.
606  */
607
608 void
609 afs_icl_AppendRecord(struct afs_icl_log *logp, afs_int32 op,
610                      afs_int32 types, long p1, long p2, long p3, long p4)
611 {
612     int rsize;                  /* record size in longs */
613     int tsize;          /* temp size */
614     osi_timeval_t tv;
615     int t1, t2, t3, t4;
616
617     t4 = types & 0x3f;          /* decode types */
618     types >>= 6;
619     t3 = types & 0x3f;
620     types >>= 6;
621     t2 = types & 0x3f;
622     types >>= 6;
623     t1 = types & 0x3f;
624
625     osi_GetTime(&tv);           /* It panics for solaris if inside */
626     ObtainWriteLock(&logp->lock, 182);
627     if (!logp->datap) {
628         ReleaseWriteLock(&logp->lock);
629         return;
630     }
631
632     /* get timestamp as # of microseconds since some time that doesn't
633      * change that often.  This algorithm ticks over every 20 minutes
634      * or so (1000 seconds).  Write a timestamp record if it has.
635      */
636     if (tv.tv_sec - logp->lastTS > 1024) {
637         /* the timer has wrapped -- write a timestamp record */
638         if (logp->logSize - logp->logElements <= 5)
639             afs_icl_GetLogSpace(logp, 5);
640
641         ICL_APPENDINT32(logp,
642                         (afs_int32) (5 << 24) + (ICL_TYPE_UNIXDATE << 18));
643         ICL_APPENDINT32(logp, (afs_int32) ICL_INFO_TIMESTAMP);
644         ICL_APPENDINT32(logp, (afs_int32) 0);   /* use thread ID zero for clocks */
645         ICL_APPENDINT32(logp,
646                         (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 +
647                         tv.tv_usec);
648         ICL_APPENDINT32(logp, (afs_int32) tv.tv_sec);
649
650         logp->lastTS = tv.tv_sec;
651     }
652
653     rsize = 4;                  /* base case: see 4 items below */
654     if (t1) {
655         /* compute size of parameter p1.  Only tricky case is string.
656          * In that case, we have to call strlen to get the string length.
657          */
658         ICL_SIZEHACK(t1, p1, tsize, rsize);
659     }
660     if (t2) {
661         /* compute size of parameter p2.  Only tricky case is string.
662          * In that case, we have to call strlen to get the string length.
663          */
664         ICL_SIZEHACK(t2, p2, tsize, rsize);
665     }
666     if (t3) {
667         /* compute size of parameter p3.  Only tricky case is string.
668          * In that case, we have to call strlen to get the string length.
669          */
670         ICL_SIZEHACK(t3, p3, tsize, rsize);
671     }
672     if (t4) {
673         /* compute size of parameter p4.  Only tricky case is string.
674          * In that case, we have to call strlen to get the string length.
675          */
676         ICL_SIZEHACK(t4, p4, tsize, rsize);
677     }
678
679     /* At this point, we've computed all of the parameter sizes, and
680      * have in rsize the size of the entire record we want to append.
681      * Next, we check that we actually have room in the log to do this
682      * work, and then we do the append.
683      */
684     if (rsize > 255) {
685         ReleaseWriteLock(&logp->lock);
686         return;                 /* log record too big to express */
687     }
688
689     if (logp->logSize - logp->logElements <= rsize)
690         afs_icl_GetLogSpace(logp, rsize);
691
692     ICL_APPENDINT32(logp,
693                     (afs_int32) (rsize << 24) + (t1 << 18) + (t2 << 12) +
694                     (t3 << 6) + t4);
695     ICL_APPENDINT32(logp, (afs_int32) op);
696     ICL_APPENDINT32(logp, (afs_int32) osi_ThreadUnique());
697     ICL_APPENDINT32(logp,
698                     (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 + tv.tv_usec);
699
700     afs_icl_AppendOne(logp, t1, p1);
701     afs_icl_AppendOne(logp, t2, p2);
702     afs_icl_AppendOne(logp, t3, p3);
703     afs_icl_AppendOne(logp, t4, p4);
704     ReleaseWriteLock(&logp->lock);
705 }
706
707 /* create a log with size logSize; return it in *outLogpp and tag
708  * it with name "name."
709  */
710 int
711 afs_icl_CreateLog(char *name, afs_int32 logSize,
712                   struct afs_icl_log **outLogpp)
713 {
714     return afs_icl_CreateLogWithFlags(name, logSize, /*flags */ 0, outLogpp);
715 }
716
717 /* create a log with size logSize; return it in *outLogpp and tag
718  * it with name "name."  'flags' can be set to make the log unclearable.
719  */
720 int
721 afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, afs_uint32 flags,
722                            struct afs_icl_log **outLogpp)
723 {
724     struct afs_icl_log *logp;
725
726     /* add into global list under lock */
727     ObtainWriteLock(&afs_icl_lock, 183);
728     if (!afs_icl_inited)
729         afs_icl_Init();
730
731     for (logp = afs_icl_allLogs; logp; logp = logp->nextp) {
732         if (strcmp(logp->name, name) == 0) {
733             /* found it already created, just return it */
734             logp->refCount++;
735             *outLogpp = logp;
736             if (flags & ICL_CRLOG_FLAG_PERSISTENT) {
737                 ObtainWriteLock(&logp->lock, 184);
738                 logp->states |= ICL_LOGF_PERSISTENT;
739                 ReleaseWriteLock(&logp->lock);
740             }
741             ReleaseWriteLock(&afs_icl_lock);
742             return 0;
743         }
744     }
745
746     logp = (struct afs_icl_log *)
747         osi_AllocSmallSpace(sizeof(struct afs_icl_log));
748     memset((caddr_t) logp, 0, sizeof(*logp));
749
750     logp->refCount = 1;
751     logp->name = osi_AllocSmallSpace(strlen(name) + 1);
752     strcpy(logp->name, name);
753     LOCK_INIT(&logp->lock, "logp lock");
754     logp->logSize = logSize;
755     logp->datap = NULL;         /* don't allocate it until we need it */
756
757     if (flags & ICL_CRLOG_FLAG_PERSISTENT)
758         logp->states |= ICL_LOGF_PERSISTENT;
759
760     logp->nextp = afs_icl_allLogs;
761     afs_icl_allLogs = logp;
762     ReleaseWriteLock(&afs_icl_lock);
763
764     *outLogpp = logp;
765     return 0;
766 }
767
768 /* called with a log, a pointer to a buffer, the size of the buffer
769  * (in *bufSizep), the starting cookie (in *cookiep, use 0 at the start)
770  * and returns data in the provided buffer, and returns output flags
771  * in *flagsp.  The flag ICL_COPYOUTF_MISSEDSOME is set if we can't
772  * find the record with cookie value cookie.
773  */
774 int
775 afs_icl_CopyOut(struct afs_icl_log *logp, afs_int32 * bufferp,
776                 afs_int32 * bufSizep, afs_uint32 * cookiep,
777                 afs_int32 * flagsp)
778 {
779     afs_int32 nwords;           /* number of words to copy out */
780     afs_uint32 startCookie;     /* first cookie to use */
781     afs_int32 outWords;         /* words we've copied out */
782     afs_int32 inWords;          /* max words to copy out */
783     afs_int32 code;             /* return code */
784     afs_int32 ix;               /* index we're copying from */
785     afs_int32 outFlags;         /* return flags */
786     afs_int32 inFlags;          /* flags passed in */
787     afs_int32 end;
788
789     inWords = *bufSizep;        /* max to copy out */
790     outWords = 0;               /* amount copied out */
791     startCookie = *cookiep;
792     outFlags = 0;
793     inFlags = *flagsp;
794     code = 0;
795
796     ObtainWriteLock(&logp->lock, 185);
797     if (!logp->datap) {
798         ReleaseWriteLock(&logp->lock);
799         goto done;
800     }
801
802     /* first, compute the index of the start cookie we've been passed */
803     while (1) {
804         /* (re-)compute where we should start */
805         if (startCookie < logp->baseCookie) {
806             if (startCookie)    /* missed some output */
807                 outFlags |= ICL_COPYOUTF_MISSEDSOME;
808             /* skip to the first available record */
809             startCookie = logp->baseCookie;
810             *cookiep = startCookie;
811         }
812
813         /* compute where we find the first element to copy out */
814         ix = logp->firstUsed + startCookie - logp->baseCookie;
815         if (ix >= logp->logSize)
816             ix -= logp->logSize;
817
818         /* if have some data now, break out and process it */
819         if (startCookie - logp->baseCookie < logp->logElements)
820             break;
821
822         /* At end of log, so clear it if we need to */
823         if (inFlags & ICL_COPYOUTF_CLRAFTERREAD) {
824             logp->firstUsed = logp->firstFree = 0;
825             logp->logElements = 0;
826         }
827         /* otherwise, either wait for the data to arrive, or return */
828         if (!(inFlags & ICL_COPYOUTF_WAITIO)) {
829             ReleaseWriteLock(&logp->lock);
830             code = 0;
831             goto done;
832         }
833         logp->states |= ICL_LOGF_WAITING;
834         ReleaseWriteLock(&logp->lock);
835         afs_osi_Sleep(&logp->lock);
836         ObtainWriteLock(&logp->lock, 186);
837     }
838     /* copy out data from ix to logSize or firstFree, depending
839      * upon whether firstUsed <= firstFree (no wrap) or otherwise.
840      * be careful not to copy out more than nwords.
841      */
842     if (ix >= logp->firstUsed) {
843         if (logp->firstUsed <= logp->firstFree)
844             /* no wrapping */
845             end = logp->firstFree;      /* first element not to copy */
846         else
847             end = logp->logSize;
848         nwords = inWords;       /* don't copy more than this */
849         if (end - ix < nwords)
850             nwords = end - ix;
851         if (nwords > 0) {
852             memcpy((char *)bufferp, (char *)&logp->datap[ix],
853                    sizeof(afs_int32) * nwords);
854             outWords += nwords;
855             inWords -= nwords;
856             bufferp += nwords;
857         }
858         /* if we're going to copy more out below, we'll start here */
859         ix = 0;
860     }
861     /* now, if active part of the log has wrapped, there's more stuff
862      * starting at the head of the log.  Copy out more from there.
863      */
864     if (logp->firstUsed > logp->firstFree && ix < logp->firstFree
865         && inWords > 0) {
866         /* (more to) copy out from the wrapped section at the
867          * start of the log.  May get here even if didn't copy any
868          * above, if the cookie points directly into the wrapped section.
869          */
870         nwords = inWords;
871         if (logp->firstFree - ix < nwords)
872             nwords = logp->firstFree - ix;
873         memcpy((char *)bufferp, (char *)&logp->datap[ix],
874                sizeof(afs_int32) * nwords);
875         outWords += nwords;
876         inWords -= nwords;
877         bufferp += nwords;
878     }
879
880     ReleaseWriteLock(&logp->lock);
881
882   done:
883     if (code == 0) {
884         *bufSizep = outWords;
885         *flagsp = outFlags;
886     }
887     return code;
888 }
889
890 /* return basic parameter information about a log */
891 int
892 afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep,
893                     afs_int32 * curSizep)
894 {
895     ObtainReadLock(&logp->lock);
896     *maxSizep = logp->logSize;
897     *curSizep = logp->logElements;
898     ReleaseReadLock(&logp->lock);
899     return 0;
900 }
901
902
903 /* hold and release logs */
904 int
905 afs_icl_LogHold(struct afs_icl_log *logp)
906 {
907     ObtainWriteLock(&afs_icl_lock, 187);
908     logp->refCount++;
909     ReleaseWriteLock(&afs_icl_lock);
910     return 0;
911 }
912
913 /* hold and release logs, called with lock already held */
914 int
915 afs_icl_LogHoldNL(struct afs_icl_log *logp)
916 {
917     logp->refCount++;
918     return 0;
919 }
920
921 /* keep track of how many sets believe the log itself is allocated */
922 int
923 afs_icl_LogUse(struct afs_icl_log *logp)
924 {
925     ObtainWriteLock(&logp->lock, 188);
926     if (logp->setCount == 0) {
927         /* this is the first set actually using the log -- allocate it */
928         if (logp->logSize == 0) {
929             /* we weren't passed in a hint and it wasn't set */
930             logp->logSize = ICL_DEFAULT_LOGSIZE;
931         }
932         logp->datap = afs_osi_Alloc(sizeof(afs_int32) * logp->logSize);
933         osi_Assert(logp->datap != NULL);
934 #ifdef  KERNEL_HAVE_PIN
935         pin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
936 #endif
937     }
938     logp->setCount++;
939     ReleaseWriteLock(&logp->lock);
940     return 0;
941 }
942
943 /* decrement the number of real users of the log, free if possible */
944 int
945 afs_icl_LogFreeUse(struct afs_icl_log *logp)
946 {
947     ObtainWriteLock(&logp->lock, 189);
948     if (--logp->setCount == 0) {
949         /* no more users -- free it (but keep log structure around) */
950         afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
951 #ifdef  KERNEL_HAVE_PIN
952         unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
953 #endif
954         logp->firstUsed = logp->firstFree = 0;
955         logp->logElements = 0;
956         logp->datap = NULL;
957     }
958     ReleaseWriteLock(&logp->lock);
959     return 0;
960 }
961
962 /* set the size of the log to 'logSize' */
963 int
964 afs_icl_LogSetSize(struct afs_icl_log *logp, afs_int32 logSize)
965 {
966     ObtainWriteLock(&logp->lock, 190);
967     if (!logp->datap) {
968         /* nothing to worry about since it's not allocated */
969         logp->logSize = logSize;
970     } else {
971         /* reset log */
972         logp->firstUsed = logp->firstFree = 0;
973         logp->logElements = 0;
974
975         /* free and allocate a new one */
976         afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
977 #ifdef  KERNEL_HAVE_PIN
978         unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
979 #endif
980         logp->datap = afs_osi_Alloc(sizeof(afs_int32) * logSize);
981         osi_Assert(logp->datap != NULL);
982 #ifdef  KERNEL_HAVE_PIN
983         pin((char *)logp->datap, sizeof(afs_int32) * logSize);
984 #endif
985         logp->logSize = logSize;
986     }
987     ReleaseWriteLock(&logp->lock);
988
989     return 0;
990 }
991
992 /* free a log.  Called with afs_icl_lock locked. */
993 int
994 afs_icl_ZapLog(struct afs_icl_log *logp)
995 {
996     struct afs_icl_log **lpp, *tp;
997
998     for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
999         if (tp == logp) {
1000             /* found the dude we want to remove */
1001             *lpp = logp->nextp;
1002             osi_FreeSmallSpace(logp->name);
1003             afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1004 #ifdef KERNEL_HAVE_PIN
1005             unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
1006 #endif
1007             osi_FreeSmallSpace(logp);
1008             break;              /* won't find it twice */
1009         }
1010     }
1011     return 0;
1012 }
1013
1014 /* do the release, watching for deleted entries */
1015 int
1016 afs_icl_LogRele(struct afs_icl_log *logp)
1017 {
1018     ObtainWriteLock(&afs_icl_lock, 191);
1019     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1020         afs_icl_ZapLog(logp);   /* destroys logp's lock! */
1021     }
1022     ReleaseWriteLock(&afs_icl_lock);
1023     return 0;
1024 }
1025
1026 /* do the release, watching for deleted entries, log already held */
1027 int
1028 afs_icl_LogReleNL(struct afs_icl_log *logp)
1029 {
1030     if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1031         afs_icl_ZapLog(logp);   /* destroys logp's lock! */
1032     }
1033     return 0;
1034 }
1035
1036 /* zero out the log */
1037 int
1038 afs_icl_ZeroLog(struct afs_icl_log *logp)
1039 {
1040     ObtainWriteLock(&logp->lock, 192);
1041     logp->firstUsed = logp->firstFree = 0;
1042     logp->logElements = 0;
1043     logp->baseCookie = 0;
1044     ReleaseWriteLock(&logp->lock);
1045     return 0;
1046 }
1047
1048 /* free a log entry, and drop its reference count */
1049 int
1050 afs_icl_LogFree(struct afs_icl_log *logp)
1051 {
1052     ObtainWriteLock(&logp->lock, 193);
1053     logp->states |= ICL_LOGF_DELETED;
1054     ReleaseWriteLock(&logp->lock);
1055     afs_icl_LogRele(logp);
1056     return 0;
1057 }
1058
1059 /* find a log by name, returning it held */
1060 struct afs_icl_log *
1061 afs_icl_FindLog(char *name)
1062 {
1063     struct afs_icl_log *tp;
1064     ObtainWriteLock(&afs_icl_lock, 194);
1065     for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
1066         if (strcmp(tp->name, name) == 0) {
1067             /* this is the dude we want */
1068             tp->refCount++;
1069             break;
1070         }
1071     }
1072     ReleaseWriteLock(&afs_icl_lock);
1073     return tp;
1074 }
1075
1076 int
1077 afs_icl_EnumerateLogs(int (*aproc)
1078                         (char *name, char *arock, struct afs_icl_log * tp),
1079                       char *arock)
1080 {
1081     struct afs_icl_log *tp;
1082     afs_int32 code;
1083
1084     code = 0;
1085     ObtainWriteLock(&afs_icl_lock, 195);
1086     for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
1087         tp->refCount++;         /* hold this guy */
1088         ReleaseWriteLock(&afs_icl_lock);
1089         ObtainReadLock(&tp->lock);
1090         code = (*aproc) (tp->name, arock, tp);
1091         ReleaseReadLock(&tp->lock);
1092         ObtainWriteLock(&afs_icl_lock, 196);
1093         if (--tp->refCount == 0)
1094             afs_icl_ZapLog(tp);
1095         if (code)
1096             break;
1097     }
1098     ReleaseWriteLock(&afs_icl_lock);
1099     return code;
1100 }
1101
1102 struct afs_icl_set *afs_icl_allSets = 0;
1103
1104 int
1105 afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
1106                   struct afs_icl_log *fatalLogp,
1107                   struct afs_icl_set **outSetpp)
1108 {
1109     return afs_icl_CreateSetWithFlags(name, baseLogp, fatalLogp,
1110                                       /*flags */ 0, outSetpp);
1111 }
1112
1113 /* create a set, given pointers to base and fatal logs, if any.
1114  * Logs are unlocked, but referenced, and *outSetpp is returned
1115  * referenced.  Function bumps reference count on logs, since it
1116  * addds references from the new afs_icl_set.  When the set is destroyed,
1117  * those references will be released.
1118  */
1119 int
1120 afs_icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
1121                            struct afs_icl_log *fatalLogp, afs_uint32 flags,
1122                            struct afs_icl_set **outSetpp)
1123 {
1124     struct afs_icl_set *setp;
1125     int i;
1126     afs_int32 states = ICL_DEFAULT_SET_STATES;
1127
1128     ObtainWriteLock(&afs_icl_lock, 197);
1129     if (!afs_icl_inited)
1130         afs_icl_Init();
1131
1132     for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
1133         if (strcmp(setp->name, name) == 0) {
1134             setp->refCount++;
1135             *outSetpp = setp;
1136             if (flags & ICL_CRSET_FLAG_PERSISTENT) {
1137                 ObtainWriteLock(&setp->lock, 198);
1138                 setp->states |= ICL_SETF_PERSISTENT;
1139                 ReleaseWriteLock(&setp->lock);
1140             }
1141             ReleaseWriteLock(&afs_icl_lock);
1142             return 0;
1143         }
1144     }
1145
1146     /* determine initial state */
1147     if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
1148         states = ICL_SETF_ACTIVE;
1149     else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
1150         states = ICL_SETF_FREED;
1151     if (flags & ICL_CRSET_FLAG_PERSISTENT)
1152         states |= ICL_SETF_PERSISTENT;
1153
1154     setp = (struct afs_icl_set *)osi_AllocSmallSpace(sizeof(struct afs_icl_set));
1155     memset((caddr_t) setp, 0, sizeof(*setp));
1156     setp->refCount = 1;
1157     if (states & ICL_SETF_FREED)
1158         states &= ~ICL_SETF_ACTIVE;     /* if freed, can't be active */
1159     setp->states = states;
1160
1161     LOCK_INIT(&setp->lock, "setp lock");
1162     /* next lock is obtained in wrong order, hierarchy-wise, but
1163      * it doesn't matter, since no one can find this lock yet, since
1164      * the afs_icl_lock is still held, and thus the obtain can't block.
1165      */
1166     ObtainWriteLock(&setp->lock, 199);
1167     setp->name = osi_AllocSmallSpace(strlen(name) + 1);
1168     strcpy(setp->name, name);
1169     setp->nevents = ICL_DEFAULTEVENTS;
1170     setp->eventFlags = afs_osi_Alloc(ICL_DEFAULTEVENTS);
1171     osi_Assert(setp->eventFlags != NULL);
1172 #ifdef  KERNEL_HAVE_PIN
1173     pin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
1174 #endif
1175     for (i = 0; i < ICL_DEFAULTEVENTS; i++)
1176         setp->eventFlags[i] = 0xff;     /* default to enabled */
1177
1178     /* update this global info under the afs_icl_lock */
1179     setp->nextp = afs_icl_allSets;
1180     afs_icl_allSets = setp;
1181     ReleaseWriteLock(&afs_icl_lock);
1182
1183     /* set's basic lock is still held, so we can finish init */
1184     if (baseLogp) {
1185         setp->logs[0] = baseLogp;
1186         afs_icl_LogHold(baseLogp);
1187         if (!(setp->states & ICL_SETF_FREED))
1188             afs_icl_LogUse(baseLogp);   /* log is actually being used */
1189     }
1190     if (fatalLogp) {
1191         setp->logs[1] = fatalLogp;
1192         afs_icl_LogHold(fatalLogp);
1193         if (!(setp->states & ICL_SETF_FREED))
1194             afs_icl_LogUse(fatalLogp);  /* log is actually being used */
1195     }
1196     ReleaseWriteLock(&setp->lock);
1197
1198     *outSetpp = setp;
1199     return 0;
1200 }
1201
1202 /* function to change event enabling information for a particular set */
1203 int
1204 afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
1205 {
1206     char *tp;
1207
1208     ObtainWriteLock(&setp->lock, 200);
1209     if (!ICL_EVENTOK(setp, eventID)) {
1210         ReleaseWriteLock(&setp->lock);
1211         return -1;
1212     }
1213     tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
1214     if (setValue)
1215         *tp |= ICL_EVENTMASK(eventID);
1216     else
1217         *tp &= ~(ICL_EVENTMASK(eventID));
1218     ReleaseWriteLock(&setp->lock);
1219     return 0;
1220 }
1221
1222 /* return indication of whether a particular event ID is enabled
1223  * for tracing.  If *getValuep is set to 0, the event is disabled,
1224  * otherwise it is enabled.  All events start out enabled by default.
1225  */
1226 int
1227 afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
1228 {
1229     ObtainReadLock(&setp->lock);
1230     if (!ICL_EVENTOK(setp, eventID)) {
1231         ReleaseWriteLock(&setp->lock);
1232         return -1;
1233     }
1234     if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
1235         *getValuep = 1;
1236     else
1237         *getValuep = 0;
1238     ReleaseReadLock(&setp->lock);
1239     return 0;
1240 }
1241
1242 /* hold and release event sets */
1243 int
1244 afs_icl_SetHold(struct afs_icl_set *setp)
1245 {
1246     ObtainWriteLock(&afs_icl_lock, 201);
1247     setp->refCount++;
1248     ReleaseWriteLock(&afs_icl_lock);
1249     return 0;
1250 }
1251
1252 /* free a set.  Called with afs_icl_lock locked */
1253 int
1254 afs_icl_ZapSet(struct afs_icl_set *setp)
1255 {
1256     struct afs_icl_set **lpp, *tp;
1257     int i;
1258     struct afs_icl_log *tlp;
1259
1260     for (lpp = &afs_icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1261         if (tp == setp) {
1262             /* found the dude we want to remove */
1263             *lpp = setp->nextp;
1264             osi_FreeSmallSpace(setp->name);
1265             afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
1266 #ifdef  KERNEL_HAVE_PIN
1267             unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
1268 #endif
1269             for (i = 0; i < ICL_LOGSPERSET; i++) {
1270                 if ((tlp = setp->logs[i]))
1271                     afs_icl_LogReleNL(tlp);
1272             }
1273             osi_FreeSmallSpace(setp);
1274             break;              /* won't find it twice */
1275         }
1276     }
1277     return 0;
1278 }
1279
1280 /* do the release, watching for deleted entries */
1281 int
1282 afs_icl_SetRele(struct afs_icl_set *setp)
1283 {
1284     ObtainWriteLock(&afs_icl_lock, 202);
1285     if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
1286         afs_icl_ZapSet(setp);   /* destroys setp's lock! */
1287     }
1288     ReleaseWriteLock(&afs_icl_lock);
1289     return 0;
1290 }
1291
1292 /* free a set entry, dropping its reference count */
1293 int
1294 afs_icl_SetFree(struct afs_icl_set *setp)
1295 {
1296     ObtainWriteLock(&setp->lock, 203);
1297     setp->states |= ICL_SETF_DELETED;
1298     ReleaseWriteLock(&setp->lock);
1299     afs_icl_SetRele(setp);
1300     return 0;
1301 }
1302
1303 /* find a set by name, returning it held */
1304 struct afs_icl_set *
1305 afs_icl_FindSet(char *name)
1306 {
1307     struct afs_icl_set *tp;
1308     ObtainWriteLock(&afs_icl_lock, 204);
1309     for (tp = afs_icl_allSets; tp; tp = tp->nextp) {
1310         if (strcmp(tp->name, name) == 0) {
1311             /* this is the dude we want */
1312             tp->refCount++;
1313             break;
1314         }
1315     }
1316     ReleaseWriteLock(&afs_icl_lock);
1317     return tp;
1318 }
1319
1320 /* zero out all the logs in the set */
1321 int
1322 afs_icl_ZeroSet(struct afs_icl_set *setp)
1323 {
1324     int i;
1325     int code = 0;
1326     int tcode;
1327     struct afs_icl_log *logp;
1328
1329     ObtainReadLock(&setp->lock);
1330     for (i = 0; i < ICL_LOGSPERSET; i++) {
1331         logp = setp->logs[i];
1332         if (logp) {
1333             afs_icl_LogHold(logp);
1334             tcode = afs_icl_ZeroLog(logp);
1335             if (tcode != 0)
1336                 code = tcode;   /* save the last bad one */
1337             afs_icl_LogRele(logp);
1338         }
1339     }
1340     ReleaseReadLock(&setp->lock);
1341     return code;
1342 }
1343
1344 int
1345 afs_icl_EnumerateSets(int (*aproc)
1346                         (char *name, char *arock, struct afs_icl_log * tp),
1347                       char *arock)
1348 {
1349     struct afs_icl_set *tp, *np;
1350     afs_int32 code;
1351
1352     code = 0;
1353     ObtainWriteLock(&afs_icl_lock, 205);
1354     for (tp = afs_icl_allSets; tp; tp = np) {
1355         tp->refCount++;         /* hold this guy */
1356         ReleaseWriteLock(&afs_icl_lock);
1357         code = (*aproc) (tp->name, arock, (struct afs_icl_log *)tp);
1358         ObtainWriteLock(&afs_icl_lock, 206);
1359         np = tp->nextp;         /* tp may disappear next, but not np */
1360         if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
1361             afs_icl_ZapSet(tp);
1362         if (code)
1363             break;
1364     }
1365     ReleaseWriteLock(&afs_icl_lock);
1366     return code;
1367 }
1368
1369 int
1370 afs_icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
1371 {
1372     int i;
1373     int code = -1;
1374
1375     ObtainWriteLock(&setp->lock, 207);
1376     for (i = 0; i < ICL_LOGSPERSET; i++) {
1377         if (!setp->logs[i]) {
1378             setp->logs[i] = newlogp;
1379             code = i;
1380             afs_icl_LogHold(newlogp);
1381             if (!(setp->states & ICL_SETF_FREED)) {
1382                 /* bump up the number of sets using the log */
1383                 afs_icl_LogUse(newlogp);
1384             }
1385             break;
1386         }
1387     }
1388     ReleaseWriteLock(&setp->lock);
1389     return code;
1390 }
1391
1392 int
1393 afs_icl_SetSetStat(struct afs_icl_set *setp, int op)
1394 {
1395     int i;
1396     afs_int32 code;
1397     struct afs_icl_log *logp;
1398
1399     ObtainWriteLock(&setp->lock, 208);
1400     switch (op) {
1401     case ICL_OP_SS_ACTIVATE:    /* activate a log */
1402         /*
1403          * If we are not already active, see if we have released
1404          * our demand that the log be allocated (FREED set).  If
1405          * we have, reassert our desire.
1406          */
1407         if (!(setp->states & ICL_SETF_ACTIVE)) {
1408             if (setp->states & ICL_SETF_FREED) {
1409                 /* have to reassert desire for logs */
1410                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1411                     logp = setp->logs[i];
1412                     if (logp) {
1413                         afs_icl_LogHold(logp);
1414                         afs_icl_LogUse(logp);
1415                         afs_icl_LogRele(logp);
1416                     }
1417                 }
1418                 setp->states &= ~ICL_SETF_FREED;
1419             }
1420             setp->states |= ICL_SETF_ACTIVE;
1421         }
1422         code = 0;
1423         break;
1424
1425     case ICL_OP_SS_DEACTIVATE:  /* deactivate a log */
1426         /* this doesn't require anything beyond clearing the ACTIVE flag */
1427         setp->states &= ~ICL_SETF_ACTIVE;
1428         code = 0;
1429         break;
1430
1431     case ICL_OP_SS_FREE:        /* deassert design for log */
1432         /*
1433          * if we are already in this state, do nothing; otherwise
1434          * deassert desire for log
1435          */
1436         if (setp->states & ICL_SETF_ACTIVE)
1437             code = EINVAL;
1438         else {
1439             if (!(setp->states & ICL_SETF_FREED)) {
1440                 for (i = 0; i < ICL_LOGSPERSET; i++) {
1441                     logp = setp->logs[i];
1442                     if (logp) {
1443                         afs_icl_LogHold(logp);
1444                         afs_icl_LogFreeUse(logp);
1445                         afs_icl_LogRele(logp);
1446                     }
1447                 }
1448                 setp->states |= ICL_SETF_FREED;
1449             }
1450             code = 0;
1451         }
1452         break;
1453
1454     default:
1455         code = EINVAL;
1456     }
1457     ReleaseWriteLock(&setp->lock);
1458     return code;
1459 }