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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/mkdev.h>
36 #include <fmd_module.h>
37 #include <fmd_error.h>
38 #include <fmd_alloc.h>
43 #include <fmd_event.h>
50 #define P2ROUNDUP(x, align) (-(-(x) & -(align)))
51 #define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0)
54 * The fmd_ckpt_t structure is used to manage all of the state needed by the
55 * various subroutines that save and restore checkpoints. The structure is
56 * initialized using fmd_ckpt_create() or fmd_ckpt_open() and is destroyed
57 * by fmd_ckpt_destroy(). Refer to the subroutines below for more details.
59 typedef struct fmd_ckpt
{
60 char ckp_src
[PATH_MAX
]; /* ckpt input or output filename */
61 char ckp_dst
[PATH_MAX
]; /* ckpt rename filename */
62 uchar_t
*ckp_buf
; /* data buffer base address */
63 fcf_hdr_t
*ckp_hdr
; /* file header pointer */
64 uchar_t
*ckp_ptr
; /* data buffer pointer */
65 size_t ckp_size
; /* data buffer size */
66 fcf_sec_t
*ckp_secp
; /* section header table pointer */
67 fcf_sec_t
*ckp_modp
; /* section header for module */
68 uint_t ckp_secs
; /* number of sections */
69 char *ckp_strs
; /* string table base pointer */
70 char *ckp_strp
; /* string table pointer */
71 size_t ckp_strn
; /* string table size */
72 int ckp_fd
; /* output descriptor */
73 fmd_module_t
*ckp_mp
; /* checkpoint module */
74 void *ckp_arg
; /* private arg for callbacks */
77 typedef struct fmd_ckpt_desc
{
78 uint64_t secd_size
; /* minimum section size */
79 uint32_t secd_entsize
; /* minimum section entry size */
80 uint32_t secd_align
; /* section alignment */
84 * Table of FCF section descriptions. Here we record the minimum size for each
85 * section (for use during restore) and the expected entry size and alignment
86 * for each section (for use during both checkpoint and restore).
88 static const fmd_ckpt_desc_t _fmd_ckpt_sections
[] = {
89 { 0, 0, sizeof (uint8_t) }, /* NONE */
90 { 1, 0, sizeof (char) }, /* STRTAB */
91 { sizeof (fcf_module_t
), 0, sizeof (uint32_t) }, /* MODULE */
92 { sizeof (fcf_case_t
), 0, sizeof (uint32_t) }, /* CASE */
93 { sizeof (fcf_buf_t
), sizeof (fcf_buf_t
), sizeof (uint32_t) }, /* BUFS */
94 { 0, 0, _MAX_ALIGNMENT
}, /* BUFFER */
95 { sizeof (fcf_serd_t
), sizeof (fcf_serd_t
), sizeof (uint64_t) }, /* SERD */
96 { sizeof (fcf_event_t
), sizeof (fcf_event_t
), sizeof (uint64_t) }, /* EVENTS */
97 { sizeof (fcf_nvl_t
), sizeof (fcf_nvl_t
), sizeof (uint64_t) }, /* NVLISTS */
101 fmd_ckpt_create(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
)
103 const char *dir
= mp
->mod_ckpt
;
104 const char *name
= mp
->mod_name
;
107 bzero(ckp
, sizeof (fmd_ckpt_t
));
110 ckp
->ckp_size
= sizeof (fcf_hdr_t
);
111 ckp
->ckp_strn
= 1; /* for \0 */
113 (void) snprintf(ckp
->ckp_src
, PATH_MAX
, "%s/%s+", dir
, name
);
114 (void) snprintf(ckp
->ckp_dst
, PATH_MAX
, "%s/%s", dir
, name
);
116 (void) unlink(ckp
->ckp_src
);
117 (void) fmd_conf_getprop(fmd
.d_conf
, "ckpt.mode", &mode
);
118 ckp
->ckp_fd
= open64(ckp
->ckp_src
, O_WRONLY
| O_CREAT
| O_EXCL
, mode
);
120 return (ckp
->ckp_fd
);
125 fmd_ckpt_inval(fmd_ckpt_t
*ckp
, const char *format
, ...)
129 va_start(ap
, format
);
130 fmd_verror(EFMD_CKPT_INVAL
, format
, ap
);
133 fmd_free(ckp
->ckp_buf
, ckp
->ckp_size
);
134 return (fmd_set_errno(EFMD_CKPT_INVAL
));
138 fmd_ckpt_open(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
)
145 bzero(ckp
, sizeof (fmd_ckpt_t
));
148 (void) snprintf(ckp
->ckp_src
, PATH_MAX
, "%s/%s",
149 mp
->mod_ckpt
, mp
->mod_name
);
151 if ((ckp
->ckp_fd
= open(ckp
->ckp_src
, O_RDONLY
)) == -1)
152 return (-1); /* failed to open checkpoint file */
154 if (fstat64(ckp
->ckp_fd
, &st
) == -1) {
156 (void) close(ckp
->ckp_fd
);
157 return (fmd_set_errno(err
));
160 ckp
->ckp_buf
= fmd_alloc(st
.st_size
, FMD_SLEEP
);
161 ckp
->ckp_hdr
= (void *)ckp
->ckp_buf
;
162 ckp
->ckp_size
= read(ckp
->ckp_fd
, ckp
->ckp_buf
, st
.st_size
);
164 if (ckp
->ckp_size
!= st
.st_size
|| ckp
->ckp_size
< sizeof (fcf_hdr_t
) ||
165 ckp
->ckp_size
!= ckp
->ckp_hdr
->fcfh_filesz
) {
166 err
= ckp
->ckp_size
== (size_t)-1L ? errno
: EFMD_CKPT_SHORT
;
167 fmd_free(ckp
->ckp_buf
, st
.st_size
);
168 (void) close(ckp
->ckp_fd
);
169 return (fmd_set_errno(err
));
172 (void) close(ckp
->ckp_fd
);
176 * Once we've read in a consistent copy of the FCF file and we're sure
177 * the header can be accessed, go through it and make sure everything
178 * is valid. We also check that unused bits are zero so we can expand
179 * to use them safely in the future and support old files if needed.
181 if (bcmp(&ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MAG0
],
182 FCF_MAG_STRING
, FCF_MAG_STRLEN
) != 0)
183 return (fmd_ckpt_inval(ckp
, "bad checkpoint magic string\n"));
185 if (ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MODEL
] != FCF_MODEL_NATIVE
)
186 return (fmd_ckpt_inval(ckp
, "bad checkpoint data model\n"));
188 if (ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_ENCODING
] != FCF_ENCODE_NATIVE
)
189 return (fmd_ckpt_inval(ckp
, "bad checkpoint data encoding\n"));
191 if (ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_VERSION
] != FCF_VERSION_1
) {
192 return (fmd_ckpt_inval(ckp
, "bad checkpoint version %u\n",
193 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_VERSION
]));
196 for (i
= FCF_ID_PAD
; i
< FCF_ID_SIZE
; i
++) {
197 if (ckp
->ckp_hdr
->fcfh_ident
[i
] != 0) {
198 return (fmd_ckpt_inval(ckp
,
199 "bad checkpoint padding at id[%d]", i
));
203 if (ckp
->ckp_hdr
->fcfh_flags
& ~FCF_FL_VALID
)
204 return (fmd_ckpt_inval(ckp
, "bad checkpoint flags\n"));
206 if (ckp
->ckp_hdr
->fcfh_pad
!= 0)
207 return (fmd_ckpt_inval(ckp
, "reserved field in use\n"));
209 if (ckp
->ckp_hdr
->fcfh_hdrsize
< sizeof (fcf_hdr_t
) ||
210 ckp
->ckp_hdr
->fcfh_secsize
< sizeof (fcf_sec_t
)) {
211 return (fmd_ckpt_inval(ckp
,
212 "bad header and/or section size\n"));
215 seclen
= (uint64_t)ckp
->ckp_hdr
->fcfh_secnum
*
216 (uint64_t)ckp
->ckp_hdr
->fcfh_secsize
;
218 if (ckp
->ckp_hdr
->fcfh_secoff
> ckp
->ckp_size
||
219 seclen
> ckp
->ckp_size
||
220 ckp
->ckp_hdr
->fcfh_secoff
+ seclen
> ckp
->ckp_size
||
221 ckp
->ckp_hdr
->fcfh_secoff
+ seclen
< ckp
->ckp_hdr
->fcfh_secoff
)
222 return (fmd_ckpt_inval(ckp
, "truncated section headers\n"));
224 if (!IS_P2ALIGNED(ckp
->ckp_hdr
->fcfh_secoff
, sizeof (uint64_t)) ||
225 !IS_P2ALIGNED(ckp
->ckp_hdr
->fcfh_secsize
, sizeof (uint64_t)))
226 return (fmd_ckpt_inval(ckp
, "misaligned section headers\n"));
229 * Once the header is validated, iterate over the section headers
230 * ensuring that each one is valid w.r.t. offset, alignment, and size.
231 * We also pick up the string table pointer during this pass.
233 ckp
->ckp_secp
= (void *)(ckp
->ckp_buf
+ ckp
->ckp_hdr
->fcfh_secoff
);
234 ckp
->ckp_secs
= ckp
->ckp_hdr
->fcfh_secnum
;
236 for (i
= 0; i
< ckp
->ckp_secs
; i
++) {
237 fcf_sec_t
*sp
= (void *)(ckp
->ckp_buf
+
238 ckp
->ckp_hdr
->fcfh_secoff
+ ckp
->ckp_hdr
->fcfh_secsize
* i
);
240 const fmd_ckpt_desc_t
*dp
= &_fmd_ckpt_sections
[sp
->fcfs_type
];
242 if (sp
->fcfs_flags
!= 0) {
243 return (fmd_ckpt_inval(ckp
, "section %u has invalid "
244 "section flags (0x%x)\n", i
, sp
->fcfs_flags
));
247 if (sp
->fcfs_align
& (sp
->fcfs_align
- 1)) {
248 return (fmd_ckpt_inval(ckp
, "section %u has invalid "
249 "alignment (%u)\n", i
, sp
->fcfs_align
));
252 if (sp
->fcfs_offset
& (sp
->fcfs_align
- 1)) {
253 return (fmd_ckpt_inval(ckp
, "section %u is not properly"
254 " aligned (offset %llu)\n", i
, sp
->fcfs_offset
));
257 if (sp
->fcfs_entsize
!= 0 &&
258 (sp
->fcfs_entsize
& (sp
->fcfs_align
- 1)) != 0) {
259 return (fmd_ckpt_inval(ckp
, "section %u has misaligned "
260 "entsize %u\n", i
, sp
->fcfs_entsize
));
263 if (sp
->fcfs_offset
> ckp
->ckp_size
||
264 sp
->fcfs_size
> ckp
->ckp_size
||
265 sp
->fcfs_offset
+ sp
->fcfs_size
> ckp
->ckp_size
||
266 sp
->fcfs_offset
+ sp
->fcfs_size
< sp
->fcfs_offset
) {
267 return (fmd_ckpt_inval(ckp
, "section %u has corrupt "
268 "size or offset\n", i
));
271 if (sp
->fcfs_type
>= sizeof (_fmd_ckpt_sections
) /
272 sizeof (_fmd_ckpt_sections
[0])) {
273 return (fmd_ckpt_inval(ckp
, "section %u has unknown "
274 "section type %u\n", i
, sp
->fcfs_type
));
277 if (sp
->fcfs_align
!= dp
->secd_align
) {
278 return (fmd_ckpt_inval(ckp
, "section %u has align %u "
279 "(not %u)\n", i
, sp
->fcfs_align
, dp
->secd_align
));
282 if (sp
->fcfs_size
< dp
->secd_size
||
283 sp
->fcfs_entsize
< dp
->secd_entsize
) {
284 return (fmd_ckpt_inval(ckp
, "section %u has short "
285 "size or entsize\n", i
));
288 switch (sp
->fcfs_type
) {
289 case FCF_SECT_STRTAB
:
290 if (ckp
->ckp_strs
!= NULL
) {
291 return (fmd_ckpt_inval(ckp
, "multiple string "
292 "tables are present in checkpoint file\n"));
295 ckp
->ckp_strs
= (char *)ckp
->ckp_buf
+ sp
->fcfs_offset
;
296 ckp
->ckp_strn
= sp
->fcfs_size
;
298 if (ckp
->ckp_strs
[ckp
->ckp_strn
- 1] != '\0') {
299 return (fmd_ckpt_inval(ckp
, "string table %u "
300 "is missing terminating nul byte\n", i
));
304 case FCF_SECT_MODULE
:
305 if (ckp
->ckp_modp
!= NULL
) {
306 return (fmd_ckpt_inval(ckp
, "multiple module "
307 "sects are present in checkpoint file\n"));
315 * Ensure that the first section is an empty one of type FCF_SECT_NONE.
316 * This is done to ensure that links can use index 0 as a null section.
318 if (ckp
->ckp_secs
== 0 || ckp
->ckp_secp
->fcfs_type
!= FCF_SECT_NONE
||
319 ckp
->ckp_secp
->fcfs_entsize
!= 0 || ckp
->ckp_secp
->fcfs_size
!= 0) {
320 return (fmd_ckpt_inval(ckp
, "section 0 is not of the "
321 "appropriate size and/or attributes (SECT_NONE)\n"));
324 if (ckp
->ckp_modp
== NULL
) {
325 return (fmd_ckpt_inval(ckp
,
326 "no module section found in file\n"));
333 fmd_ckpt_destroy(fmd_ckpt_t
*ckp
)
335 if (ckp
->ckp_buf
!= NULL
)
336 fmd_free(ckp
->ckp_buf
, ckp
->ckp_size
);
337 if (ckp
->ckp_fd
>= 0)
338 (void) close(ckp
->ckp_fd
);
342 * fmd_ckpt_error() is used as a wrapper around fmd_error() for ckpt routines.
343 * It calls fmd_module_unlock() on behalf of its caller, logs the error, and
344 * then aborts the API call and the surrounding module entry point by doing an
345 * fmd_module_abort(), which longjmps to the place where we entered the module.
346 * Depending on the type of error and conf settings, we will reset or fail.
350 fmd_ckpt_error(fmd_ckpt_t
*ckp
, int err
, const char *format
, ...)
352 fmd_module_t
*mp
= ckp
->ckp_mp
;
355 va_start(ap
, format
);
356 fmd_verror(err
, format
, ap
);
359 if (fmd_module_locked(mp
))
360 fmd_module_unlock(mp
);
362 fmd_ckpt_destroy(ckp
);
363 fmd_module_abort(mp
, err
);
367 fmd_ckpt_section(fmd_ckpt_t
*ckp
, const void *data
, uint_t type
, uint64_t size
)
369 const fmd_ckpt_desc_t
*dp
;
371 ASSERT(type
< sizeof (_fmd_ckpt_sections
) / sizeof (fmd_ckpt_desc_t
));
372 dp
= &_fmd_ckpt_sections
[type
];
374 ckp
->ckp_ptr
= (uchar_t
*)
375 P2ROUNDUP((uintptr_t)ckp
->ckp_ptr
, dp
->secd_align
);
377 ckp
->ckp_secp
->fcfs_type
= type
;
378 ckp
->ckp_secp
->fcfs_align
= dp
->secd_align
;
379 ckp
->ckp_secp
->fcfs_flags
= 0;
380 ckp
->ckp_secp
->fcfs_entsize
= dp
->secd_entsize
;
381 ckp
->ckp_secp
->fcfs_offset
= (size_t)(ckp
->ckp_ptr
- ckp
->ckp_buf
);
382 ckp
->ckp_secp
->fcfs_size
= size
;
385 * If the data pointer is non-NULL, copy the data to our buffer; else
386 * the caller is responsible for doing so and updating ckp->ckp_ptr.
389 bcopy(data
, ckp
->ckp_ptr
, size
);
390 ckp
->ckp_ptr
+= size
;
394 return (ckp
->ckp_secs
++);
398 fmd_ckpt_string(fmd_ckpt_t
*ckp
, const char *s
)
400 fcf_stridx_t idx
= (fcf_stridx_t
)(ckp
->ckp_strp
- ckp
->ckp_strs
);
402 (void) strcpy(ckp
->ckp_strp
, s
);
403 ckp
->ckp_strp
+= strlen(s
) + 1;
409 fmd_ckpt_alloc(fmd_ckpt_t
*ckp
, uint64_t gen
)
412 * We've added up all the sections by now: add two more for SECT_NONE
413 * and SECT_STRTAB, and add the size of the section header table and
414 * string table to the total size. We know that the fcf_hdr_t is
415 * aligned so that that fcf_sec_t's can follow it, and that fcf_sec_t
416 * is aligned so that any section can follow it, so no extra padding
417 * bytes need to be allocated between any of these items.
419 ckp
->ckp_secs
+= 2; /* for FCF_SECT_NONE and FCF_SECT_STRTAB */
420 ckp
->ckp_size
+= sizeof (fcf_sec_t
) * ckp
->ckp_secs
;
421 ckp
->ckp_size
+= ckp
->ckp_strn
;
423 TRACE((FMD_DBG_CKPT
, "alloc fcf buf size %u", ckp
->ckp_size
));
424 ckp
->ckp_buf
= fmd_zalloc(ckp
->ckp_size
, FMD_NOSLEEP
);
426 if (ckp
->ckp_buf
== NULL
)
427 return (-1); /* errno is set for us */
429 ckp
->ckp_hdr
= (void *)ckp
->ckp_buf
;
431 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MAG0
] = FCF_MAG_MAG0
;
432 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MAG1
] = FCF_MAG_MAG1
;
433 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MAG2
] = FCF_MAG_MAG2
;
434 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MAG3
] = FCF_MAG_MAG3
;
435 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_MODEL
] = FCF_MODEL_NATIVE
;
436 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_ENCODING
] = FCF_ENCODE_NATIVE
;
437 ckp
->ckp_hdr
->fcfh_ident
[FCF_ID_VERSION
] = FCF_VERSION
;
439 ckp
->ckp_hdr
->fcfh_hdrsize
= sizeof (fcf_hdr_t
);
440 ckp
->ckp_hdr
->fcfh_secsize
= sizeof (fcf_sec_t
);
441 ckp
->ckp_hdr
->fcfh_secnum
= ckp
->ckp_secs
;
442 ckp
->ckp_hdr
->fcfh_secoff
= sizeof (fcf_hdr_t
);
443 ckp
->ckp_hdr
->fcfh_filesz
= ckp
->ckp_size
;
444 ckp
->ckp_hdr
->fcfh_cgen
= gen
;
446 ckp
->ckp_secs
= 0; /* reset section counter for second pass */
447 ckp
->ckp_secp
= (void *)(ckp
->ckp_buf
+ sizeof (fcf_hdr_t
));
448 ckp
->ckp_strs
= (char *)ckp
->ckp_buf
+ ckp
->ckp_size
- ckp
->ckp_strn
;
449 ckp
->ckp_strp
= ckp
->ckp_strs
+ 1; /* use first byte as \0 */
450 ckp
->ckp_ptr
= (uchar_t
*)(ckp
->ckp_secp
+ ckp
->ckp_hdr
->fcfh_secnum
);
452 (void) fmd_ckpt_section(ckp
, NULL
, FCF_SECT_NONE
, 0);
457 fmd_ckpt_commit(fmd_ckpt_t
*ckp
)
459 fcf_sec_t
*secbase
= (void *)(ckp
->ckp_buf
+ sizeof (fcf_hdr_t
));
460 size_t stroff
= ckp
->ckp_size
- ckp
->ckp_strn
;
463 * Before committing the checkpoint, we assert that fmd_ckpt_t's sizes
464 * and current pointer locations all add up appropriately. Any ASSERTs
465 * which trip here likely indicate an inconsistency in the code for the
466 * reservation pass and the buffer update pass of the FCF subroutines.
468 ASSERT((size_t)(ckp
->ckp_ptr
- ckp
->ckp_buf
) == stroff
);
469 (void) fmd_ckpt_section(ckp
, NULL
, FCF_SECT_STRTAB
, ckp
->ckp_strn
);
470 ckp
->ckp_ptr
+= ckp
->ckp_strn
; /* string table is already filled in */
472 ASSERT(ckp
->ckp_secs
== ckp
->ckp_hdr
->fcfh_secnum
);
473 ASSERT(ckp
->ckp_secp
== secbase
+ ckp
->ckp_hdr
->fcfh_secnum
);
474 ASSERT(ckp
->ckp_ptr
== ckp
->ckp_buf
+ ckp
->ckp_hdr
->fcfh_filesz
);
476 if (write(ckp
->ckp_fd
, ckp
->ckp_buf
, ckp
->ckp_size
) != ckp
->ckp_size
||
477 fsync(ckp
->ckp_fd
) != 0 || close(ckp
->ckp_fd
) != 0)
478 return (-1); /* errno is set for us */
480 ckp
->ckp_fd
= -1; /* fd is now closed */
481 return (rename(ckp
->ckp_src
, ckp
->ckp_dst
) != 0);
485 fmd_ckpt_resv(fmd_ckpt_t
*ckp
, size_t size
, size_t align
)
488 ckp
->ckp_size
= P2ROUNDUP(ckp
->ckp_size
, align
) + size
;
494 fmd_ckpt_resv_buf(fmd_buf_t
*bp
, fmd_ckpt_t
*ckp
)
496 ckp
->ckp_size
= P2ROUNDUP(ckp
->ckp_size
, _MAX_ALIGNMENT
) + bp
->buf_size
;
497 ckp
->ckp_strn
+= strlen(bp
->buf_name
) + 1;
502 fmd_ckpt_save_buf(fmd_buf_t
*bp
, fmd_ckpt_t
*ckp
)
504 fcf_buf_t
*fcfb
= ckp
->ckp_arg
;
506 fcfb
->fcfb_name
= fmd_ckpt_string(ckp
, bp
->buf_name
);
507 fcfb
->fcfb_data
= fmd_ckpt_section(ckp
,
508 bp
->buf_data
, FCF_SECT_BUFFER
, bp
->buf_size
);
510 ckp
->ckp_arg
= fcfb
+ 1;
514 fmd_ckpt_save_event(fmd_ckpt_t
*ckp
, fmd_event_t
*e
)
516 fcf_event_t
*fcfe
= (void *)ckp
->ckp_ptr
;
517 fmd_event_impl_t
*ep
= (fmd_event_impl_t
*)e
;
518 fmd_log_t
*lp
= ep
->ev_log
;
520 fcfe
->fcfe_todsec
= ep
->ev_time
.ftv_sec
;
521 fcfe
->fcfe_todnsec
= ep
->ev_time
.ftv_nsec
;
522 fcfe
->fcfe_major
= lp
? major(lp
->log_stat
.st_dev
) : -1U;
523 fcfe
->fcfe_minor
= lp
? minor(lp
->log_stat
.st_dev
) : -1U;
524 fcfe
->fcfe_inode
= lp
? lp
->log_stat
.st_ino
: -1ULL;
525 fcfe
->fcfe_offset
= ep
->ev_off
;
527 ckp
->ckp_ptr
+= sizeof (fcf_event_t
);
531 fmd_ckpt_save_nvlist(fmd_ckpt_t
*ckp
, nvlist_t
*nvl
)
533 fcf_nvl_t
*fcfn
= (void *)ckp
->ckp_ptr
;
534 char *nvbuf
= (char *)ckp
->ckp_ptr
+ sizeof (fcf_nvl_t
);
537 (void) nvlist_size(nvl
, &nvsize
, NV_ENCODE_NATIVE
);
538 fcfn
->fcfn_size
= (uint64_t)nvsize
;
540 (void) nvlist_pack(nvl
, &nvbuf
, &nvsize
, NV_ENCODE_NATIVE
, 0);
541 ckp
->ckp_ptr
+= sizeof (fcf_nvl_t
) + nvsize
;
543 ckp
->ckp_ptr
= (uchar_t
*)
544 P2ROUNDUP((uintptr_t)ckp
->ckp_ptr
, sizeof (uint64_t));
548 fmd_ckpt_resv_serd(fmd_serd_eng_t
*sgp
, fmd_ckpt_t
*ckp
)
551 sizeof (fcf_event_t
) * sgp
->sg_count
, sizeof (uint64_t));
553 ckp
->ckp_strn
+= strlen(sgp
->sg_name
) + 1;
557 fmd_ckpt_save_serd(fmd_serd_eng_t
*sgp
, fmd_ckpt_t
*ckp
)
559 fcf_serd_t
*fcfd
= ckp
->ckp_arg
;
560 fcf_secidx_t evsec
= FCF_SECT_NONE
;
561 fmd_serd_elem_t
*sep
;
563 if (sgp
->sg_count
!= 0) {
564 evsec
= fmd_ckpt_section(ckp
, NULL
, FCF_SECT_EVENTS
,
565 sizeof (fcf_event_t
) * sgp
->sg_count
);
567 for (sep
= fmd_list_next(&sgp
->sg_list
);
568 sep
!= NULL
; sep
= fmd_list_next(sep
))
569 fmd_ckpt_save_event(ckp
, sep
->se_event
);
572 fcfd
->fcfd_name
= fmd_ckpt_string(ckp
, sgp
->sg_name
);
573 fcfd
->fcfd_events
= evsec
;
575 fcfd
->fcfd_n
= sgp
->sg_n
;
576 fcfd
->fcfd_t
= sgp
->sg_t
;
578 ckp
->ckp_arg
= fcfd
+ 1;
582 fmd_ckpt_resv_case(fmd_ckpt_t
*ckp
, fmd_case_t
*cp
)
584 fmd_case_impl_t
*cip
= (fmd_case_impl_t
*)cp
;
585 fmd_case_susp_t
*cis
;
588 if (cip
->ci_xprt
!= NULL
)
589 return; /* do not checkpoint cases from remote transports */
591 n
= fmd_buf_hash_count(&cip
->ci_bufs
);
592 fmd_buf_hash_apply(&cip
->ci_bufs
, (fmd_buf_f
*)fmd_ckpt_resv_buf
, ckp
);
593 fmd_ckpt_resv(ckp
, sizeof (fcf_buf_t
) * n
, sizeof (uint32_t));
595 if (cip
->ci_principal
!= NULL
)
596 fmd_ckpt_resv(ckp
, sizeof (fcf_event_t
), sizeof (uint64_t));
599 sizeof (fcf_event_t
) * cip
->ci_nitems
, sizeof (uint64_t));
601 if (cip
->ci_nsuspects
!= 0)
602 ckp
->ckp_size
= P2ROUNDUP(ckp
->ckp_size
, sizeof (uint64_t));
604 cip
->ci_nvsz
= 0; /* compute size of packed suspect nvlist array */
606 for (cis
= cip
->ci_suspects
; cis
!= NULL
; cis
= cis
->cis_next
) {
609 (void) nvlist_size(cis
->cis_nvl
, &nvsize
, NV_ENCODE_NATIVE
);
610 cip
->ci_nvsz
+= sizeof (fcf_nvl_t
) + nvsize
;
611 cip
->ci_nvsz
= P2ROUNDUP(cip
->ci_nvsz
, sizeof (uint64_t));
614 fmd_ckpt_resv(ckp
, cip
->ci_nvsz
, sizeof (uint64_t));
615 fmd_ckpt_resv(ckp
, sizeof (fcf_case_t
), sizeof (uint32_t));
616 ckp
->ckp_strn
+= strlen(cip
->ci_uuid
) + 1;
620 fmd_ckpt_save_case(fmd_ckpt_t
*ckp
, fmd_case_t
*cp
)
622 fmd_case_impl_t
*cip
= (fmd_case_impl_t
*)cp
;
624 fmd_case_item_t
*cit
;
625 fmd_case_susp_t
*cis
;
629 fcf_secidx_t bufsec
= FCF_SECIDX_NONE
;
630 fcf_secidx_t evsec
= FCF_SECIDX_NONE
;
631 fcf_secidx_t nvsec
= FCF_SECIDX_NONE
;
632 fcf_secidx_t prsec
= FCF_SECIDX_NONE
;
634 if (cip
->ci_xprt
!= NULL
)
635 return; /* do not checkpoint cases from remote transports */
637 if ((n
= fmd_buf_hash_count(&cip
->ci_bufs
)) != 0) {
638 size_t size
= sizeof (fcf_buf_t
) * n
;
639 fcf_buf_t
*bufs
= ckp
->ckp_arg
= fmd_alloc(size
, FMD_SLEEP
);
641 fmd_buf_hash_apply(&cip
->ci_bufs
,
642 (fmd_buf_f
*)fmd_ckpt_save_buf
, ckp
);
644 bufsec
= fmd_ckpt_section(ckp
, bufs
, FCF_SECT_BUFS
, size
);
645 fmd_free(bufs
, size
);
648 if (cip
->ci_principal
!= NULL
) {
649 prsec
= fmd_ckpt_section(ckp
, NULL
, FCF_SECT_EVENTS
,
650 sizeof (fcf_event_t
));
652 fmd_ckpt_save_event(ckp
, cip
->ci_principal
);
655 if (cip
->ci_nitems
!= 0) {
656 evsec
= fmd_ckpt_section(ckp
, NULL
, FCF_SECT_EVENTS
,
657 sizeof (fcf_event_t
) * cip
->ci_nitems
);
659 for (cit
= cip
->ci_items
; cit
!= NULL
; cit
= cit
->cit_next
)
660 fmd_ckpt_save_event(ckp
, cit
->cit_event
);
663 if (cip
->ci_nsuspects
!= 0) {
664 nvsec
= fmd_ckpt_section(ckp
, NULL
,
665 FCF_SECT_NVLISTS
, cip
->ci_nvsz
);
667 for (cis
= cip
->ci_suspects
; cis
!= NULL
; cis
= cis
->cis_next
)
668 fmd_ckpt_save_nvlist(ckp
, cis
->cis_nvl
);
671 fcfc
.fcfc_uuid
= fmd_ckpt_string(ckp
, cip
->ci_uuid
);
672 fcfc
.fcfc_bufs
= bufsec
;
673 fcfc
.fcfc_principal
= prsec
;
674 fcfc
.fcfc_events
= evsec
;
675 fcfc
.fcfc_suspects
= nvsec
;
677 switch (cip
->ci_state
) {
678 case FMD_CASE_UNSOLVED
:
679 fcfc
.fcfc_state
= FCF_CASE_UNSOLVED
;
681 case FMD_CASE_SOLVED
:
682 fcfc
.fcfc_state
= FCF_CASE_SOLVED
;
684 case FMD_CASE_CLOSE_WAIT
:
685 fcfc
.fcfc_state
= FCF_CASE_CLOSE_WAIT
;
688 fmd_panic("case %p (%s) has invalid state %u",
689 (void *)cp
, cip
->ci_uuid
, cip
->ci_state
);
692 (void) fmd_ckpt_section(ckp
, &fcfc
, FCF_SECT_CASE
, sizeof (fcf_case_t
));
696 fmd_ckpt_resv_module(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
)
701 for (cp
= fmd_list_next(&mp
->mod_cases
); cp
; cp
= fmd_list_next(cp
))
702 fmd_ckpt_resv_case(ckp
, cp
);
704 n
= fmd_serd_hash_count(&mp
->mod_serds
);
705 fmd_serd_hash_apply(&mp
->mod_serds
,
706 (fmd_serd_eng_f
*)fmd_ckpt_resv_serd
, ckp
);
707 fmd_ckpt_resv(ckp
, sizeof (fcf_serd_t
) * n
, sizeof (uint64_t));
709 n
= fmd_buf_hash_count(&mp
->mod_bufs
);
710 fmd_buf_hash_apply(&mp
->mod_bufs
, (fmd_buf_f
*)fmd_ckpt_resv_buf
, ckp
);
711 fmd_ckpt_resv(ckp
, sizeof (fcf_buf_t
) * n
, sizeof (uint32_t));
713 fmd_ckpt_resv(ckp
, sizeof (fcf_module_t
), sizeof (uint32_t));
714 ckp
->ckp_strn
+= strlen(mp
->mod_name
) + 1;
715 ckp
->ckp_strn
+= strlen(mp
->mod_path
) + 1;
716 ckp
->ckp_strn
+= strlen(mp
->mod_info
->fmdi_desc
) + 1;
717 ckp
->ckp_strn
+= strlen(mp
->mod_info
->fmdi_vers
) + 1;
721 fmd_ckpt_save_module(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
)
723 fcf_secidx_t bufsec
= FCF_SECIDX_NONE
;
728 for (cp
= fmd_list_next(&mp
->mod_cases
); cp
; cp
= fmd_list_next(cp
))
729 fmd_ckpt_save_case(ckp
, cp
);
731 if ((n
= fmd_serd_hash_count(&mp
->mod_serds
)) != 0) {
732 size_t size
= sizeof (fcf_serd_t
) * n
;
733 fcf_serd_t
*serds
= ckp
->ckp_arg
= fmd_alloc(size
, FMD_SLEEP
);
735 fmd_serd_hash_apply(&mp
->mod_serds
,
736 (fmd_serd_eng_f
*)fmd_ckpt_save_serd
, ckp
);
738 (void) fmd_ckpt_section(ckp
, serds
, FCF_SECT_SERD
, size
);
739 fmd_free(serds
, size
);
742 if ((n
= fmd_buf_hash_count(&mp
->mod_bufs
)) != 0) {
743 size_t size
= sizeof (fcf_buf_t
) * n
;
744 fcf_buf_t
*bufs
= ckp
->ckp_arg
= fmd_alloc(size
, FMD_SLEEP
);
746 fmd_buf_hash_apply(&mp
->mod_bufs
,
747 (fmd_buf_f
*)fmd_ckpt_save_buf
, ckp
);
749 bufsec
= fmd_ckpt_section(ckp
, bufs
, FCF_SECT_BUFS
, size
);
750 fmd_free(bufs
, size
);
753 fcfm
.fcfm_name
= fmd_ckpt_string(ckp
, mp
->mod_name
);
754 fcfm
.fcfm_path
= fmd_ckpt_string(ckp
, mp
->mod_path
);
755 fcfm
.fcfm_desc
= fmd_ckpt_string(ckp
, mp
->mod_info
->fmdi_desc
);
756 fcfm
.fcfm_vers
= fmd_ckpt_string(ckp
, mp
->mod_info
->fmdi_vers
);
757 fcfm
.fcfm_bufs
= bufsec
;
759 (void) fmd_ckpt_section(ckp
, &fcfm
,
760 FCF_SECT_MODULE
, sizeof (fcf_module_t
));
764 fmd_ckpt_save(fmd_module_t
*mp
)
770 hrtime_t now
= gethrtime();
774 ASSERT(fmd_module_locked(mp
));
777 * If checkpointing is disabled for the module, just return. We must
778 * commit the module state anyway to transition pending log events.
780 if (mp
->mod_stats
->ms_ckpt_save
.fmds_value
.b
== FMD_B_FALSE
) {
781 fmd_module_commit(mp
);
785 if (!(mp
->mod_flags
& (FMD_MOD_MDIRTY
| FMD_MOD_CDIRTY
)))
786 return; /* no checkpoint is necessary for this module */
788 TRACE((FMD_DBG_CKPT
, "ckpt save begin %s %llu",
789 mp
->mod_name
, mp
->mod_gen
+ 1));
792 * If the per-module checkpoint directory isn't found or isn't of type
793 * directory, move aside whatever is there (if anything) and attempt
794 * to mkdir(2) a new module checkpoint directory. If this fails, we
795 * have no choice but to abort the checkpoint and try again later.
797 if (stat64(mp
->mod_ckpt
, &st
) != 0 || !S_ISDIR(st
.st_mode
)) {
798 (void) snprintf(path
, sizeof (path
), "%s-", mp
->mod_ckpt
);
799 (void) rename(mp
->mod_ckpt
, path
);
800 (void) fmd_conf_getprop(fmd
.d_conf
, "ckpt.dirmode", &dirmode
);
802 if (mkdir(mp
->mod_ckpt
, dirmode
) != 0) {
803 fmd_error(EFMD_CKPT_MKDIR
,
804 "failed to mkdir %s", mp
->mod_ckpt
);
805 return; /* return without clearing dirty bits */
810 * Create a temporary file to write out the checkpoint into, and create
811 * a fmd_ckpt_t structure to manage construction of the checkpoint. We
812 * then figure out how much space will be required, and allocate it.
814 if (fmd_ckpt_create(&ckp
, mp
) == -1) {
815 fmd_error(EFMD_CKPT_CREATE
, "failed to create %s", ckp
.ckp_src
);
819 fmd_ckpt_resv_module(&ckp
, mp
);
821 if (fmd_ckpt_alloc(&ckp
, mp
->mod_gen
+ 1) != 0) {
822 fmd_error(EFMD_CKPT_NOMEM
, "failed to build %s", ckp
.ckp_src
);
823 fmd_ckpt_destroy(&ckp
);
828 * Fill in the checkpoint content, write it to disk, sync it, and then
829 * atomically rename it to the destination path. If this fails, we
830 * have no choice but to leave all our dirty bits set and return.
832 fmd_ckpt_save_module(&ckp
, mp
);
833 err
= fmd_ckpt_commit(&ckp
);
834 fmd_ckpt_destroy(&ckp
);
837 fmd_error(EFMD_CKPT_COMMIT
, "failed to commit %s", ckp
.ckp_dst
);
838 return; /* return without clearing dirty bits */
841 fmd_module_commit(mp
);
842 TRACE((FMD_DBG_CKPT
, "ckpt save end %s", mp
->mod_name
));
844 mp
->mod_stats
->ms_ckpt_cnt
.fmds_value
.ui64
++;
845 mp
->mod_stats
->ms_ckpt_time
.fmds_value
.ui64
+= gethrtime() - now
;
847 fmd_dprintf(FMD_DBG_CKPT
, "saved checkpoint of %s (%llu)\n",
848 mp
->mod_name
, mp
->mod_gen
);
852 * Utility function to retrieve a pointer to a section's header and verify that
853 * it is of the expected type or it is a FCF_SECT_NONE reference.
855 static const fcf_sec_t
*
856 fmd_ckpt_secptr(fmd_ckpt_t
*ckp
, fcf_secidx_t sid
, uint_t type
)
858 const fcf_sec_t
*sp
= (void *)(ckp
->ckp_buf
+
859 ckp
->ckp_hdr
->fcfh_secoff
+ ckp
->ckp_hdr
->fcfh_secsize
* sid
);
861 return (sid
< ckp
->ckp_secs
&& (sp
->fcfs_type
== type
||
862 sp
->fcfs_type
== FCF_SECT_NONE
) ? sp
: NULL
);
866 * Utility function to retrieve the data pointer for a particular section. The
867 * validity of the header values has already been checked by fmd_ckpt_open().
870 fmd_ckpt_dataptr(fmd_ckpt_t
*ckp
, const fcf_sec_t
*sp
)
872 return (ckp
->ckp_buf
+ sp
->fcfs_offset
);
876 * Utility function to retrieve the end of the data region for a particular
877 * section. The validity of this value has been confirmed by fmd_ckpt_open().
880 fmd_ckpt_datalim(fmd_ckpt_t
*ckp
, const fcf_sec_t
*sp
)
882 return (ckp
->ckp_buf
+ sp
->fcfs_offset
+ sp
->fcfs_size
);
886 * Utility function to retrieve a string pointer (fcf_stridx_t). If the string
887 * index is valid, the string data is returned; otherwise 'defstr' is returned.
890 fmd_ckpt_strptr(fmd_ckpt_t
*ckp
, fcf_stridx_t sid
, const char *defstr
)
892 return (sid
< ckp
->ckp_strn
? ckp
->ckp_strs
+ sid
: defstr
);
896 fmd_ckpt_restore_events(fmd_ckpt_t
*ckp
, fcf_secidx_t sid
,
897 void (*func
)(void *, fmd_event_t
*), void *arg
)
899 const fcf_event_t
*fcfe
;
902 fmd_log_t
*lp
, *errlp
;
904 uint32_t e_maj
, e_min
;
907 if ((sp
= fmd_ckpt_secptr(ckp
, sid
, FCF_SECT_EVENTS
)) == NULL
) {
908 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
909 "invalid link to section %u: expected events\n", sid
);
912 if (sp
->fcfs_size
== 0)
913 return; /* empty events section or type none */
915 fcfe
= fmd_ckpt_dataptr(ckp
, sp
);
916 n
= sp
->fcfs_size
/ sp
->fcfs_entsize
;
919 * Hold the reader lock on log pointers to block log rotation during
920 * the section restore so that we can safely insert refs to d_errlog.
922 (void) pthread_rwlock_rdlock(&fmd
.d_log_lock
);
923 errlp
= fmd
.d_errlog
;
925 e_maj
= major(errlp
->log_stat
.st_dev
);
926 e_min
= minor(errlp
->log_stat
.st_dev
);
927 e_ino
= errlp
->log_stat
.st_ino
;
929 for (i
= 0; i
< n
; i
++) {
932 ftv
.ftv_sec
= fcfe
->fcfe_todsec
;
933 ftv
.ftv_nsec
= fcfe
->fcfe_todnsec
;
935 if (e_ino
== fcfe
->fcfe_inode
&&
936 e_maj
== fcfe
->fcfe_major
&&
937 e_min
== fcfe
->fcfe_minor
)
942 ep
= fmd_event_recreate(FMD_EVT_PROTOCOL
,
943 &ftv
, NULL
, NULL
, lp
, fcfe
->fcfe_offset
, 0);
948 fcfe
= (fcf_event_t
*)((uintptr_t)fcfe
+ sp
->fcfs_entsize
);
951 (void) pthread_rwlock_unlock(&fmd
.d_log_lock
);
955 fmd_ckpt_restore_suspects(fmd_ckpt_t
*ckp
, fmd_case_t
*cp
, fcf_secidx_t sid
)
957 const fcf_nvl_t
*fcfn
, *endn
;
962 if ((sp
= fmd_ckpt_secptr(ckp
, sid
, FCF_SECT_NVLISTS
)) == NULL
) {
963 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
964 "invalid link to section %u: expected nvlists\n", sid
);
967 fcfn
= fmd_ckpt_dataptr(ckp
, sp
);
968 endn
= fmd_ckpt_datalim(ckp
, sp
);
970 for (i
= 0; fcfn
< endn
; i
++) {
971 char *data
= (char *)fcfn
+ sp
->fcfs_entsize
;
972 size_t size
= (size_t)fcfn
->fcfn_size
;
974 if (fcfn
->fcfn_size
> (size_t)((char *)endn
- data
)) {
975 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
, "nvlist %u [%d] "
976 "size %u exceeds buffer\n", sid
, i
, size
);
979 if ((err
= nvlist_xunpack(data
, size
, &nvl
, &fmd
.d_nva
)) != 0) {
980 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
, "failed to "
981 "unpack nvlist %u [%d]: %s\n", sid
, i
,
985 fmd_case_insert_suspect(cp
, nvl
);
987 size
= sp
->fcfs_entsize
+ fcfn
->fcfn_size
;
988 size
= P2ROUNDUP(size
, sizeof (uint64_t));
989 fcfn
= (fcf_nvl_t
*)((uintptr_t)fcfn
+ size
);
996 fmd_ckpt_restore_bufs(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
,
997 fmd_case_t
*cp
, fcf_secidx_t sid
)
999 const fcf_sec_t
*sp
, *dsp
;
1000 const fcf_buf_t
*fcfb
;
1003 if ((sp
= fmd_ckpt_secptr(ckp
, sid
, FCF_SECT_BUFS
)) == NULL
) {
1004 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
1005 "invalid link to section %u: expected bufs\n", sid
);
1008 if (sp
->fcfs_size
== 0)
1009 return; /* empty events section or type none */
1011 fcfb
= fmd_ckpt_dataptr(ckp
, sp
);
1012 n
= sp
->fcfs_size
/ sp
->fcfs_entsize
;
1014 for (i
= 0; i
< n
; i
++) {
1015 dsp
= fmd_ckpt_secptr(ckp
, fcfb
->fcfb_data
, FCF_SECT_BUFFER
);
1018 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
, "invalid %u "
1019 "buffer link %u\n", sid
, fcfb
->fcfb_data
);
1022 fmd_buf_write((fmd_hdl_t
*)mp
, cp
,
1023 fmd_ckpt_strptr(ckp
, fcfb
->fcfb_name
, "<CORRUPT>"),
1024 ckp
->ckp_buf
+ dsp
->fcfs_offset
, dsp
->fcfs_size
);
1026 fcfb
= (fcf_buf_t
*)((uintptr_t)fcfb
+ sp
->fcfs_entsize
);
1031 fmd_ckpt_restore_case(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
, const fcf_sec_t
*sp
)
1033 const fcf_case_t
*fcfc
= fmd_ckpt_dataptr(ckp
, sp
);
1034 const char *uuid
= fmd_ckpt_strptr(ckp
, fcfc
->fcfc_uuid
, NULL
);
1038 if (uuid
== NULL
|| fcfc
->fcfc_state
> FCF_CASE_CLOSE_WAIT
) {
1039 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
, "corrupt %u case uuid "
1040 "and/or state\n", (uint_t
)(sp
- ckp
->ckp_secp
));
1043 fmd_module_lock(mp
);
1045 if ((cp
= fmd_case_recreate(mp
, NULL
,
1046 fcfc
->fcfc_state
!= FCF_CASE_UNSOLVED
? FCF_CASE_SOLVED
:
1047 FMD_CASE_UNSOLVED
, uuid
, NULL
)) == NULL
) {
1048 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
1049 "duplicate case uuid: %s\n", uuid
);
1052 fmd_ckpt_restore_events(ckp
, fcfc
->fcfc_principal
,
1053 (void (*)(void *, fmd_event_t
*))fmd_case_insert_principal
, cp
);
1055 fmd_ckpt_restore_events(ckp
, fcfc
->fcfc_events
,
1056 (void (*)(void *, fmd_event_t
*))fmd_case_insert_event
, cp
);
1059 * Once solved, treat suspects from resource cache as master copy.
1061 * If !fmd.d_running, this module must be a builtin, and so we don't
1062 * want to restore suspects or call fmd_case_transition_update() at this
1063 * stage. The suspects will be added later from the resource cache.
1064 * Calling fmd_case_transition("SOLVED") is OK here as the state is
1065 * already solved, so all it does is update the case flags.
1067 if (fmd
.d_running
&& (n
= ((fmd_case_impl_t
*)cp
)->ci_nsuspects
) == 0)
1068 n
= fmd_ckpt_restore_suspects(ckp
, cp
, fcfc
->fcfc_suspects
);
1071 fmd_case_transition(cp
, FMD_CASE_SOLVED
, FMD_CF_SOLVED
);
1072 else if (fcfc
->fcfc_state
== FCF_CASE_SOLVED
)
1073 fmd_case_transition_update(cp
, FMD_CASE_SOLVED
, FMD_CF_SOLVED
);
1074 else if (fcfc
->fcfc_state
== FCF_CASE_CLOSE_WAIT
&& n
!= 0)
1075 fmd_case_transition(cp
, FMD_CASE_CLOSE_WAIT
, FMD_CF_SOLVED
);
1076 else if (fcfc
->fcfc_state
== FCF_CASE_CLOSE_WAIT
&& n
== 0)
1077 fmd_case_transition(cp
, FMD_CASE_CLOSE_WAIT
, 0);
1079 fmd_module_unlock(mp
);
1080 fmd_ckpt_restore_bufs(ckp
, mp
, cp
, fcfc
->fcfc_bufs
);
1084 fmd_ckpt_restore_serd(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
, const fcf_sec_t
*sp
)
1086 const fcf_serd_t
*fcfd
= fmd_ckpt_dataptr(ckp
, sp
);
1087 uint_t i
, n
= sp
->fcfs_size
/ sp
->fcfs_entsize
;
1088 const fcf_sec_t
*esp
;
1091 for (i
= 0; i
< n
; i
++) {
1092 esp
= fmd_ckpt_secptr(ckp
, fcfd
->fcfd_events
, FCF_SECT_EVENTS
);
1095 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
1096 "invalid events link %u\n", fcfd
->fcfd_events
);
1099 if ((s
= fmd_ckpt_strptr(ckp
, fcfd
->fcfd_name
, NULL
)) == NULL
) {
1100 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
1101 "serd name %u is corrupt\n", fcfd
->fcfd_name
);
1104 fmd_serd_create((fmd_hdl_t
*)mp
, s
, fcfd
->fcfd_n
, fcfd
->fcfd_t
);
1105 fmd_module_lock(mp
);
1107 fmd_ckpt_restore_events(ckp
, fcfd
->fcfd_events
,
1108 (void (*)(void *, fmd_event_t
*))fmd_serd_eng_record
,
1109 fmd_serd_eng_lookup(&mp
->mod_serds
, s
));
1111 fmd_module_unlock(mp
);
1112 fcfd
= (fcf_serd_t
*)((uintptr_t)fcfd
+ sp
->fcfs_entsize
);
1117 fmd_ckpt_restore_module(fmd_ckpt_t
*ckp
, fmd_module_t
*mp
)
1119 const fcf_module_t
*fcfm
= fmd_ckpt_dataptr(ckp
, ckp
->ckp_modp
);
1120 const fcf_sec_t
*sp
;
1123 if (strcmp(mp
->mod_name
, fmd_ckpt_strptr(ckp
, fcfm
->fcfm_name
, "")) ||
1124 strcmp(mp
->mod_path
, fmd_ckpt_strptr(ckp
, fcfm
->fcfm_path
, ""))) {
1125 fmd_ckpt_error(ckp
, EFMD_CKPT_INVAL
,
1126 "checkpoint is not for module %s\n", mp
->mod_name
);
1129 for (i
= 0; i
< ckp
->ckp_secs
; i
++) {
1130 sp
= (void *)(ckp
->ckp_buf
+
1131 ckp
->ckp_hdr
->fcfh_secoff
+ ckp
->ckp_hdr
->fcfh_secsize
* i
);
1133 switch (sp
->fcfs_type
) {
1135 fmd_ckpt_restore_case(ckp
, mp
, sp
);
1138 fmd_ckpt_restore_serd(ckp
, mp
, sp
);
1143 fmd_ckpt_restore_bufs(ckp
, mp
, NULL
, fcfm
->fcfm_bufs
);
1144 mp
->mod_gen
= ckp
->ckp_hdr
->fcfh_cgen
;
1148 * Restore a checkpoint for the specified module. Any errors which occur
1149 * during restore will call fmd_ckpt_error() or trigger an fmd_api_error(),
1150 * either of which will automatically unlock the module and trigger an abort.
1153 fmd_ckpt_restore(fmd_module_t
*mp
)
1157 if (mp
->mod_stats
->ms_ckpt_restore
.fmds_value
.b
== FMD_B_FALSE
)
1158 return; /* never restore checkpoints for this module */
1160 TRACE((FMD_DBG_CKPT
, "ckpt restore begin %s", mp
->mod_name
));
1162 if (fmd_ckpt_open(&ckp
, mp
) == -1) {
1163 if (errno
!= ENOENT
)
1164 fmd_error(EFMD_CKPT_OPEN
, "can't open %s", ckp
.ckp_src
);
1165 TRACE((FMD_DBG_CKPT
, "ckpt restore end %s", mp
->mod_name
));
1169 ASSERT(!fmd_module_locked(mp
));
1170 fmd_ckpt_restore_module(&ckp
, mp
);
1171 fmd_ckpt_destroy(&ckp
);
1172 fmd_module_clrdirty(mp
);
1174 TRACE((FMD_DBG_CKPT
, "ckpt restore end %s", mp
->mod_name
));
1175 fmd_dprintf(FMD_DBG_CKPT
, "restored checkpoint of %s\n", mp
->mod_name
);
1179 * Delete the module's checkpoint file. This is used by the ckpt.zero property
1180 * code or by the fmadm reset RPC service path to force a checkpoint delete.
1183 fmd_ckpt_delete(fmd_module_t
*mp
)
1185 char path
[PATH_MAX
];
1187 (void) snprintf(path
, sizeof (path
),
1188 "%s/%s", mp
->mod_ckpt
, mp
->mod_name
);
1190 TRACE((FMD_DBG_CKPT
, "delete %s ckpt", mp
->mod_name
));
1192 if (unlink(path
) != 0 && errno
!= ENOENT
)
1193 fmd_error(EFMD_CKPT_DELETE
, "failed to delete %s", path
);
1197 * Move aside the module's checkpoint file if checkpoint restore has failed.
1198 * We rename the file rather than deleting it in the hopes that someone might
1199 * send it to us for post-mortem analysis of whether we have a checkpoint bug.
1202 fmd_ckpt_rename(fmd_module_t
*mp
)
1204 char src
[PATH_MAX
], dst
[PATH_MAX
];
1206 (void) snprintf(src
, sizeof (src
), "%s/%s", mp
->mod_ckpt
, mp
->mod_name
);
1207 (void) snprintf(dst
, sizeof (dst
), "%s-", src
);
1209 TRACE((FMD_DBG_CKPT
, "rename %s ckpt", mp
->mod_name
));
1211 if (rename(src
, dst
) != 0 && errno
!= ENOENT
)
1212 fmd_error(EFMD_CKPT_DELETE
, "failed to rename %s", src
);