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