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
65static etm_ckpt_id_list_t *etm_id_lst = NULL;	/* list of ereports ids */
66
67static 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 */
78static uint_t
79etm_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 */
98static void
99etm_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 */
109static int
110etm_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 */
160static boolean_t
161etm_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 */
172static void
173etm_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 */
241static int
242etm_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 */
271static int
272etm_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 */
313int
314etm_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 */
374void
375etm_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 */
415void
416etm_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 */
534int
535etm_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 */
604static int
605etm_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
640int
641etm_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
654int
655etm_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 */
668void
669etm_ckpt_init(fmd_hdl_t *hdl) {
670	(void) pthread_mutex_init(&etm_id_lst_lock, NULL);
671	etm_id_lst = NULL;
672}
673
674void
675etm_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