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