xref: /titanic_44/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.c (revision 25351652d920ae27c5a56c199da581033ce763f6)
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