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