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