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