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