2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "afs/param.h"
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)
21 #include "h/hashing.h"
23 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_DARWIN_ENV)
24 #include "netinet/in_var.h"
26 #endif /* !defined(UKERNEL) */
29 struct afs_icl_set *afs_iclSetp = (struct afs_icl_set *)0;
30 struct afs_icl_set *afs_iclLongTermSetp = (struct afs_icl_set *)0;
32 /* Matches below where ICL_APPENDLONG is 2 INT32s */
33 #if (defined(AFS_SGI61_ENV) && (_MIPS_SZLONG==64)) || (defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)) || defined(AFS_DARWIN_ENV) && defined(__amd64__)
39 int afs_icl_sizeofLong = ICL_LONG;
41 int afs_icl_inited = 0;
43 /* init function, called once, under afs_icl_lock */
51 /* Function called at shutdown - zap everything */
55 struct afs_icl_log *logp;
56 struct afs_icl_set *setp;
58 setp = afs_icl_FindSet("cm");
60 /* Release the reference from Find, and the initial one */
61 afs_icl_SetFree(setp);
62 afs_icl_SetFree(setp);
64 setp = afs_icl_FindSet("cmlongterm");
66 /* Release the reference from Find, and the initial one */
67 afs_icl_SetFree(setp);
68 afs_icl_SetFree(setp);
70 logp = afs_icl_FindLog("cmfx");
72 /* Release the reference from Find, and the initial one */
73 afs_icl_LogFree(logp);
74 afs_icl_LogFree(logp);
79 afs_icl_InitLogs(void)
81 struct afs_icl_log *logp;
84 /* initialize the ICL system */
85 code = afs_icl_CreateLog("cmfx", 60 * 1024, &logp);
89 code = afs_icl_CreateSetWithFlags("cm", logp, NULL,
90 ICL_CRSET_FLAG_DEFAULT_OFF,
95 code = afs_icl_CreateSet("cmlongterm", logp, NULL,
96 &afs_iclLongTermSetp);
101 struct afs_icl_log *afs_icl_FindLog(char *);
102 struct afs_icl_set *afs_icl_FindSet(char *);
105 #ifdef AFS_DARWIN100_ENV
106 #define AFSKPTR(X) k ## X
108 Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
110 return Afscall64_icl(opcode,
111 CAST_USER_ADDR_T((p1)),
112 CAST_USER_ADDR_T((p2)),
113 CAST_USER_ADDR_T((p3)),
114 CAST_USER_ADDR_T((p4)),
118 #define AFSKPTR(X) ((caddr_t)X)
122 #ifdef AFS_DARWIN100_ENV
123 Afscall64_icl(int opcode, user_addr_t kp1, user_addr_t kp2, user_addr_t kp3, user_addr_t kp4, int *retval)
125 Afscall_icl(long opcode, long p1, long p2, long p3, long p4, long *retval)
128 afs_int32 *lp, elts, flags;
130 struct afs_icl_log *logp;
131 struct afs_icl_set *setp;
132 #if defined(AFS_SGI61_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
134 #else /* AFS_SGI61_ENV */
135 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
140 #endif /* AFS_SGI61_ENV */
142 afs_int32 startCookie;
144 struct afs_icl_log *tlp;
145 #ifdef AFS_DARWIN100_ENV
146 afs_uint32 p1 = (afs_uint32)kp1;
147 afs_uint32 p2 = (afs_uint32)kp2;
148 afs_uint32 p3 = (afs_uint32)kp3;
149 afs_uint32 p4 = (afs_uint32)kp4;
153 if (!afs_suser(CRED())) { /* only root can run this code */
157 if (!afs_suser(NULL)) { /* only root can run this code */
158 #if defined(KERNEL_HAVE_UERROR)
167 case ICL_OP_COPYOUTCLR: /* copy out data then clear */
168 case ICL_OP_COPYOUT: /* copy ouy data */
169 /* copyout: p1=logname, p2=&buffer, p3=size(words), p4=&cookie
170 * return flags<<24 + nwords.
171 * updates cookie to updated start (not end) if we had to
174 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
177 AFS_COPYIN(AFSKPTR(p4), (char *)&startCookie, sizeof(afs_int32), code);
180 logp = afs_icl_FindLog(tname);
183 #define BUFFERSIZE AFS_LRALLOCSIZ
184 lp = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
185 elts = BUFFERSIZE / sizeof(afs_int32);
188 flags = (opcode == ICL_OP_COPYOUT) ? 0 : ICL_COPYOUTF_CLRAFTERREAD;
190 afs_icl_CopyOut(logp, lp, &elts, (afs_uint32 *) & startCookie,
193 osi_FreeLargeSpace((struct osi_buffer *)lp);
196 AFS_COPYOUT((char *)lp, AFSKPTR(p2), elts * sizeof(afs_int32), code);
199 AFS_COPYOUT((char *)&startCookie, AFSKPTR(p4), sizeof(afs_int32),
203 #if defined(AFS_AIX51_ENV) && defined(AFS_64BIT_KERNEL)
205 *retval = ((long)((flags << 24) | (elts & 0xffffff))) << 32;
208 *retval = (flags << 24) | (elts & 0xffffff);
210 afs_icl_LogRele(logp);
211 osi_FreeLargeSpace((struct osi_buffer *)lp);
214 case ICL_OP_ENUMLOGS: /* enumerate logs */
215 /* enumerate logs: p1=index, p2=&name, p3=sizeof(name), p4=&size.
216 * return 0 for success, otherwise error.
218 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
223 return ENOENT; /* past the end of file */
224 temp = strlen(tlp->name) + 1;
227 AFS_COPYOUT(tlp->name, AFSKPTR(p2), temp, code);
228 if (!code) /* copy out size of log */
229 AFS_COPYOUT((char *)&tlp->logSize, AFSKPTR(p4), sizeof(afs_int32),
233 case ICL_OP_ENUMLOGSBYSET: /* enumerate logs by set name */
234 /* enumerate logs: p1=setname, p2=index, p3=&name, p4=sizeof(name).
235 * return 0 for success, otherwise error.
237 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
240 setp = afs_icl_FindSet(tname);
243 if (p2 >= ICL_LOGSPERSET)
245 if (!(tlp = setp->logs[p2]))
247 temp = strlen(tlp->name) + 1;
250 AFS_COPYOUT(tlp->name, AFSKPTR(p3), temp, code);
253 case ICL_OP_CLRLOG: /* clear specified log */
254 /* zero out the specified log: p1=logname */
255 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
258 logp = afs_icl_FindLog(tname);
261 code = afs_icl_ZeroLog(logp);
262 afs_icl_LogRele(logp);
265 case ICL_OP_CLRSET: /* clear specified set */
266 /* zero out the specified set: p1=setname */
267 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
270 setp = afs_icl_FindSet(tname);
273 code = afs_icl_ZeroSet(setp);
274 afs_icl_SetRele(setp);
277 case ICL_OP_CLRALL: /* clear all logs */
278 /* zero out all logs -- no args */
280 ObtainWriteLock(&afs_icl_lock, 178);
281 for (tlp = afs_icl_allLogs; tlp; tlp = tlp->nextp) {
282 tlp->refCount++; /* hold this guy */
283 ReleaseWriteLock(&afs_icl_lock);
284 /* don't clear persistent logs */
285 if ((tlp->states & ICL_LOGF_PERSISTENT) == 0)
286 code = afs_icl_ZeroLog(tlp);
287 ObtainWriteLock(&afs_icl_lock, 179);
288 if (--tlp->refCount == 0)
293 ReleaseWriteLock(&afs_icl_lock);
296 case ICL_OP_ENUMSETS: /* enumerate all sets */
297 /* enumerate sets: p1=index, p2=&name, p3=sizeof(name), p4=&states.
298 * return 0 for success, otherwise error.
300 for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
305 return ENOENT; /* past the end of file */
306 temp = strlen(setp->name) + 1;
309 AFS_COPYOUT(setp->name, AFSKPTR(p2), temp, code);
310 if (!code) /* copy out size of log */
311 AFS_COPYOUT((char *)&setp->states, AFSKPTR(p4), sizeof(afs_int32),
315 case ICL_OP_SETSTAT: /* set status on a set */
316 /* activate the specified set: p1=setname, p2=op */
317 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
320 setp = afs_icl_FindSet(tname);
323 code = afs_icl_SetSetStat(setp, p2);
324 afs_icl_SetRele(setp);
327 case ICL_OP_SETSTATALL: /* set status on all sets */
328 /* activate the specified set: p1=op */
330 ObtainWriteLock(&afs_icl_lock, 180);
331 for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
332 setp->refCount++; /* hold this guy */
333 ReleaseWriteLock(&afs_icl_lock);
334 /* don't set states on persistent sets */
335 if ((setp->states & ICL_SETF_PERSISTENT) == 0)
336 code = afs_icl_SetSetStat(setp, p1);
337 ObtainWriteLock(&afs_icl_lock, 181);
338 if (--setp->refCount == 0)
339 afs_icl_ZapSet(setp);
343 ReleaseWriteLock(&afs_icl_lock);
346 case ICL_OP_SETLOGSIZE: /* set size of log */
347 /* set the size of the specified log: p1=logname, p2=size (in words) */
348 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
351 logp = afs_icl_FindLog(tname);
354 code = afs_icl_LogSetSize(logp, p2);
355 afs_icl_LogRele(logp);
358 case ICL_OP_GETLOGINFO: /* get size of log */
359 /* zero out the specified log: p1=logname, p2=&logSize, p3=&allocated */
360 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
363 logp = afs_icl_FindLog(tname);
366 allocated = !!logp->datap;
367 AFS_COPYOUT((char *)&logp->logSize, AFSKPTR(p2), sizeof(afs_int32),
370 AFS_COPYOUT((char *)&allocated, AFSKPTR(p3), sizeof(afs_int32),
372 afs_icl_LogRele(logp);
375 case ICL_OP_GETSETINFO: /* get state of set */
376 /* zero out the specified set: p1=setname, p2=&state */
377 AFS_COPYINSTR(AFSKPTR(p1), tname, sizeof(tname), &temp, code);
380 setp = afs_icl_FindSet(tname);
383 AFS_COPYOUT((char *)&setp->states, AFSKPTR(p2), sizeof(afs_int32),
385 afs_icl_SetRele(setp);
396 afs_lock_t afs_icl_lock;
398 /* exported routine: a 4 parameter event */
400 afs_icl_Event4(struct afs_icl_set *setp, afs_int32 eventID,
401 afs_int32 lAndT, long p1, long p2, long p3, long p4)
408 /* If things aren't init'ed yet (or the set is inactive), don't panic */
409 if (!ICL_SETACTIVE(setp))
413 afs_icl_SetHold(setp);
414 mask = lAndT >> 24 & 0xff; /* mask of which logs to log to */
415 ix = ICL_EVENTBYTE(eventID);
416 ObtainReadLock(&setp->lock);
417 if (setp->eventFlags[ix] & ICL_EVENTMASK(eventID)) {
418 for (i = 0, tmask = 1; i < ICL_LOGSPERSET; i++, tmask <<= 1) {
420 afs_icl_AppendRecord(setp->logs[i], eventID, lAndT & 0xffffff,
425 break; /* break early */
428 ReleaseReadLock(&setp->lock);
429 afs_icl_SetRele(setp);
433 /* Next 4 routines should be implemented via var-args or something.
434 * Whole purpose is to avoid compiler warnings about parameter # mismatches.
435 * Otherwise, could call afs_icl_Event4 directly.
438 afs_icl_Event3(struct afs_icl_set *setp, afs_int32 eventID,
439 afs_int32 lAndT, long p1, long p2, long p3)
441 return afs_icl_Event4(setp, eventID, lAndT, p1, p2, p3, (long)0);
445 afs_icl_Event2(struct afs_icl_set *setp, afs_int32 eventID,
446 afs_int32 lAndT, long p1, long p2)
448 return afs_icl_Event4(setp, eventID, lAndT, p1, p2, (long)0, (long)0);
452 afs_icl_Event1(struct afs_icl_set *setp, afs_int32 eventID,
453 afs_int32 lAndT, long p1)
455 return afs_icl_Event4(setp, eventID, lAndT, p1, (long)0, (long)0,
460 afs_icl_Event0(struct afs_icl_set *setp, afs_int32 eventID,
463 return afs_icl_Event4(setp, eventID, lAndT, (long)0, (long)0, (long)0,
467 struct afs_icl_log *afs_icl_allLogs = 0;
469 /* function to purge records from the start of the log, until there
470 * is at least minSpace long's worth of space available without
471 * making the head and the tail point to the same word.
473 * Log must be write-locked.
476 afs_icl_GetLogSpace(struct afs_icl_log *logp, afs_int32 minSpace)
480 while (logp->logSize - logp->logElements <= minSpace) {
482 tsize = ((logp->datap[logp->firstUsed]) >> 24) & 0xff;
483 logp->logElements -= tsize;
484 logp->firstUsed += tsize;
485 if (logp->firstUsed >= logp->logSize)
486 logp->firstUsed -= logp->logSize;
487 logp->baseCookie += tsize;
491 /* append string astr to buffer, including terminating null char.
493 * log must be write-locked.
495 #define ICL_CHARSPERLONG 4
497 afs_icl_AppendString(struct afs_icl_log *logp, char *astr)
499 char *op; /* ptr to char to write */
501 int bib; /* bytes in buffer */
504 op = (char *)&(logp->datap[logp->firstFree]);
508 if (++bib >= ICL_CHARSPERLONG) {
511 if (++(logp->firstFree) >= logp->logSize) {
513 op = (char *)&(logp->datap[0]);
521 /* if we've used this word at all, allocate it */
522 if (++(logp->firstFree) >= logp->logSize) {
529 /* add a long to the log, ignoring overflow (checked already) */
530 #define ICL_APPENDINT32(lp, x) \
532 (lp)->datap[(lp)->firstFree] = (x); \
533 if (++((lp)->firstFree) >= (lp)->logSize) { \
534 (lp)->firstFree = 0; \
536 (lp)->logElements++; \
540 #define ICL_APPENDLONG(lp, x) \
542 ICL_APPENDINT32((lp), ((x) >> 32) & 0xffffffffL); \
543 ICL_APPENDINT32((lp), (x) & 0xffffffffL); \
547 #define ICL_APPENDLONG(lp, x) ICL_APPENDINT32((lp), (x))
550 /* routine to tell whether we're dealing with the address or the
554 afs_icl_UseAddr(int type)
556 if (type == ICL_TYPE_HYPER || type == ICL_TYPE_STRING
557 || type == ICL_TYPE_FID || type == ICL_TYPE_INT64)
564 afs_icl_AppendOne(struct afs_icl_log *logp, int type, long parm)
567 /* marshall parameter 3 now */
568 if (type == ICL_TYPE_STRING)
569 afs_icl_AppendString(logp, (char *)parm);
570 else if (type == ICL_TYPE_HYPER) {
571 ICL_APPENDINT32(logp,
572 (afs_int32) ((struct afs_hyper_t *)parm)->high);
573 ICL_APPENDINT32(logp,
574 (afs_int32) ((struct afs_hyper_t *)parm)->low);
575 } else if (type == ICL_TYPE_INT64) {
576 #ifndef WORDS_BIGENDIAN
577 #ifdef AFS_64BIT_CLIENT
578 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
579 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
580 #else /* AFS_64BIT_CLIENT */
581 ICL_APPENDINT32(logp, (afs_int32) parm);
582 ICL_APPENDINT32(logp, (afs_int32) 0);
583 #endif /* AFS_64BIT_CLIENT */
584 #else /* AFSLITTLE_ENDIAN */
585 #ifdef AFS_64BIT_CLIENT
586 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
587 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
588 #else /* AFS_64BIT_CLIENT */
589 ICL_APPENDINT32(logp, (afs_int32) 0);
590 ICL_APPENDINT32(logp, (afs_int32) parm);
591 #endif /* AFS_64BIT_CLIENT */
592 #endif /* AFSLITTLE_ENDIAN */
593 } else if (type == ICL_TYPE_FID) {
594 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[0]);
595 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[1]);
596 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[2]);
597 ICL_APPENDINT32(logp, (afs_int32) ((afs_int32 *) parm)[3]);
600 else if (type == ICL_TYPE_INT32)
601 ICL_APPENDINT32(logp, (afs_int32) parm);
604 ICL_APPENDLONG(logp, parm);
608 /* Function to append a record to the log. Written for speed
609 * since we know that we're going to have to make this work fast
610 * pretty soon, anyway. The log must be unlocked.
614 afs_icl_AppendRecord(struct afs_icl_log *logp, afs_int32 op,
615 afs_int32 types, long p1, long p2, long p3, long p4)
617 int rsize; /* record size in longs */
618 int tsize; /* temp size */
622 t4 = types & 0x3f; /* decode types */
630 osi_GetTime(&tv); /* It panics for solaris if inside */
631 ObtainWriteLock(&logp->lock, 182);
633 ReleaseWriteLock(&logp->lock);
637 /* get timestamp as # of microseconds since some time that doesn't
638 * change that often. This algorithm ticks over every 20 minutes
639 * or so (1000 seconds). Write a timestamp record if it has.
641 if (tv.tv_sec - logp->lastTS > 1024) {
642 /* the timer has wrapped -- write a timestamp record */
643 if (logp->logSize - logp->logElements <= 5)
644 afs_icl_GetLogSpace(logp, 5);
646 ICL_APPENDINT32(logp,
647 (afs_int32) (5 << 24) + (ICL_TYPE_UNIXDATE << 18));
648 ICL_APPENDINT32(logp, (afs_int32) ICL_INFO_TIMESTAMP);
649 ICL_APPENDINT32(logp, (afs_int32) 0); /* use thread ID zero for clocks */
650 ICL_APPENDINT32(logp,
651 (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 +
653 ICL_APPENDINT32(logp, (afs_int32) tv.tv_sec);
655 logp->lastTS = tv.tv_sec;
658 rsize = 4; /* base case: see 4 items below */
660 /* compute size of parameter p1. Only tricky case is string.
661 * In that case, we have to call strlen to get the string length.
663 ICL_SIZEHACK(t1, p1, tsize, rsize);
666 /* compute size of parameter p2. Only tricky case is string.
667 * In that case, we have to call strlen to get the string length.
669 ICL_SIZEHACK(t2, p2, tsize, rsize);
672 /* compute size of parameter p3. Only tricky case is string.
673 * In that case, we have to call strlen to get the string length.
675 ICL_SIZEHACK(t3, p3, tsize, rsize);
678 /* compute size of parameter p4. Only tricky case is string.
679 * In that case, we have to call strlen to get the string length.
681 ICL_SIZEHACK(t4, p4, tsize, rsize);
684 /* At this point, we've computed all of the parameter sizes, and
685 * have in rsize the size of the entire record we want to append.
686 * Next, we check that we actually have room in the log to do this
687 * work, and then we do the append.
690 ReleaseWriteLock(&logp->lock);
691 return; /* log record too big to express */
694 if (logp->logSize - logp->logElements <= rsize)
695 afs_icl_GetLogSpace(logp, rsize);
697 ICL_APPENDINT32(logp,
698 (afs_int32) (rsize << 24) + (t1 << 18) + (t2 << 12) +
700 ICL_APPENDINT32(logp, (afs_int32) op);
701 ICL_APPENDINT32(logp, (afs_int32) osi_ThreadUnique());
702 ICL_APPENDINT32(logp,
703 (afs_int32) (tv.tv_sec & 0x3ff) * 1000000 + tv.tv_usec);
705 afs_icl_AppendOne(logp, t1, p1);
706 afs_icl_AppendOne(logp, t2, p2);
707 afs_icl_AppendOne(logp, t3, p3);
708 afs_icl_AppendOne(logp, t4, p4);
709 ReleaseWriteLock(&logp->lock);
712 /* create a log with size logSize; return it in *outLogpp and tag
713 * it with name "name."
716 afs_icl_CreateLog(char *name, afs_int32 logSize,
717 struct afs_icl_log **outLogpp)
719 return afs_icl_CreateLogWithFlags(name, logSize, /*flags */ 0, outLogpp);
722 /* create a log with size logSize; return it in *outLogpp and tag
723 * it with name "name." 'flags' can be set to make the log unclearable.
726 afs_icl_CreateLogWithFlags(char *name, afs_int32 logSize, afs_uint32 flags,
727 struct afs_icl_log **outLogpp)
729 struct afs_icl_log *logp;
731 /* add into global list under lock */
732 ObtainWriteLock(&afs_icl_lock, 183);
736 for (logp = afs_icl_allLogs; logp; logp = logp->nextp) {
737 if (strcmp(logp->name, name) == 0) {
738 /* found it already created, just return it */
741 if (flags & ICL_CRLOG_FLAG_PERSISTENT) {
742 ObtainWriteLock(&logp->lock, 184);
743 logp->states |= ICL_LOGF_PERSISTENT;
744 ReleaseWriteLock(&logp->lock);
746 ReleaseWriteLock(&afs_icl_lock);
751 logp = osi_AllocSmallSpace(sizeof(struct afs_icl_log));
752 memset((caddr_t) logp, 0, sizeof(*logp));
755 logp->name = osi_AllocSmallSpace(strlen(name) + 1);
756 strcpy(logp->name, name);
757 LOCK_INIT(&logp->lock, "logp lock");
758 logp->logSize = logSize;
759 logp->datap = NULL; /* don't allocate it until we need it */
761 if (flags & ICL_CRLOG_FLAG_PERSISTENT)
762 logp->states |= ICL_LOGF_PERSISTENT;
764 logp->nextp = afs_icl_allLogs;
765 afs_icl_allLogs = logp;
766 ReleaseWriteLock(&afs_icl_lock);
772 /* called with a log, a pointer to a buffer, the size of the buffer
773 * (in *bufSizep), the starting cookie (in *cookiep, use 0 at the start)
774 * and returns data in the provided buffer, and returns output flags
775 * in *flagsp. The flag ICL_COPYOUTF_MISSEDSOME is set if we can't
776 * find the record with cookie value cookie.
779 afs_icl_CopyOut(struct afs_icl_log *logp, afs_int32 * bufferp,
780 afs_int32 * bufSizep, afs_uint32 * cookiep,
783 afs_int32 nwords; /* number of words to copy out */
784 afs_uint32 startCookie; /* first cookie to use */
785 afs_int32 outWords; /* words we've copied out */
786 afs_int32 inWords; /* max words to copy out */
787 afs_int32 code; /* return code */
788 afs_int32 ix; /* index we're copying from */
789 afs_int32 outFlags; /* return flags */
790 afs_int32 inFlags; /* flags passed in */
793 inWords = *bufSizep; /* max to copy out */
794 outWords = 0; /* amount copied out */
795 startCookie = *cookiep;
800 ObtainWriteLock(&logp->lock, 185);
802 ReleaseWriteLock(&logp->lock);
806 /* first, compute the index of the start cookie we've been passed */
808 /* (re-)compute where we should start */
809 if (startCookie < logp->baseCookie) {
810 if (startCookie) /* missed some output */
811 outFlags |= ICL_COPYOUTF_MISSEDSOME;
812 /* skip to the first available record */
813 startCookie = logp->baseCookie;
814 *cookiep = startCookie;
817 /* compute where we find the first element to copy out */
818 ix = logp->firstUsed + startCookie - logp->baseCookie;
819 if (ix >= logp->logSize)
822 /* if have some data now, break out and process it */
823 if (startCookie - logp->baseCookie < logp->logElements)
826 /* At end of log, so clear it if we need to */
827 if (inFlags & ICL_COPYOUTF_CLRAFTERREAD) {
828 logp->firstUsed = logp->firstFree = 0;
829 logp->logElements = 0;
831 /* otherwise, either wait for the data to arrive, or return */
832 if (!(inFlags & ICL_COPYOUTF_WAITIO)) {
833 ReleaseWriteLock(&logp->lock);
837 logp->states |= ICL_LOGF_WAITING;
838 ReleaseWriteLock(&logp->lock);
839 afs_osi_Sleep(&logp->lock);
840 ObtainWriteLock(&logp->lock, 186);
842 /* copy out data from ix to logSize or firstFree, depending
843 * upon whether firstUsed <= firstFree (no wrap) or otherwise.
844 * be careful not to copy out more than nwords.
846 if (ix >= logp->firstUsed) {
847 if (logp->firstUsed <= logp->firstFree)
849 end = logp->firstFree; /* first element not to copy */
852 nwords = inWords; /* don't copy more than this */
853 if (end - ix < nwords)
856 memcpy((char *)bufferp, (char *)&logp->datap[ix],
857 sizeof(afs_int32) * nwords);
862 /* if we're going to copy more out below, we'll start here */
865 /* now, if active part of the log has wrapped, there's more stuff
866 * starting at the head of the log. Copy out more from there.
868 if (logp->firstUsed > logp->firstFree && ix < logp->firstFree
870 /* (more to) copy out from the wrapped section at the
871 * start of the log. May get here even if didn't copy any
872 * above, if the cookie points directly into the wrapped section.
875 if (logp->firstFree - ix < nwords)
876 nwords = logp->firstFree - ix;
877 memcpy((char *)bufferp, (char *)&logp->datap[ix],
878 sizeof(afs_int32) * nwords);
884 ReleaseWriteLock(&logp->lock);
888 *bufSizep = outWords;
894 /* return basic parameter information about a log */
896 afs_icl_GetLogParms(struct afs_icl_log *logp, afs_int32 * maxSizep,
897 afs_int32 * curSizep)
899 ObtainReadLock(&logp->lock);
900 *maxSizep = logp->logSize;
901 *curSizep = logp->logElements;
902 ReleaseReadLock(&logp->lock);
907 /* hold and release logs */
909 afs_icl_LogHold(struct afs_icl_log *logp)
911 ObtainWriteLock(&afs_icl_lock, 187);
913 ReleaseWriteLock(&afs_icl_lock);
917 /* hold and release logs, called with lock already held */
919 afs_icl_LogHoldNL(struct afs_icl_log *logp)
925 /* keep track of how many sets believe the log itself is allocated */
927 afs_icl_LogUse(struct afs_icl_log *logp)
929 ObtainWriteLock(&logp->lock, 188);
930 if (logp->setCount == 0) {
931 /* this is the first set actually using the log -- allocate it */
932 if (logp->logSize == 0) {
933 /* we weren't passed in a hint and it wasn't set */
934 logp->logSize = ICL_DEFAULT_LOGSIZE;
936 logp->datap = afs_osi_Alloc(sizeof(afs_int32) * logp->logSize);
937 osi_Assert(logp->datap != NULL);
938 #ifdef KERNEL_HAVE_PIN
939 pin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
943 ReleaseWriteLock(&logp->lock);
947 /* decrement the number of real users of the log, free if possible */
949 afs_icl_LogFreeUse(struct afs_icl_log *logp)
951 ObtainWriteLock(&logp->lock, 189);
952 if (--logp->setCount == 0) {
953 /* no more users -- free it (but keep log structure around) */
954 afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
955 #ifdef KERNEL_HAVE_PIN
956 unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
958 logp->firstUsed = logp->firstFree = 0;
959 logp->logElements = 0;
962 ReleaseWriteLock(&logp->lock);
966 /* set the size of the log to 'logSize' */
968 afs_icl_LogSetSize(struct afs_icl_log *logp, afs_int32 logSize)
970 ObtainWriteLock(&logp->lock, 190);
972 /* nothing to worry about since it's not allocated */
973 logp->logSize = logSize;
976 logp->firstUsed = logp->firstFree = 0;
977 logp->logElements = 0;
979 /* free and allocate a new one */
980 afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
981 #ifdef KERNEL_HAVE_PIN
982 unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
984 logp->datap = afs_osi_Alloc(sizeof(afs_int32) * logSize);
985 osi_Assert(logp->datap != NULL);
986 #ifdef KERNEL_HAVE_PIN
987 pin((char *)logp->datap, sizeof(afs_int32) * logSize);
989 logp->logSize = logSize;
991 ReleaseWriteLock(&logp->lock);
996 /* free a log. Called with afs_icl_lock locked. */
998 afs_icl_ZapLog(struct afs_icl_log *logp)
1000 struct afs_icl_log **lpp, *tp;
1002 for (lpp = &afs_icl_allLogs, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1004 /* found the dude we want to remove */
1006 osi_FreeSmallSpace(logp->name);
1007 afs_osi_Free(logp->datap, sizeof(afs_int32) * logp->logSize);
1008 #ifdef KERNEL_HAVE_PIN
1009 unpin((char *)logp->datap, sizeof(afs_int32) * logp->logSize);
1011 osi_FreeSmallSpace(logp);
1012 break; /* won't find it twice */
1018 /* do the release, watching for deleted entries */
1020 afs_icl_LogRele(struct afs_icl_log *logp)
1022 ObtainWriteLock(&afs_icl_lock, 191);
1023 if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1024 afs_icl_ZapLog(logp); /* destroys logp's lock! */
1026 ReleaseWriteLock(&afs_icl_lock);
1030 /* do the release, watching for deleted entries, log already held */
1032 afs_icl_LogReleNL(struct afs_icl_log *logp)
1034 if (--logp->refCount == 0 && (logp->states & ICL_LOGF_DELETED)) {
1035 afs_icl_ZapLog(logp); /* destroys logp's lock! */
1040 /* zero out the log */
1042 afs_icl_ZeroLog(struct afs_icl_log *logp)
1044 ObtainWriteLock(&logp->lock, 192);
1045 logp->firstUsed = logp->firstFree = 0;
1046 logp->logElements = 0;
1047 logp->baseCookie = 0;
1048 ReleaseWriteLock(&logp->lock);
1052 /* free a log entry, and drop its reference count */
1054 afs_icl_LogFree(struct afs_icl_log *logp)
1056 ObtainWriteLock(&logp->lock, 193);
1057 logp->states |= ICL_LOGF_DELETED;
1058 ReleaseWriteLock(&logp->lock);
1059 afs_icl_LogRele(logp);
1063 /* find a log by name, returning it held */
1064 struct afs_icl_log *
1065 afs_icl_FindLog(char *name)
1067 struct afs_icl_log *tp;
1068 ObtainWriteLock(&afs_icl_lock, 194);
1069 for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
1070 if (strcmp(tp->name, name) == 0) {
1071 /* this is the dude we want */
1076 ReleaseWriteLock(&afs_icl_lock);
1081 afs_icl_EnumerateLogs(int (*aproc)
1082 (char *name, char *arock, struct afs_icl_log * tp),
1085 struct afs_icl_log *tp;
1089 ObtainWriteLock(&afs_icl_lock, 195);
1090 for (tp = afs_icl_allLogs; tp; tp = tp->nextp) {
1091 tp->refCount++; /* hold this guy */
1092 ReleaseWriteLock(&afs_icl_lock);
1093 ObtainReadLock(&tp->lock);
1094 code = (*aproc) (tp->name, arock, tp);
1095 ReleaseReadLock(&tp->lock);
1096 ObtainWriteLock(&afs_icl_lock, 196);
1097 if (--tp->refCount == 0)
1102 ReleaseWriteLock(&afs_icl_lock);
1106 struct afs_icl_set *afs_icl_allSets = 0;
1109 afs_icl_CreateSet(char *name, struct afs_icl_log *baseLogp,
1110 struct afs_icl_log *fatalLogp,
1111 struct afs_icl_set **outSetpp)
1113 return afs_icl_CreateSetWithFlags(name, baseLogp, fatalLogp,
1114 /*flags */ 0, outSetpp);
1117 /* create a set, given pointers to base and fatal logs, if any.
1118 * Logs are unlocked, but referenced, and *outSetpp is returned
1119 * referenced. Function bumps reference count on logs, since it
1120 * addds references from the new afs_icl_set. When the set is destroyed,
1121 * those references will be released.
1124 afs_icl_CreateSetWithFlags(char *name, struct afs_icl_log *baseLogp,
1125 struct afs_icl_log *fatalLogp, afs_uint32 flags,
1126 struct afs_icl_set **outSetpp)
1128 struct afs_icl_set *setp;
1130 afs_int32 states = ICL_DEFAULT_SET_STATES;
1132 ObtainWriteLock(&afs_icl_lock, 197);
1133 if (!afs_icl_inited)
1136 for (setp = afs_icl_allSets; setp; setp = setp->nextp) {
1137 if (strcmp(setp->name, name) == 0) {
1140 if (flags & ICL_CRSET_FLAG_PERSISTENT) {
1141 ObtainWriteLock(&setp->lock, 198);
1142 setp->states |= ICL_SETF_PERSISTENT;
1143 ReleaseWriteLock(&setp->lock);
1145 ReleaseWriteLock(&afs_icl_lock);
1150 /* determine initial state */
1151 if (flags & ICL_CRSET_FLAG_DEFAULT_ON)
1152 states = ICL_SETF_ACTIVE;
1153 else if (flags & ICL_CRSET_FLAG_DEFAULT_OFF)
1154 states = ICL_SETF_FREED;
1155 if (flags & ICL_CRSET_FLAG_PERSISTENT)
1156 states |= ICL_SETF_PERSISTENT;
1158 setp = osi_AllocSmallSpace(sizeof(struct afs_icl_set));
1159 memset((caddr_t) setp, 0, sizeof(*setp));
1161 if (states & ICL_SETF_FREED)
1162 states &= ~ICL_SETF_ACTIVE; /* if freed, can't be active */
1163 setp->states = states;
1165 LOCK_INIT(&setp->lock, "setp lock");
1166 /* next lock is obtained in wrong order, hierarchy-wise, but
1167 * it doesn't matter, since no one can find this lock yet, since
1168 * the afs_icl_lock is still held, and thus the obtain can't block.
1170 ObtainWriteLock(&setp->lock, 199);
1171 setp->name = osi_AllocSmallSpace(strlen(name) + 1);
1172 strcpy(setp->name, name);
1173 setp->nevents = ICL_DEFAULTEVENTS;
1174 setp->eventFlags = afs_osi_Alloc(ICL_DEFAULTEVENTS);
1175 osi_Assert(setp->eventFlags != NULL);
1176 #ifdef KERNEL_HAVE_PIN
1177 pin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
1179 for (i = 0; i < ICL_DEFAULTEVENTS; i++)
1180 setp->eventFlags[i] = 0xff; /* default to enabled */
1182 /* update this global info under the afs_icl_lock */
1183 setp->nextp = afs_icl_allSets;
1184 afs_icl_allSets = setp;
1185 ReleaseWriteLock(&afs_icl_lock);
1187 /* set's basic lock is still held, so we can finish init */
1189 setp->logs[0] = baseLogp;
1190 afs_icl_LogHold(baseLogp);
1191 if (!(setp->states & ICL_SETF_FREED))
1192 afs_icl_LogUse(baseLogp); /* log is actually being used */
1195 setp->logs[1] = fatalLogp;
1196 afs_icl_LogHold(fatalLogp);
1197 if (!(setp->states & ICL_SETF_FREED))
1198 afs_icl_LogUse(fatalLogp); /* log is actually being used */
1200 ReleaseWriteLock(&setp->lock);
1206 /* function to change event enabling information for a particular set */
1208 afs_icl_SetEnable(struct afs_icl_set *setp, afs_int32 eventID, int setValue)
1212 ObtainWriteLock(&setp->lock, 200);
1213 if (!ICL_EVENTOK(setp, eventID)) {
1214 ReleaseWriteLock(&setp->lock);
1217 tp = &setp->eventFlags[ICL_EVENTBYTE(eventID)];
1219 *tp |= ICL_EVENTMASK(eventID);
1221 *tp &= ~(ICL_EVENTMASK(eventID));
1222 ReleaseWriteLock(&setp->lock);
1226 /* return indication of whether a particular event ID is enabled
1227 * for tracing. If *getValuep is set to 0, the event is disabled,
1228 * otherwise it is enabled. All events start out enabled by default.
1231 afs_icl_GetEnable(struct afs_icl_set *setp, afs_int32 eventID, int *getValuep)
1233 ObtainReadLock(&setp->lock);
1234 if (!ICL_EVENTOK(setp, eventID)) {
1235 ReleaseWriteLock(&setp->lock);
1238 if (setp->eventFlags[ICL_EVENTBYTE(eventID)] & ICL_EVENTMASK(eventID))
1242 ReleaseReadLock(&setp->lock);
1246 /* hold and release event sets */
1248 afs_icl_SetHold(struct afs_icl_set *setp)
1250 ObtainWriteLock(&afs_icl_lock, 201);
1252 ReleaseWriteLock(&afs_icl_lock);
1256 /* free a set. Called with afs_icl_lock locked */
1258 afs_icl_ZapSet(struct afs_icl_set *setp)
1260 struct afs_icl_set **lpp, *tp;
1262 struct afs_icl_log *tlp;
1264 for (lpp = &afs_icl_allSets, tp = *lpp; tp; lpp = &tp->nextp, tp = *lpp) {
1266 /* found the dude we want to remove */
1268 osi_FreeSmallSpace(setp->name);
1269 afs_osi_Free(setp->eventFlags, ICL_DEFAULTEVENTS);
1270 #ifdef KERNEL_HAVE_PIN
1271 unpin((char *)setp->eventFlags, ICL_DEFAULTEVENTS);
1273 for (i = 0; i < ICL_LOGSPERSET; i++) {
1274 if ((tlp = setp->logs[i]))
1275 afs_icl_LogReleNL(tlp);
1277 osi_FreeSmallSpace(setp);
1278 break; /* won't find it twice */
1284 /* do the release, watching for deleted entries */
1286 afs_icl_SetRele(struct afs_icl_set *setp)
1288 ObtainWriteLock(&afs_icl_lock, 202);
1289 if (--setp->refCount == 0 && (setp->states & ICL_SETF_DELETED)) {
1290 afs_icl_ZapSet(setp); /* destroys setp's lock! */
1292 ReleaseWriteLock(&afs_icl_lock);
1296 /* free a set entry, dropping its reference count */
1298 afs_icl_SetFree(struct afs_icl_set *setp)
1300 ObtainWriteLock(&setp->lock, 203);
1301 setp->states |= ICL_SETF_DELETED;
1302 ReleaseWriteLock(&setp->lock);
1303 afs_icl_SetRele(setp);
1307 /* find a set by name, returning it held */
1308 struct afs_icl_set *
1309 afs_icl_FindSet(char *name)
1311 struct afs_icl_set *tp;
1312 ObtainWriteLock(&afs_icl_lock, 204);
1313 for (tp = afs_icl_allSets; tp; tp = tp->nextp) {
1314 if (strcmp(tp->name, name) == 0) {
1315 /* this is the dude we want */
1320 ReleaseWriteLock(&afs_icl_lock);
1324 /* zero out all the logs in the set */
1326 afs_icl_ZeroSet(struct afs_icl_set *setp)
1331 struct afs_icl_log *logp;
1333 ObtainReadLock(&setp->lock);
1334 for (i = 0; i < ICL_LOGSPERSET; i++) {
1335 logp = setp->logs[i];
1337 afs_icl_LogHold(logp);
1338 tcode = afs_icl_ZeroLog(logp);
1340 code = tcode; /* save the last bad one */
1341 afs_icl_LogRele(logp);
1344 ReleaseReadLock(&setp->lock);
1349 afs_icl_EnumerateSets(int (*aproc)
1350 (char *name, char *arock, struct afs_icl_log * tp),
1353 struct afs_icl_set *tp, *np;
1357 ObtainWriteLock(&afs_icl_lock, 205);
1358 for (tp = afs_icl_allSets; tp; tp = np) {
1359 tp->refCount++; /* hold this guy */
1360 ReleaseWriteLock(&afs_icl_lock);
1361 code = (*aproc) (tp->name, arock, (struct afs_icl_log *)tp);
1362 ObtainWriteLock(&afs_icl_lock, 206);
1363 np = tp->nextp; /* tp may disappear next, but not np */
1364 if (--tp->refCount == 0 && (tp->states & ICL_SETF_DELETED))
1369 ReleaseWriteLock(&afs_icl_lock);
1374 afs_icl_AddLogToSet(struct afs_icl_set *setp, struct afs_icl_log *newlogp)
1379 ObtainWriteLock(&setp->lock, 207);
1380 for (i = 0; i < ICL_LOGSPERSET; i++) {
1381 if (!setp->logs[i]) {
1382 setp->logs[i] = newlogp;
1384 afs_icl_LogHold(newlogp);
1385 if (!(setp->states & ICL_SETF_FREED)) {
1386 /* bump up the number of sets using the log */
1387 afs_icl_LogUse(newlogp);
1392 ReleaseWriteLock(&setp->lock);
1397 afs_icl_SetSetStat(struct afs_icl_set *setp, int op)
1401 struct afs_icl_log *logp;
1403 ObtainWriteLock(&setp->lock, 208);
1405 case ICL_OP_SS_ACTIVATE: /* activate a log */
1407 * If we are not already active, see if we have released
1408 * our demand that the log be allocated (FREED set). If
1409 * we have, reassert our desire.
1411 if (!(setp->states & ICL_SETF_ACTIVE)) {
1412 if (setp->states & ICL_SETF_FREED) {
1413 /* have to reassert desire for logs */
1414 for (i = 0; i < ICL_LOGSPERSET; i++) {
1415 logp = setp->logs[i];
1417 afs_icl_LogHold(logp);
1418 afs_icl_LogUse(logp);
1419 afs_icl_LogRele(logp);
1422 setp->states &= ~ICL_SETF_FREED;
1424 setp->states |= ICL_SETF_ACTIVE;
1429 case ICL_OP_SS_DEACTIVATE: /* deactivate a log */
1430 /* this doesn't require anything beyond clearing the ACTIVE flag */
1431 setp->states &= ~ICL_SETF_ACTIVE;
1435 case ICL_OP_SS_FREE: /* deassert design for log */
1437 * if we are already in this state, do nothing; otherwise
1438 * deassert desire for log
1440 if (setp->states & ICL_SETF_ACTIVE)
1443 if (!(setp->states & ICL_SETF_FREED)) {
1444 for (i = 0; i < ICL_LOGSPERSET; i++) {
1445 logp = setp->logs[i];
1447 afs_icl_LogHold(logp);
1448 afs_icl_LogFreeUse(logp);
1449 afs_icl_LogRele(logp);
1452 setp->states |= ICL_SETF_FREED;
1461 ReleaseWriteLock(&setp->lock);