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