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