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