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