1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * etm_ckpt.c
29 * Description:
30 * Checkpoint the ereport events for persitence across fmd restart.
31 *
32 * Each ereport is stored in a named buffer. Each ereport is uniquely
33 * indentified by a id which is consists of a number of ereport fields. The
34 * name of the buffer is derived from the id.
35 *
36 * All ereport ids are stored in the circular list which is saved in a
37 * separate buffer.
38 */
39
40 #include <assert.h>
41 #include <stdio.h>
42 #include <pthread.h>
43 #include <strings.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/fm/ldom.h>
47 #include <sys/fm/protocol.h>
48 #include <fm/fmd_api.h>
49 #include <fm/libtopo.h>
50 #include <fm/topo_hc.h>
51
52 #include "etm_etm_proto.h"
53 #include "etm_iosvc.h"
54 #include "etm_ckpt.h"
55 #include "etm_filter.h"
56
57 #define ETM_ATTR_PRIMARY "primary"
58 #define ETM_ATTR_TOD "__tod"
59 #define ETM_LDOM_PRIMARY "primary"
60
61 /*
62 * -------------------------- private variables ------------------------------
63 */
64
65 static etm_ckpt_id_list_t *etm_id_lst = NULL; /* list of ereports ids */
66
67 static pthread_mutex_t etm_id_lst_lock; /* list lock */
68
69 /*
70 * -------------------------- functions --------------------------------------
71 */
72
73 /*
74 * etm_ckpt_str_hash()
75 * Description:
76 * Hash a class name to a number
77 */
78 static uint_t
etm_ckpt_str_hash(char * str)79 etm_ckpt_str_hash(char *str)
80 {
81 uint_t hash = 0; /* hash value */
82
83 if (str == NULL)
84 return (0);
85
86 while (*str != '\0')
87 hash += *str++;
88
89 return (hash);
90 }
91
92 /*
93 * etm_ckpt_id2str()
94 * Description:
95 * Get the string of an ereport id. It is used as the named buffer that
96 * store the ereport.
97 */
98 static void
etm_ckpt_id2str(etm_ckpt_erpt_id_t * id,char * str,size_t size)99 etm_ckpt_id2str(etm_ckpt_erpt_id_t *id, char *str, size_t size) {
100 (void) snprintf(str, size, "%s_%llx_%d_%x_%d", ETM_CKPT_ERPT_PREFIX,
101 id->ei_ena, id->ei_hash, id->ei_tod1, id->ei_pri);
102 }
103
104 /*
105 * etm_ckpt_erpt2id()
106 * Description:
107 * Get the buffer name and ereport id of a given ereport
108 */
109 static int
etm_ckpt_erpt2id(fmd_hdl_t * hdl,nvlist_t * erpt,etm_ckpt_erpt_id_t * id,char * str,int size)110 etm_ckpt_erpt2id(fmd_hdl_t *hdl, nvlist_t *erpt, etm_ckpt_erpt_id_t *id,
111 char *str, int size) {
112 char *class = NULL;
113 uint64_t *tod;
114 uint_t sz;
115 boolean_t pri = B_FALSE;
116
117 bzero(id, sizeof (etm_ckpt_erpt_id_t));
118
119 /* ena */
120 if (nvlist_lookup_uint64(erpt, FM_EREPORT_ENA, &id->ei_ena) != 0) {
121 fmd_hdl_debug(hdl, "Ena not found\n");
122 return (-1);
123 }
124
125 /* class name */
126 (void) nvlist_lookup_string(erpt, FM_CLASS, &class);
127 if (class == NULL) {
128 fmd_hdl_debug(hdl, "%s not found\n", FM_CLASS);
129 return (-1);
130 }
131 if (strncmp(class, FM_EREPORT_CLASS, strlen(FM_EREPORT_CLASS)) != 0) {
132 fmd_hdl_debug(hdl, "Only support checkpointing %s\n",
133 FM_EREPORT_CLASS);
134 return (-1);
135 }
136 id->ei_hash = etm_ckpt_str_hash(class);
137
138 /* tod[1]: fractional of a second */
139 if (nvlist_lookup_uint64_array(erpt, ETM_ATTR_TOD, &tod, &sz) == 0) {
140 if (sz >= 2) {
141 id->ei_tod1 = (uint32_t)tod[1];
142 }
143 }
144
145 /* primary flag */
146 if (nvlist_lookup_boolean_value(erpt, ETM_ATTR_PRIMARY, &pri) == 0) {
147 id->ei_pri = pri ? 1 : 0;
148 }
149
150 etm_ckpt_id2str(id, str, size);
151
152 return (0);
153 }
154
155 /*
156 * etm_ckpt_il_equal()
157 * Description:
158 * Test if two ereport ids are equal.
159 */
160 static boolean_t
etm_ckpt_il_equal(etm_ckpt_erpt_id_t * i1,etm_ckpt_erpt_id_t * i2)161 etm_ckpt_il_equal(etm_ckpt_erpt_id_t *i1, etm_ckpt_erpt_id_t *i2)
162 {
163 return ((i1->ei_ena == i2->ei_ena) && (i1->ei_tod1 == i2->ei_tod1) &&
164 (i1->ei_pri == i2->ei_pri) && (i1->ei_hash == i2->ei_hash));
165 }
166
167 /*
168 * etm_ckpt_il_resize()
169 * Description:
170 * Increase the size of the circular list and pack its entries.
171 */
172 static void
etm_ckpt_il_resize(fmd_hdl_t * hdl,uint_t factor)173 etm_ckpt_il_resize(fmd_hdl_t *hdl, uint_t factor)
174 {
175 etm_ckpt_id_list_t *il1, *il2; /* temp lists */
176 size_t sz1, sz2; /* sizes of lists */
177 int i, next; /* temp counters */
178 etm_ckpt_erpt_id_t *p1, *p2, *s1, *s2; /* temp id pointers */
179 etm_ckpt_erpt_id_t blank; /* blank ereport id */
180
181 if (factor == 0)
182 return;
183
184 /* the present queue */
185 il1 = etm_id_lst;
186 sz1 = sizeof (etm_ckpt_id_list_t) + il1->il_ids_sz;
187
188 /* Create an empty queue with a new size */
189 sz2 = sizeof (etm_ckpt_id_list_t) + (factor * il1->il_ids_sz);
190 il2 = fmd_hdl_zalloc(hdl, sz2, FMD_SLEEP);
191 il2->il_ver = ETM_CKPT_VERSION;
192 il2->il_max = factor * etm_id_lst->il_max;
193 il2->il_ids_sz = factor * il1->il_ids_sz;
194
195 /* pointers to the two arrays of entries */
196 bzero(&blank, sizeof (blank));
197 s1 = (etm_ckpt_erpt_id_t *)
198 ((ptrdiff_t)il1 + sizeof (etm_ckpt_id_list_t));
199 s2 = (etm_ckpt_erpt_id_t *)
200 ((ptrdiff_t)il2 + sizeof (etm_ckpt_id_list_t));
201
202 /* copy non-empty ereport ids from list il1 to il2. Toss the blank. */
203 if (il1->il_head != il1->il_tail) {
204 for (i = il1->il_head; i != il1->il_tail; i = next) {
205 next = (i + 1) % il1->il_max;
206 p1 = s1 + next;
207 if (!etm_ckpt_il_equal(p1, &blank)) {
208 /* copy non-empty entries */
209 il2->il_tail = (il2->il_tail + 1) % il2->il_max;
210 fmd_hdl_debug(hdl, "Copying entry %d to %d\n",
211 next, il2->il_tail);
212 p2 = s2 + il2->il_tail;
213 *p2 = *p1;
214 il2->il_cnt++;
215 }
216 }
217 }
218
219 if (factor == 1) {
220 /* both lists have the same size, update the present list */
221 bcopy(il2, il1, sz1);
222 fmd_hdl_free(hdl, il2, sz2);
223 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il1, sz1);
224 } else {
225 /* replace the present list */
226 etm_id_lst = il2;
227 fmd_hdl_free(hdl, il1, sz1);
228 /* write to new buffer */
229 fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
230 fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, sz2);
231 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il2, sz2);
232 }
233 }
234
235 /*
236 * etm_ckpt_il_find()
237 * Description:
238 * Find the ereport id in the list.
239 */
240 /* ARGSUSED */
241 static int
etm_ckpt_il_find(fmd_hdl_t * hdl,etm_ckpt_erpt_id_t * id)242 etm_ckpt_il_find(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id)
243 {
244 int i, next; /* temp counter */
245 etm_ckpt_erpt_id_t *p, *s; /* temp erpt id */
246
247 fmd_hdl_debug(hdl, "etm_ckpt_il_find()\n");
248
249 /* empty list */
250 if (etm_id_lst->il_head == etm_id_lst->il_tail) {
251 fmd_hdl_debug(hdl, "find an empty list\n");
252 return (-1);
253 }
254 s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
255 sizeof (etm_ckpt_id_list_t));
256 for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
257 next = (i + 1) % etm_id_lst->il_max;
258 p = s + next;
259 if (etm_ckpt_il_equal(p, id))
260 return (i);
261 }
262
263 return (-1);
264 }
265
266 /*
267 * etm_ckpt_il_add()
268 * Description:
269 * Add an ereport id in the list.
270 */
271 static int
etm_ckpt_il_add(fmd_hdl_t * hdl,etm_ckpt_erpt_id_t * id)272 etm_ckpt_il_add(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
273 int next;
274 etm_ckpt_erpt_id_t *p, *s; /* temp id */
275
276 /*
277 * resize the q if it is full.
278 * If the capacity is less 80%, purge the emtpy entries to make more
279 * room for new entries. Otherwise, double the queue size.
280 */
281 next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
282 if (next == etm_id_lst->il_head) {
283 if ((etm_id_lst->il_cnt * 1.0 / etm_id_lst->il_max) < 0.8) {
284 etm_ckpt_il_resize(hdl, 1);
285 } else {
286 etm_ckpt_il_resize(hdl, 2);
287 }
288
289 /* test if the list again */
290 next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
291 if (next == etm_id_lst->il_head) {
292 fmd_hdl_error(hdl, "List is full %d %d\n",
293 etm_id_lst->il_head, etm_id_lst->il_tail);
294 }
295 }
296
297 /* Add the id entry at the head */
298 s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
299 sizeof (etm_ckpt_id_list_t));
300 etm_id_lst->il_tail = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
301 p = s + etm_id_lst->il_tail;
302 *p = *id;
303 etm_id_lst->il_cnt++;
304
305 return (etm_id_lst->il_tail);
306 }
307
308 /*
309 * etm_ckpt_il_delete()
310 * Description:
311 * Delete an ereport id from the list.
312 */
313 int
etm_ckpt_il_delete(fmd_hdl_t * hdl,etm_ckpt_erpt_id_t * id)314 etm_ckpt_il_delete(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
315
316 int i, next; /* temp counter */
317 etm_ckpt_erpt_id_t *p, *s; /* temp id pointers */
318 etm_ckpt_erpt_id_t blank; /* blank id */
319
320 /* empty list */
321 if (etm_id_lst->il_tail == etm_id_lst->il_head) {
322 fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
323 return (-1);
324 }
325
326 bzero(&blank, sizeof (blank));
327 s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
328 sizeof (etm_ckpt_id_list_t));
329
330 /* delete leading empty entries */
331 for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
332 next = (i + 1) % etm_id_lst->il_max;
333 p = s + next;
334 if (!etm_ckpt_il_equal(p, &blank)) {
335 break;
336 }
337 etm_id_lst->il_cnt--;
338 etm_id_lst->il_head = next;
339 }
340
341 /* empty queue */
342 if (etm_id_lst->il_head == etm_id_lst->il_tail) {
343 fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
344 return (-1);
345 }
346
347 /* find the entry and clear it */
348 for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
349 next = (i + 1) % etm_id_lst->il_max;
350 p = s + next;
351 if (etm_ckpt_il_equal(p, id)) {
352 /* clear the entry */
353 *p = blank;
354 etm_id_lst->il_cnt--;
355
356 /* remove the entry if it is the last one */
357 if (i == etm_id_lst->il_head) {
358 etm_id_lst->il_head = next;
359 }
360 return (i);
361 }
362 }
363
364 return (-1);
365 }
366
367
368 /*
369 * etm_ckpt_il_restore()
370 * Description:
371 * Restore the idlist named buffer which is the circular list of the
372 * the ereport ids.
373 */
374 void
etm_ckpt_il_restore(fmd_hdl_t * hdl)375 etm_ckpt_il_restore(fmd_hdl_t *hdl)
376 {
377 size_t size; /* buffer size */
378
379 /* get the buffer of the id list */
380 size = fmd_buf_size(hdl, NULL, ETM_CKPT_IL_BUF);
381 if (size < sizeof (etm_ckpt_id_list_t)) {
382 fmd_hdl_debug(hdl, "Buffer name %s do not exist\n",
383 ETM_CKPT_IL_BUF);
384 return;
385 }
386 etm_id_lst = (etm_ckpt_id_list_t *)fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
387 fmd_buf_read(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, size);
388
389 /* check version */
390 if (etm_id_lst->il_ver > ETM_CKPT_VERSION) {
391
392 fmd_hdl_error(hdl, "Unsupport checkpoint version (%#x)\n",
393 etm_id_lst->il_ver);
394 fmd_hdl_free(hdl, (void *) etm_id_lst, size);
395 etm_id_lst = NULL;
396 return;
397 }
398
399 /* check the length */
400 if (etm_id_lst->il_ids_sz != (size - sizeof (etm_ckpt_id_list_t))) {
401 fmd_hdl_debug(hdl, "Invalid ids buffer size (%d, %d)\n",
402 etm_id_lst->il_ids_sz, size);
403 fmd_hdl_free(hdl, (void *) etm_id_lst, size);
404 etm_id_lst = NULL;
405 return;
406 }
407 }
408
409 /*
410 * etm_ckpt_recover()
411 * Description:
412 * Recover ereports from the checkpointed data and dispatch them to the
413 * ldom queue(s).
414 */
415 void
etm_ckpt_recover(fmd_hdl_t * hdl)416 etm_ckpt_recover(fmd_hdl_t *hdl)
417 {
418 int size; /* buffer size */
419 int i, next; /* temp counter */
420 boolean_t dirty = B_FALSE; /* dirty flag */
421 uint64_t did; /* domain id */
422 char name[ETM_LINE_LEN]; /* temp str */
423 char ldom[ETM_LINE_LEN]; /* ldom id */
424 etm_ckpt_erpt_id_t *p, *s; /* temp ereport id */
425 etm_ckpt_erpt_id_t blank; /* blank ereport id */
426 etm_ckpt_erpt_buf_t *ep; /* ereport buffer */
427 size_t sz; /* size of ep */
428 char *buf; /* temp buf */
429 nvlist_t *nvl; /* ereport */
430 etm_iosvc_t *iosvc; /* iosvc data struct */
431
432 /*
433 * restore the circular list of ereport ids
434 */
435 etm_ckpt_il_restore(hdl);
436 if (etm_id_lst == NULL) {
437 fmd_hdl_debug(hdl, "Initialize a new id list\n");
438 size = sizeof (etm_ckpt_id_list_t) +
439 ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
440 etm_id_lst = fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
441 etm_id_lst->il_ver = ETM_CKPT_VERSION;
442 etm_id_lst->il_max = ETM_CKPT_IL_MIN_SIZE;
443 etm_id_lst->il_head = 0;
444 etm_id_lst->il_tail = 0;
445 etm_id_lst->il_ids_sz =
446 ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
447 fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
448 fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, size);
449 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
450 size);
451
452 /* commit */
453 fmd_thr_checkpoint(hdl);
454
455 return;
456 }
457
458 /* Empty list */
459 if ((etm_id_lst->il_head == etm_id_lst->il_tail) ||
460 (etm_id_lst->il_cnt == 0)) {
461 return;
462 }
463
464 /* Visit all the entries in the list */
465 bzero(&blank, sizeof (blank));
466 s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
467 sizeof (etm_ckpt_id_list_t));
468 for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
469 next = (i + 1) % etm_id_lst->il_max;
470 p = s + next;
471 if (etm_ckpt_il_equal(p, &blank)) {
472 fmd_hdl_debug(hdl, "Skip empty entry %d\n", i);
473 continue;
474 }
475
476 etm_ckpt_id2str(p, name, sizeof (name));
477 fmd_hdl_debug(hdl, "Restoring entry %s\n", name);
478 if ((sz = fmd_buf_size(hdl, NULL, name)) == 0) {
479 fmd_hdl_error(hdl, "Clear the stale entry %s\n", name);
480 *p = blank;
481 continue;
482 }
483 ep = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
484 fmd_buf_read(hdl, NULL, name, (void *) ep, sz);
485 buf = (char *)((ptrdiff_t)ep + sizeof (etm_ckpt_erpt_buf_t));
486 nvl = NULL;
487 if (nvlist_unpack(buf, ep->eb_len, &nvl, 0)) {
488 fmd_hdl_debug(hdl, "failed to unpack %s\n", name);
489 fmd_hdl_free(hdl, ep, sz);
490 continue;
491 }
492 fmd_hdl_free(hdl, ep, sz);
493 if (etm_filter_find_ldom_id(hdl, nvl, ldom, ETM_LINE_LEN,
494 &did) || (strcmp(name, ETM_LDOM_PRIMARY) == 0)) {
495 fmd_hdl_debug(hdl, "Discard event %s\n", name);
496 fmd_buf_destroy(hdl, NULL, name);
497 *p = blank;
498 nvlist_free(nvl);
499 dirty = B_TRUE;
500 continue;
501 }
502
503 fmd_hdl_debug(hdl, "Dispatch %s to ldom %s\n", name, ldom);
504
505 /*
506 * Find the queue of the ldom, create it if not exist.
507 * Then insert this event into the queue.
508 */
509 iosvc = etm_iosvc_lookup(hdl, ldom, DS_INVALID_HDL, B_TRUE);
510 if (iosvc != NULL) {
511 (void) etm_pack_ds_msg(hdl, iosvc, NULL, 0, nvl, SP_MSG,
512 ETM_CKPT_RESTORE);
513 }
514 nvlist_free(nvl);
515 }
516 if (dirty) {
517 /* update the buffer of the queue */
518 size = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
519 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
520 size);
521
522 /* commit */
523 fmd_thr_checkpoint(hdl);
524 }
525
526 } /* etm_ckpt_recover */
527
528
529 /*
530 * etm_ckpt_add_entry()
531 * Description:
532 * Save an ereport for persistence.
533 */
534 int
etm_ckpt_add_entry(fmd_hdl_t * hdl,nvlist_t * erpt)535 etm_ckpt_add_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
536 etm_ckpt_erpt_id_t id;
537 char name[ETM_LINE_LEN];
538 int rc; /* gen use */
539 size_t sz; /* size */
540 size_t buflen; /* sz of packed erpt */
541 uint8_t *buf; /* buffer of erpt */
542 etm_ckpt_erpt_buf_t *hdr;
543
544 /* map ereport to id */
545 bzero(name, ETM_LINE_LEN);
546 rc = etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN);
547 if (rc != 0) {
548 fmd_hdl_debug(hdl, "Invalid ereport\n");
549 return (rc);
550 }
551
552 /*
553 * check for a duplicate entry in the id list
554 * find the ereport buffer and search for the id
555 */
556 if (fmd_buf_size(hdl, NULL, name) > 0 &&
557 etm_ckpt_il_find(hdl, &id) >= 0) {
558 fmd_hdl_debug(hdl, "Duplicate id %s\n", name);
559 return (-1);
560 }
561
562 /* Create the ereport buffer */
563 if (nvlist_size(erpt, &buflen, NV_ENCODE_XDR) != 0) {
564 fmd_hdl_debug(hdl, "nvlist_size fails\n");
565 return (-1);
566 }
567 sz = sizeof (etm_ckpt_erpt_buf_t) + buflen;
568 hdr = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
569 buf = (uint8_t *)((ptrdiff_t)hdr + sizeof (etm_ckpt_erpt_buf_t));
570 hdr->eb_ver = ETM_CKPT_VERSION;
571 hdr->eb_len = buflen;
572 if (nvlist_pack(erpt, (char **)&buf, &buflen, NV_ENCODE_XDR, 0) != 0) {
573 fmd_hdl_free(hdl, hdr, sz);
574 fmd_hdl_debug(hdl, "unpack fails\n");
575 return (-1);
576 }
577 fmd_hdl_debug(hdl, "Add ckpt event(%s, %d)\n", name, sz);
578 fmd_buf_create(hdl, NULL, name, sz);
579 fmd_buf_write(hdl, NULL, name, hdr, sz);
580 fmd_hdl_free(hdl, hdr, sz);
581
582 /* Insert the ereport id into the id list */
583 if (etm_ckpt_il_add(hdl, &id) < 0) {
584 fmd_hdl_debug(hdl, "Insert id %s failed\n", name);
585 fmd_buf_destroy(hdl, NULL, name);
586 return (-1);
587 }
588
589 /* update the buffer of the queue */
590 sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
591 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
592
593 /* commit */
594 fmd_thr_checkpoint(hdl);
595
596 return (0);
597 }
598
599 /*
600 * etm_ckpt_delete_entry()
601 * Description:
602 * Delete an ereport id in the list.
603 */
604 static int
etm_ckpt_delete_entry(fmd_hdl_t * hdl,nvlist_t * erpt)605 etm_ckpt_delete_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
606 etm_ckpt_erpt_id_t id;
607 char name[ETM_LINE_LEN];
608 int rc; /* return code */
609 size_t sz; /* size */
610
611 /* get id, id name */
612 bzero(name, ETM_LINE_LEN);
613 if (etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN) != 0) {
614 fmd_hdl_debug(hdl, "Invalid ereport\n");
615 return (-1);
616 }
617 fmd_hdl_debug(hdl, "Delete ckpt event(%s)\n", name);
618
619 /* delete the ereport buffer */
620 if (fmd_buf_size(hdl, NULL, name) > 0) {
621 fmd_buf_destroy(hdl, NULL, name);
622 }
623
624 rc = etm_ckpt_il_delete(hdl, &id);
625 if (rc < 0) {
626 fmd_hdl_debug(hdl, "Delete id %s failed\n", name);
627 return (rc);
628 }
629
630 /* update the buffer of the queue */
631 sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
632 fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
633
634 /* commit */
635 fmd_thr_checkpoint(hdl);
636
637 return (rc);
638 }
639
640 int
etm_ckpt_add(fmd_hdl_t * hdl,nvlist_t * erpt)641 etm_ckpt_add(fmd_hdl_t *hdl, nvlist_t *erpt) {
642
643 int rc; /* return code */
644
645 (void) pthread_mutex_lock(&etm_id_lst_lock);
646
647 rc = etm_ckpt_add_entry(hdl, erpt);
648
649 (void) pthread_mutex_unlock(&etm_id_lst_lock);
650
651 return (rc >= 0 ? 0 : rc);
652 }
653
654 int
etm_ckpt_delete(fmd_hdl_t * hdl,nvlist_t * erpt)655 etm_ckpt_delete(fmd_hdl_t *hdl, nvlist_t *erpt) {
656 int rc; /* return code */
657
658 (void) pthread_mutex_lock(&etm_id_lst_lock);
659
660 rc = etm_ckpt_delete_entry(hdl, erpt);
661
662 (void) pthread_mutex_unlock(&etm_id_lst_lock);
663
664 return (rc >= 0 ? 0 : rc);
665 }
666
667 /* ARGSUSED */
668 void
etm_ckpt_init(fmd_hdl_t * hdl)669 etm_ckpt_init(fmd_hdl_t *hdl) {
670 (void) pthread_mutex_init(&etm_id_lst_lock, NULL);
671 etm_id_lst = NULL;
672 }
673
674 void
etm_ckpt_fini(fmd_hdl_t * hdl)675 etm_ckpt_fini(fmd_hdl_t *hdl) {
676 if (etm_id_lst != NULL) {
677 fmd_hdl_free(hdl, etm_id_lst,
678 sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz);
679 }
680 (void) pthread_mutex_destroy(&etm_id_lst_lock);
681 }
682