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