17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 547911a7dScy152378 * Common Development and Distribution License (the "License"). 647911a7dScy152378 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21d9638e54Smws 227c478bd9Sstevel@tonic-gate /* 23*cbf75e67SStephen Hanson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 297c478bd9Sstevel@tonic-gate #include <sys/stat.h> 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <strings.h> 327c478bd9Sstevel@tonic-gate #include <unistd.h> 337c478bd9Sstevel@tonic-gate #include <limits.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <fmd_module.h> 377c478bd9Sstevel@tonic-gate #include <fmd_error.h> 387c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 397c478bd9Sstevel@tonic-gate #include <fmd_case.h> 407c478bd9Sstevel@tonic-gate #include <fmd_serd.h> 417c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 427c478bd9Sstevel@tonic-gate #include <fmd_conf.h> 437c478bd9Sstevel@tonic-gate #include <fmd_event.h> 447c478bd9Sstevel@tonic-gate #include <fmd_log.h> 457c478bd9Sstevel@tonic-gate #include <fmd_api.h> 467c478bd9Sstevel@tonic-gate #include <fmd_ckpt.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <fmd.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #define P2ROUNDUP(x, align) (-(-(x) & -(align))) 517c478bd9Sstevel@tonic-gate #define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0) 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * The fmd_ckpt_t structure is used to manage all of the state needed by the 557c478bd9Sstevel@tonic-gate * various subroutines that save and restore checkpoints. The structure is 567c478bd9Sstevel@tonic-gate * initialized using fmd_ckpt_create() or fmd_ckpt_open() and is destroyed 577c478bd9Sstevel@tonic-gate * by fmd_ckpt_destroy(). Refer to the subroutines below for more details. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate typedef struct fmd_ckpt { 607c478bd9Sstevel@tonic-gate char ckp_src[PATH_MAX]; /* ckpt input or output filename */ 617c478bd9Sstevel@tonic-gate char ckp_dst[PATH_MAX]; /* ckpt rename filename */ 627c478bd9Sstevel@tonic-gate uchar_t *ckp_buf; /* data buffer base address */ 637c478bd9Sstevel@tonic-gate fcf_hdr_t *ckp_hdr; /* file header pointer */ 647c478bd9Sstevel@tonic-gate uchar_t *ckp_ptr; /* data buffer pointer */ 657c478bd9Sstevel@tonic-gate size_t ckp_size; /* data buffer size */ 667c478bd9Sstevel@tonic-gate fcf_sec_t *ckp_secp; /* section header table pointer */ 677c478bd9Sstevel@tonic-gate fcf_sec_t *ckp_modp; /* section header for module */ 687c478bd9Sstevel@tonic-gate uint_t ckp_secs; /* number of sections */ 697c478bd9Sstevel@tonic-gate char *ckp_strs; /* string table base pointer */ 707c478bd9Sstevel@tonic-gate char *ckp_strp; /* string table pointer */ 717c478bd9Sstevel@tonic-gate size_t ckp_strn; /* string table size */ 727c478bd9Sstevel@tonic-gate int ckp_fd; /* output descriptor */ 737c478bd9Sstevel@tonic-gate fmd_module_t *ckp_mp; /* checkpoint module */ 747c478bd9Sstevel@tonic-gate void *ckp_arg; /* private arg for callbacks */ 757c478bd9Sstevel@tonic-gate } fmd_ckpt_t; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate typedef struct fmd_ckpt_desc { 787c478bd9Sstevel@tonic-gate uint64_t secd_size; /* minimum section size */ 797c478bd9Sstevel@tonic-gate uint32_t secd_entsize; /* minimum section entry size */ 807c478bd9Sstevel@tonic-gate uint32_t secd_align; /* section alignment */ 817c478bd9Sstevel@tonic-gate } fmd_ckpt_desc_t; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * Table of FCF section descriptions. Here we record the minimum size for each 857c478bd9Sstevel@tonic-gate * section (for use during restore) and the expected entry size and alignment 867c478bd9Sstevel@tonic-gate * for each section (for use during both checkpoint and restore). 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate static const fmd_ckpt_desc_t _fmd_ckpt_sections[] = { 897c478bd9Sstevel@tonic-gate { 0, 0, sizeof (uint8_t) }, /* NONE */ 907c478bd9Sstevel@tonic-gate { 1, 0, sizeof (char) }, /* STRTAB */ 917c478bd9Sstevel@tonic-gate { sizeof (fcf_module_t), 0, sizeof (uint32_t) }, /* MODULE */ 927c478bd9Sstevel@tonic-gate { sizeof (fcf_case_t), 0, sizeof (uint32_t) }, /* CASE */ 937c478bd9Sstevel@tonic-gate { sizeof (fcf_buf_t), sizeof (fcf_buf_t), sizeof (uint32_t) }, /* BUFS */ 947c478bd9Sstevel@tonic-gate { 0, 0, _MAX_ALIGNMENT }, /* BUFFER */ 957c478bd9Sstevel@tonic-gate { sizeof (fcf_serd_t), sizeof (fcf_serd_t), sizeof (uint64_t) }, /* SERD */ 967c478bd9Sstevel@tonic-gate { sizeof (fcf_event_t), sizeof (fcf_event_t), sizeof (uint64_t) }, /* EVENTS */ 977c478bd9Sstevel@tonic-gate { sizeof (fcf_nvl_t), sizeof (fcf_nvl_t), sizeof (uint64_t) }, /* NVLISTS */ 987c478bd9Sstevel@tonic-gate }; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static int 1017c478bd9Sstevel@tonic-gate fmd_ckpt_create(fmd_ckpt_t *ckp, fmd_module_t *mp) 1027c478bd9Sstevel@tonic-gate { 1037c478bd9Sstevel@tonic-gate const char *dir = mp->mod_ckpt; 1047c478bd9Sstevel@tonic-gate const char *name = mp->mod_name; 1057c478bd9Sstevel@tonic-gate mode_t mode; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate bzero(ckp, sizeof (fmd_ckpt_t)); 1087c478bd9Sstevel@tonic-gate ckp->ckp_mp = mp; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate ckp->ckp_size = sizeof (fcf_hdr_t); 1117c478bd9Sstevel@tonic-gate ckp->ckp_strn = 1; /* for \0 */ 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_src, PATH_MAX, "%s/%s+", dir, name); 1147c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_dst, PATH_MAX, "%s/%s", dir, name); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate (void) unlink(ckp->ckp_src); 1177c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.mode", &mode); 1187c478bd9Sstevel@tonic-gate ckp->ckp_fd = open64(ckp->ckp_src, O_WRONLY | O_CREAT | O_EXCL, mode); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate return (ckp->ckp_fd); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 1247c478bd9Sstevel@tonic-gate static int 1257c478bd9Sstevel@tonic-gate fmd_ckpt_inval(fmd_ckpt_t *ckp, const char *format, ...) 1267c478bd9Sstevel@tonic-gate { 1277c478bd9Sstevel@tonic-gate va_list ap; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate va_start(ap, format); 1307c478bd9Sstevel@tonic-gate fmd_verror(EFMD_CKPT_INVAL, format, ap); 1317c478bd9Sstevel@tonic-gate va_end(ap); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, ckp->ckp_size); 1347c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_CKPT_INVAL)); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static int 1387c478bd9Sstevel@tonic-gate fmd_ckpt_open(fmd_ckpt_t *ckp, fmd_module_t *mp) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate struct stat64 st; 1417c478bd9Sstevel@tonic-gate uint64_t seclen; 1427c478bd9Sstevel@tonic-gate uint_t i; 1437c478bd9Sstevel@tonic-gate int err; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate bzero(ckp, sizeof (fmd_ckpt_t)); 1467c478bd9Sstevel@tonic-gate ckp->ckp_mp = mp; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_src, PATH_MAX, "%s/%s", 1497c478bd9Sstevel@tonic-gate mp->mod_ckpt, mp->mod_name); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate if ((ckp->ckp_fd = open(ckp->ckp_src, O_RDONLY)) == -1) 1527c478bd9Sstevel@tonic-gate return (-1); /* failed to open checkpoint file */ 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (fstat64(ckp->ckp_fd, &st) == -1) { 1557c478bd9Sstevel@tonic-gate err = errno; 1567c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 1577c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate ckp->ckp_buf = fmd_alloc(st.st_size, FMD_SLEEP); 1617c478bd9Sstevel@tonic-gate ckp->ckp_hdr = (void *)ckp->ckp_buf; 1627c478bd9Sstevel@tonic-gate ckp->ckp_size = read(ckp->ckp_fd, ckp->ckp_buf, st.st_size); 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (ckp->ckp_size != st.st_size || ckp->ckp_size < sizeof (fcf_hdr_t) || 1657c478bd9Sstevel@tonic-gate ckp->ckp_size != ckp->ckp_hdr->fcfh_filesz) { 1667c478bd9Sstevel@tonic-gate err = ckp->ckp_size == (size_t)-1L ? errno : EFMD_CKPT_SHORT; 1677c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, st.st_size); 1687c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 1697c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 1737c478bd9Sstevel@tonic-gate ckp->ckp_fd = -1; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * Once we've read in a consistent copy of the FCF file and we're sure 1777c478bd9Sstevel@tonic-gate * the header can be accessed, go through it and make sure everything 1787c478bd9Sstevel@tonic-gate * is valid. We also check that unused bits are zero so we can expand 1797c478bd9Sstevel@tonic-gate * to use them safely in the future and support old files if needed. 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate if (bcmp(&ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG0], 1827c478bd9Sstevel@tonic-gate FCF_MAG_STRING, FCF_MAG_STRLEN) != 0) 1837c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint magic string\n")); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_MODEL] != FCF_MODEL_NATIVE) 1867c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint data model\n")); 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_ENCODING] != FCF_ENCODE_NATIVE) 1897c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint data encoding\n")); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION] != FCF_VERSION_1) { 1927c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint version %u\n", 1937c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION])); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate for (i = FCF_ID_PAD; i < FCF_ID_SIZE; i++) { 1977c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[i] != 0) { 1987c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 1997c478bd9Sstevel@tonic-gate "bad checkpoint padding at id[%d]", i)); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_flags & ~FCF_FL_VALID) 2047c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint flags\n")); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_pad != 0) 2077c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "reserved field in use\n")); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_hdrsize < sizeof (fcf_hdr_t) || 2107c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secsize < sizeof (fcf_sec_t)) { 2117c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 2127c478bd9Sstevel@tonic-gate "bad header and/or section size\n")); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate seclen = (uint64_t)ckp->ckp_hdr->fcfh_secnum * 2167c478bd9Sstevel@tonic-gate (uint64_t)ckp->ckp_hdr->fcfh_secsize; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_secoff > ckp->ckp_size || 2197c478bd9Sstevel@tonic-gate seclen > ckp->ckp_size || 2207c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + seclen > ckp->ckp_size || 2217c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + seclen < ckp->ckp_hdr->fcfh_secoff) 2227c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "truncated section headers\n")); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (!IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secoff, sizeof (uint64_t)) || 2257c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secsize, sizeof (uint64_t))) 2267c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "misaligned section headers\n")); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Once the header is validated, iterate over the section headers 2307c478bd9Sstevel@tonic-gate * ensuring that each one is valid w.r.t. offset, alignment, and size. 2317c478bd9Sstevel@tonic-gate * We also pick up the string table pointer during this pass. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate ckp->ckp_secp = (void *)(ckp->ckp_buf + ckp->ckp_hdr->fcfh_secoff); 2347c478bd9Sstevel@tonic-gate ckp->ckp_secs = ckp->ckp_hdr->fcfh_secnum; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate for (i = 0; i < ckp->ckp_secs; i++) { 2377c478bd9Sstevel@tonic-gate fcf_sec_t *sp = (void *)(ckp->ckp_buf + 2387c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * i); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate const fmd_ckpt_desc_t *dp = &_fmd_ckpt_sections[sp->fcfs_type]; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (sp->fcfs_flags != 0) { 2437c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has invalid " 2447c478bd9Sstevel@tonic-gate "section flags (0x%x)\n", i, sp->fcfs_flags)); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate if (sp->fcfs_align & (sp->fcfs_align - 1)) { 2487c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has invalid " 2497c478bd9Sstevel@tonic-gate "alignment (%u)\n", i, sp->fcfs_align)); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate if (sp->fcfs_offset & (sp->fcfs_align - 1)) { 2537c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u is not properly" 2547c478bd9Sstevel@tonic-gate " aligned (offset %llu)\n", i, sp->fcfs_offset)); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate if (sp->fcfs_entsize != 0 && 2587c478bd9Sstevel@tonic-gate (sp->fcfs_entsize & (sp->fcfs_align - 1)) != 0) { 2597c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has misaligned " 2607c478bd9Sstevel@tonic-gate "entsize %u\n", i, sp->fcfs_entsize)); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate if (sp->fcfs_offset > ckp->ckp_size || 2647c478bd9Sstevel@tonic-gate sp->fcfs_size > ckp->ckp_size || 2657c478bd9Sstevel@tonic-gate sp->fcfs_offset + sp->fcfs_size > ckp->ckp_size || 2667c478bd9Sstevel@tonic-gate sp->fcfs_offset + sp->fcfs_size < sp->fcfs_offset) { 2677c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has corrupt " 2687c478bd9Sstevel@tonic-gate "size or offset\n", i)); 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate if (sp->fcfs_type >= sizeof (_fmd_ckpt_sections) / 2727c478bd9Sstevel@tonic-gate sizeof (_fmd_ckpt_sections[0])) { 2737c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has unknown " 2747c478bd9Sstevel@tonic-gate "section type %u\n", i, sp->fcfs_type)); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (sp->fcfs_align != dp->secd_align) { 2787c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has align %u " 2797c478bd9Sstevel@tonic-gate "(not %u)\n", i, sp->fcfs_align, dp->secd_align)); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (sp->fcfs_size < dp->secd_size || 2837c478bd9Sstevel@tonic-gate sp->fcfs_entsize < dp->secd_entsize) { 2847c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has short " 2857c478bd9Sstevel@tonic-gate "size or entsize\n", i)); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate switch (sp->fcfs_type) { 2897c478bd9Sstevel@tonic-gate case FCF_SECT_STRTAB: 2907c478bd9Sstevel@tonic-gate if (ckp->ckp_strs != NULL) { 2917c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "multiple string " 2927c478bd9Sstevel@tonic-gate "tables are present in checkpoint file\n")); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate ckp->ckp_strs = (char *)ckp->ckp_buf + sp->fcfs_offset; 2967c478bd9Sstevel@tonic-gate ckp->ckp_strn = sp->fcfs_size; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if (ckp->ckp_strs[ckp->ckp_strn - 1] != '\0') { 2997c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "string table %u " 3007c478bd9Sstevel@tonic-gate "is missing terminating nul byte\n", i)); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate break; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate case FCF_SECT_MODULE: 3057c478bd9Sstevel@tonic-gate if (ckp->ckp_modp != NULL) { 3067c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "multiple module " 3077c478bd9Sstevel@tonic-gate "sects are present in checkpoint file\n")); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate ckp->ckp_modp = sp; 3107c478bd9Sstevel@tonic-gate break; 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Ensure that the first section is an empty one of type FCF_SECT_NONE. 3167c478bd9Sstevel@tonic-gate * This is done to ensure that links can use index 0 as a null section. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate if (ckp->ckp_secs == 0 || ckp->ckp_secp->fcfs_type != FCF_SECT_NONE || 3197c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_entsize != 0 || ckp->ckp_secp->fcfs_size != 0) { 3207c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section 0 is not of the " 3217c478bd9Sstevel@tonic-gate "appropriate size and/or attributes (SECT_NONE)\n")); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (ckp->ckp_modp == NULL) { 3257c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 3267c478bd9Sstevel@tonic-gate "no module section found in file\n")); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate return (0); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate static void 3337c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(fmd_ckpt_t *ckp) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate if (ckp->ckp_buf != NULL) 3367c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, ckp->ckp_size); 3377c478bd9Sstevel@tonic-gate if (ckp->ckp_fd >= 0) 3387c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * fmd_ckpt_error() is used as a wrapper around fmd_error() for ckpt routines. 3437c478bd9Sstevel@tonic-gate * It calls fmd_module_unlock() on behalf of its caller, logs the error, and 3447c478bd9Sstevel@tonic-gate * then aborts the API call and the surrounding module entry point by doing an 3457c478bd9Sstevel@tonic-gate * fmd_module_abort(), which longjmps to the place where we entered the module. 3467c478bd9Sstevel@tonic-gate * Depending on the type of error and conf settings, we will reset or fail. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 3497c478bd9Sstevel@tonic-gate static void 3507c478bd9Sstevel@tonic-gate fmd_ckpt_error(fmd_ckpt_t *ckp, int err, const char *format, ...) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate fmd_module_t *mp = ckp->ckp_mp; 3537c478bd9Sstevel@tonic-gate va_list ap; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate va_start(ap, format); 3567c478bd9Sstevel@tonic-gate fmd_verror(err, format, ap); 3577c478bd9Sstevel@tonic-gate va_end(ap); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (fmd_module_locked(mp)) 3607c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(ckp); 3637c478bd9Sstevel@tonic-gate fmd_module_abort(mp, err); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate static fcf_secidx_t 3677c478bd9Sstevel@tonic-gate fmd_ckpt_section(fmd_ckpt_t *ckp, const void *data, uint_t type, uint64_t size) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate const fmd_ckpt_desc_t *dp; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate ASSERT(type < sizeof (_fmd_ckpt_sections) / sizeof (fmd_ckpt_desc_t)); 3727c478bd9Sstevel@tonic-gate dp = &_fmd_ckpt_sections[type]; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *) 3757c478bd9Sstevel@tonic-gate P2ROUNDUP((uintptr_t)ckp->ckp_ptr, dp->secd_align); 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_type = type; 3787c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_align = dp->secd_align; 3797c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_flags = 0; 3807c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_entsize = dp->secd_entsize; 3817c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_offset = (size_t)(ckp->ckp_ptr - ckp->ckp_buf); 3827c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_size = size; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * If the data pointer is non-NULL, copy the data to our buffer; else 3867c478bd9Sstevel@tonic-gate * the caller is responsible for doing so and updating ckp->ckp_ptr. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (data != NULL) { 3897c478bd9Sstevel@tonic-gate bcopy(data, ckp->ckp_ptr, size); 3907c478bd9Sstevel@tonic-gate ckp->ckp_ptr += size; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate ckp->ckp_secp++; 3947c478bd9Sstevel@tonic-gate return (ckp->ckp_secs++); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate static fcf_stridx_t 3987c478bd9Sstevel@tonic-gate fmd_ckpt_string(fmd_ckpt_t *ckp, const char *s) 3997c478bd9Sstevel@tonic-gate { 4007c478bd9Sstevel@tonic-gate fcf_stridx_t idx = (fcf_stridx_t)(ckp->ckp_strp - ckp->ckp_strs); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate (void) strcpy(ckp->ckp_strp, s); 4037c478bd9Sstevel@tonic-gate ckp->ckp_strp += strlen(s) + 1; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate return (idx); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate static int 4097c478bd9Sstevel@tonic-gate fmd_ckpt_alloc(fmd_ckpt_t *ckp, uint64_t gen) 4107c478bd9Sstevel@tonic-gate { 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * We've added up all the sections by now: add two more for SECT_NONE 4137c478bd9Sstevel@tonic-gate * and SECT_STRTAB, and add the size of the section header table and 4147c478bd9Sstevel@tonic-gate * string table to the total size. We know that the fcf_hdr_t is 4157c478bd9Sstevel@tonic-gate * aligned so that that fcf_sec_t's can follow it, and that fcf_sec_t 4167c478bd9Sstevel@tonic-gate * is aligned so that any section can follow it, so no extra padding 4177c478bd9Sstevel@tonic-gate * bytes need to be allocated between any of these items. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate ckp->ckp_secs += 2; /* for FCF_SECT_NONE and FCF_SECT_STRTAB */ 4207c478bd9Sstevel@tonic-gate ckp->ckp_size += sizeof (fcf_sec_t) * ckp->ckp_secs; 4217c478bd9Sstevel@tonic-gate ckp->ckp_size += ckp->ckp_strn; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "alloc fcf buf size %u", ckp->ckp_size)); 4247c478bd9Sstevel@tonic-gate ckp->ckp_buf = fmd_zalloc(ckp->ckp_size, FMD_NOSLEEP); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate if (ckp->ckp_buf == NULL) 4277c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate ckp->ckp_hdr = (void *)ckp->ckp_buf; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG0] = FCF_MAG_MAG0; 4327c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG1] = FCF_MAG_MAG1; 4337c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG2] = FCF_MAG_MAG2; 4347c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG3] = FCF_MAG_MAG3; 4357c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MODEL] = FCF_MODEL_NATIVE; 4367c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_ENCODING] = FCF_ENCODE_NATIVE; 4377c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION] = FCF_VERSION; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_hdrsize = sizeof (fcf_hdr_t); 4407c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secsize = sizeof (fcf_sec_t); 4417c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secnum = ckp->ckp_secs; 4427c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff = sizeof (fcf_hdr_t); 4437c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_filesz = ckp->ckp_size; 4447c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_cgen = gen; 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate ckp->ckp_secs = 0; /* reset section counter for second pass */ 4477c478bd9Sstevel@tonic-gate ckp->ckp_secp = (void *)(ckp->ckp_buf + sizeof (fcf_hdr_t)); 4487c478bd9Sstevel@tonic-gate ckp->ckp_strs = (char *)ckp->ckp_buf + ckp->ckp_size - ckp->ckp_strn; 4497c478bd9Sstevel@tonic-gate ckp->ckp_strp = ckp->ckp_strs + 1; /* use first byte as \0 */ 4507c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *)(ckp->ckp_secp + ckp->ckp_hdr->fcfh_secnum); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, NULL, FCF_SECT_NONE, 0); 4537c478bd9Sstevel@tonic-gate return (0); 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate static int 4577c478bd9Sstevel@tonic-gate fmd_ckpt_commit(fmd_ckpt_t *ckp) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate fcf_sec_t *secbase = (void *)(ckp->ckp_buf + sizeof (fcf_hdr_t)); 4607c478bd9Sstevel@tonic-gate size_t stroff = ckp->ckp_size - ckp->ckp_strn; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * Before committing the checkpoint, we assert that fmd_ckpt_t's sizes 4647c478bd9Sstevel@tonic-gate * and current pointer locations all add up appropriately. Any ASSERTs 4657c478bd9Sstevel@tonic-gate * which trip here likely indicate an inconsistency in the code for the 4667c478bd9Sstevel@tonic-gate * reservation pass and the buffer update pass of the FCF subroutines. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate ASSERT((size_t)(ckp->ckp_ptr - ckp->ckp_buf) == stroff); 4697c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, NULL, FCF_SECT_STRTAB, ckp->ckp_strn); 4707c478bd9Sstevel@tonic-gate ckp->ckp_ptr += ckp->ckp_strn; /* string table is already filled in */ 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_secs == ckp->ckp_hdr->fcfh_secnum); 4737c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_secp == secbase + ckp->ckp_hdr->fcfh_secnum); 4747c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_ptr == ckp->ckp_buf + ckp->ckp_hdr->fcfh_filesz); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (write(ckp->ckp_fd, ckp->ckp_buf, ckp->ckp_size) != ckp->ckp_size || 4777c478bd9Sstevel@tonic-gate fsync(ckp->ckp_fd) != 0 || close(ckp->ckp_fd) != 0) 4787c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate ckp->ckp_fd = -1; /* fd is now closed */ 4817c478bd9Sstevel@tonic-gate return (rename(ckp->ckp_src, ckp->ckp_dst) != 0); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate static void 4857c478bd9Sstevel@tonic-gate fmd_ckpt_resv(fmd_ckpt_t *ckp, size_t size, size_t align) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate if (size != 0) { 4887c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, align) + size; 4897c478bd9Sstevel@tonic-gate ckp->ckp_secs++; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate static void 4947c478bd9Sstevel@tonic-gate fmd_ckpt_resv_buf(fmd_buf_t *bp, fmd_ckpt_t *ckp) 4957c478bd9Sstevel@tonic-gate { 4967c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, _MAX_ALIGNMENT) + bp->buf_size; 4977c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(bp->buf_name) + 1; 4987c478bd9Sstevel@tonic-gate ckp->ckp_secs++; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate static void 5027c478bd9Sstevel@tonic-gate fmd_ckpt_save_buf(fmd_buf_t *bp, fmd_ckpt_t *ckp) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate fcf_buf_t *fcfb = ckp->ckp_arg; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate fcfb->fcfb_name = fmd_ckpt_string(ckp, bp->buf_name); 5077c478bd9Sstevel@tonic-gate fcfb->fcfb_data = fmd_ckpt_section(ckp, 5087c478bd9Sstevel@tonic-gate bp->buf_data, FCF_SECT_BUFFER, bp->buf_size); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate ckp->ckp_arg = fcfb + 1; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate static void 5147c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(fmd_ckpt_t *ckp, fmd_event_t *e) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate fcf_event_t *fcfe = (void *)ckp->ckp_ptr; 5177c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 5187c478bd9Sstevel@tonic-gate fmd_log_t *lp = ep->ev_log; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate fcfe->fcfe_todsec = ep->ev_time.ftv_sec; 5217c478bd9Sstevel@tonic-gate fcfe->fcfe_todnsec = ep->ev_time.ftv_nsec; 5227c478bd9Sstevel@tonic-gate fcfe->fcfe_major = lp ? major(lp->log_stat.st_dev) : -1U; 5237c478bd9Sstevel@tonic-gate fcfe->fcfe_minor = lp ? minor(lp->log_stat.st_dev) : -1U; 5247c478bd9Sstevel@tonic-gate fcfe->fcfe_inode = lp ? lp->log_stat.st_ino : -1ULL; 5257c478bd9Sstevel@tonic-gate fcfe->fcfe_offset = ep->ev_off; 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate ckp->ckp_ptr += sizeof (fcf_event_t); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate static void 5317c478bd9Sstevel@tonic-gate fmd_ckpt_save_nvlist(fmd_ckpt_t *ckp, nvlist_t *nvl) 5327c478bd9Sstevel@tonic-gate { 5337c478bd9Sstevel@tonic-gate fcf_nvl_t *fcfn = (void *)ckp->ckp_ptr; 5347c478bd9Sstevel@tonic-gate char *nvbuf = (char *)ckp->ckp_ptr + sizeof (fcf_nvl_t); 5357c478bd9Sstevel@tonic-gate size_t nvsize = 0; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate (void) nvlist_size(nvl, &nvsize, NV_ENCODE_NATIVE); 5387c478bd9Sstevel@tonic-gate fcfn->fcfn_size = (uint64_t)nvsize; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate (void) nvlist_pack(nvl, &nvbuf, &nvsize, NV_ENCODE_NATIVE, 0); 5417c478bd9Sstevel@tonic-gate ckp->ckp_ptr += sizeof (fcf_nvl_t) + nvsize; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *) 5447c478bd9Sstevel@tonic-gate P2ROUNDUP((uintptr_t)ckp->ckp_ptr, sizeof (uint64_t)); 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate static void 5487c478bd9Sstevel@tonic-gate fmd_ckpt_resv_serd(fmd_serd_eng_t *sgp, fmd_ckpt_t *ckp) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, 5517c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * sgp->sg_count, sizeof (uint64_t)); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(sgp->sg_name) + 1; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate static void 5577c478bd9Sstevel@tonic-gate fmd_ckpt_save_serd(fmd_serd_eng_t *sgp, fmd_ckpt_t *ckp) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate fcf_serd_t *fcfd = ckp->ckp_arg; 5607c478bd9Sstevel@tonic-gate fcf_secidx_t evsec = FCF_SECT_NONE; 5617c478bd9Sstevel@tonic-gate fmd_serd_elem_t *sep; 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate if (sgp->sg_count != 0) { 5647c478bd9Sstevel@tonic-gate evsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 5657c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * sgp->sg_count); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate for (sep = fmd_list_next(&sgp->sg_list); 5687c478bd9Sstevel@tonic-gate sep != NULL; sep = fmd_list_next(sep)) 5697c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, sep->se_event); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate fcfd->fcfd_name = fmd_ckpt_string(ckp, sgp->sg_name); 5737c478bd9Sstevel@tonic-gate fcfd->fcfd_events = evsec; 5747c478bd9Sstevel@tonic-gate fcfd->fcfd_pad = 0; 5757c478bd9Sstevel@tonic-gate fcfd->fcfd_n = sgp->sg_n; 5767c478bd9Sstevel@tonic-gate fcfd->fcfd_t = sgp->sg_t; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate ckp->ckp_arg = fcfd + 1; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate static void 5827c478bd9Sstevel@tonic-gate fmd_ckpt_resv_case(fmd_ckpt_t *ckp, fmd_case_t *cp) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 5857c478bd9Sstevel@tonic-gate fmd_case_susp_t *cis; 5867c478bd9Sstevel@tonic-gate uint_t n; 5877c478bd9Sstevel@tonic-gate 588d9638e54Smws if (cip->ci_xprt != NULL) 589d9638e54Smws return; /* do not checkpoint cases from remote transports */ 590d9638e54Smws 5917c478bd9Sstevel@tonic-gate n = fmd_buf_hash_count(&cip->ci_bufs); 5927c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&cip->ci_bufs, (fmd_buf_f *)fmd_ckpt_resv_buf, ckp); 5937c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_buf_t) * n, sizeof (uint32_t)); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (cip->ci_principal != NULL) 5967c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_event_t), sizeof (uint64_t)); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, 5997c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * cip->ci_nitems, sizeof (uint64_t)); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if (cip->ci_nsuspects != 0) 6027c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, sizeof (uint64_t)); 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate cip->ci_nvsz = 0; /* compute size of packed suspect nvlist array */ 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) { 6077c478bd9Sstevel@tonic-gate size_t nvsize = 0; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate (void) nvlist_size(cis->cis_nvl, &nvsize, NV_ENCODE_NATIVE); 6107c478bd9Sstevel@tonic-gate cip->ci_nvsz += sizeof (fcf_nvl_t) + nvsize; 6117c478bd9Sstevel@tonic-gate cip->ci_nvsz = P2ROUNDUP(cip->ci_nvsz, sizeof (uint64_t)); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, cip->ci_nvsz, sizeof (uint64_t)); 6157c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_case_t), sizeof (uint32_t)); 6167c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(cip->ci_uuid) + 1; 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate static void 6207c478bd9Sstevel@tonic-gate fmd_ckpt_save_case(fmd_ckpt_t *ckp, fmd_case_t *cp) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate fmd_case_item_t *cit; 6257c478bd9Sstevel@tonic-gate fmd_case_susp_t *cis; 6267c478bd9Sstevel@tonic-gate fcf_case_t fcfc; 6277c478bd9Sstevel@tonic-gate uint_t n; 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate fcf_secidx_t bufsec = FCF_SECIDX_NONE; 6307c478bd9Sstevel@tonic-gate fcf_secidx_t evsec = FCF_SECIDX_NONE; 6317c478bd9Sstevel@tonic-gate fcf_secidx_t nvsec = FCF_SECIDX_NONE; 6327c478bd9Sstevel@tonic-gate fcf_secidx_t prsec = FCF_SECIDX_NONE; 6337c478bd9Sstevel@tonic-gate 634d9638e54Smws if (cip->ci_xprt != NULL) 635d9638e54Smws return; /* do not checkpoint cases from remote transports */ 636d9638e54Smws 6377c478bd9Sstevel@tonic-gate if ((n = fmd_buf_hash_count(&cip->ci_bufs)) != 0) { 6387c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_buf_t) * n; 6397c478bd9Sstevel@tonic-gate fcf_buf_t *bufs = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&cip->ci_bufs, 6427c478bd9Sstevel@tonic-gate (fmd_buf_f *)fmd_ckpt_save_buf, ckp); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate bufsec = fmd_ckpt_section(ckp, bufs, FCF_SECT_BUFS, size); 6457c478bd9Sstevel@tonic-gate fmd_free(bufs, size); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if (cip->ci_principal != NULL) { 6497c478bd9Sstevel@tonic-gate prsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 6507c478bd9Sstevel@tonic-gate sizeof (fcf_event_t)); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, cip->ci_principal); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate if (cip->ci_nitems != 0) { 6567c478bd9Sstevel@tonic-gate evsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 6577c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * cip->ci_nitems); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) 6607c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, cit->cit_event); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if (cip->ci_nsuspects != 0) { 6647c478bd9Sstevel@tonic-gate nvsec = fmd_ckpt_section(ckp, NULL, 6657c478bd9Sstevel@tonic-gate FCF_SECT_NVLISTS, cip->ci_nvsz); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) 6687c478bd9Sstevel@tonic-gate fmd_ckpt_save_nvlist(ckp, cis->cis_nvl); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate fcfc.fcfc_uuid = fmd_ckpt_string(ckp, cip->ci_uuid); 6727c478bd9Sstevel@tonic-gate fcfc.fcfc_bufs = bufsec; 6737c478bd9Sstevel@tonic-gate fcfc.fcfc_principal = prsec; 6747c478bd9Sstevel@tonic-gate fcfc.fcfc_events = evsec; 6757c478bd9Sstevel@tonic-gate fcfc.fcfc_suspects = nvsec; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate switch (cip->ci_state) { 6787c478bd9Sstevel@tonic-gate case FMD_CASE_UNSOLVED: 6797c478bd9Sstevel@tonic-gate fcfc.fcfc_state = FCF_CASE_UNSOLVED; 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate case FMD_CASE_SOLVED: 6827c478bd9Sstevel@tonic-gate fcfc.fcfc_state = FCF_CASE_SOLVED; 6837c478bd9Sstevel@tonic-gate break; 684d9638e54Smws case FMD_CASE_CLOSE_WAIT: 685d9638e54Smws fcfc.fcfc_state = FCF_CASE_CLOSE_WAIT; 6867c478bd9Sstevel@tonic-gate break; 6877c478bd9Sstevel@tonic-gate default: 6887c478bd9Sstevel@tonic-gate fmd_panic("case %p (%s) has invalid state %u", 6897c478bd9Sstevel@tonic-gate (void *)cp, cip->ci_uuid, cip->ci_state); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, &fcfc, FCF_SECT_CASE, sizeof (fcf_case_t)); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate static void 6967c478bd9Sstevel@tonic-gate fmd_ckpt_resv_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate fmd_case_t *cp; 6997c478bd9Sstevel@tonic-gate uint_t n; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); cp; cp = fmd_list_next(cp)) 7027c478bd9Sstevel@tonic-gate fmd_ckpt_resv_case(ckp, cp); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate n = fmd_serd_hash_count(&mp->mod_serds); 7057c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 7067c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_ckpt_resv_serd, ckp); 7077c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_serd_t) * n, sizeof (uint64_t)); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate n = fmd_buf_hash_count(&mp->mod_bufs); 7107c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&mp->mod_bufs, (fmd_buf_f *)fmd_ckpt_resv_buf, ckp); 7117c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_buf_t) * n, sizeof (uint32_t)); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_module_t), sizeof (uint32_t)); 7147c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_name) + 1; 7157c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_path) + 1; 7167c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_info->fmdi_desc) + 1; 7177c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_info->fmdi_vers) + 1; 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate static void 7217c478bd9Sstevel@tonic-gate fmd_ckpt_save_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 7227c478bd9Sstevel@tonic-gate { 7237c478bd9Sstevel@tonic-gate fcf_secidx_t bufsec = FCF_SECIDX_NONE; 7247c478bd9Sstevel@tonic-gate fcf_module_t fcfm; 7257c478bd9Sstevel@tonic-gate fmd_case_t *cp; 7267c478bd9Sstevel@tonic-gate uint_t n; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); cp; cp = fmd_list_next(cp)) 7297c478bd9Sstevel@tonic-gate fmd_ckpt_save_case(ckp, cp); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate if ((n = fmd_serd_hash_count(&mp->mod_serds)) != 0) { 7327c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_serd_t) * n; 7337c478bd9Sstevel@tonic-gate fcf_serd_t *serds = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 7367c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_ckpt_save_serd, ckp); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, serds, FCF_SECT_SERD, size); 7397c478bd9Sstevel@tonic-gate fmd_free(serds, size); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate if ((n = fmd_buf_hash_count(&mp->mod_bufs)) != 0) { 7437c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_buf_t) * n; 7447c478bd9Sstevel@tonic-gate fcf_buf_t *bufs = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&mp->mod_bufs, 7477c478bd9Sstevel@tonic-gate (fmd_buf_f *)fmd_ckpt_save_buf, ckp); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate bufsec = fmd_ckpt_section(ckp, bufs, FCF_SECT_BUFS, size); 7507c478bd9Sstevel@tonic-gate fmd_free(bufs, size); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate fcfm.fcfm_name = fmd_ckpt_string(ckp, mp->mod_name); 7547c478bd9Sstevel@tonic-gate fcfm.fcfm_path = fmd_ckpt_string(ckp, mp->mod_path); 7557c478bd9Sstevel@tonic-gate fcfm.fcfm_desc = fmd_ckpt_string(ckp, mp->mod_info->fmdi_desc); 7567c478bd9Sstevel@tonic-gate fcfm.fcfm_vers = fmd_ckpt_string(ckp, mp->mod_info->fmdi_vers); 7577c478bd9Sstevel@tonic-gate fcfm.fcfm_bufs = bufsec; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, &fcfm, 7607c478bd9Sstevel@tonic-gate FCF_SECT_MODULE, sizeof (fcf_module_t)); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate void 7647c478bd9Sstevel@tonic-gate fmd_ckpt_save(fmd_module_t *mp) 7657c478bd9Sstevel@tonic-gate { 7667c478bd9Sstevel@tonic-gate struct stat64 st; 7677c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 7687c478bd9Sstevel@tonic-gate mode_t dirmode; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate hrtime_t now = gethrtime(); 7717c478bd9Sstevel@tonic-gate fmd_ckpt_t ckp; 7727c478bd9Sstevel@tonic-gate int err; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate ASSERT(fmd_module_locked(mp)); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * If checkpointing is disabled for the module, just return. We must 7787c478bd9Sstevel@tonic-gate * commit the module state anyway to transition pending log events. 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_ckpt_save.fmds_value.bool == FMD_B_FALSE) { 7817c478bd9Sstevel@tonic-gate fmd_module_commit(mp); 7827c478bd9Sstevel@tonic-gate return; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if (!(mp->mod_flags & (FMD_MOD_MDIRTY | FMD_MOD_CDIRTY))) 7867c478bd9Sstevel@tonic-gate return; /* no checkpoint is necessary for this module */ 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt save begin %s %llu", 7897c478bd9Sstevel@tonic-gate mp->mod_name, mp->mod_gen + 1)); 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * If the per-module checkpoint directory isn't found or isn't of type 7937c478bd9Sstevel@tonic-gate * directory, move aside whatever is there (if anything) and attempt 7947c478bd9Sstevel@tonic-gate * to mkdir(2) a new module checkpoint directory. If this fails, we 7957c478bd9Sstevel@tonic-gate * have no choice but to abort the checkpoint and try again later. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate if (stat64(mp->mod_ckpt, &st) != 0 || !S_ISDIR(st.st_mode)) { 7987c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s-", mp->mod_ckpt); 7997c478bd9Sstevel@tonic-gate (void) rename(mp->mod_ckpt, path); 8007c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.dirmode", &dirmode); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if (mkdir(mp->mod_ckpt, dirmode) != 0) { 8037c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_MKDIR, 8047c478bd9Sstevel@tonic-gate "failed to mkdir %s", mp->mod_ckpt); 8057c478bd9Sstevel@tonic-gate return; /* return without clearing dirty bits */ 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Create a temporary file to write out the checkpoint into, and create 8117c478bd9Sstevel@tonic-gate * a fmd_ckpt_t structure to manage construction of the checkpoint. We 8127c478bd9Sstevel@tonic-gate * then figure out how much space will be required, and allocate it. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate if (fmd_ckpt_create(&ckp, mp) == -1) { 8157c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_CREATE, "failed to create %s", ckp.ckp_src); 8167c478bd9Sstevel@tonic-gate return; 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate fmd_ckpt_resv_module(&ckp, mp); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate if (fmd_ckpt_alloc(&ckp, mp->mod_gen + 1) != 0) { 8227c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_NOMEM, "failed to build %s", ckp.ckp_src); 8237c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 8247c478bd9Sstevel@tonic-gate return; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Fill in the checkpoint content, write it to disk, sync it, and then 8297c478bd9Sstevel@tonic-gate * atomically rename it to the destination path. If this fails, we 8307c478bd9Sstevel@tonic-gate * have no choice but to leave all our dirty bits set and return. 8317c478bd9Sstevel@tonic-gate */ 8327c478bd9Sstevel@tonic-gate fmd_ckpt_save_module(&ckp, mp); 8337c478bd9Sstevel@tonic-gate err = fmd_ckpt_commit(&ckp); 8347c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (err != 0) { 8377c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_COMMIT, "failed to commit %s", ckp.ckp_dst); 8387c478bd9Sstevel@tonic-gate return; /* return without clearing dirty bits */ 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate fmd_module_commit(mp); 8427c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt save end %s", mp->mod_name)); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate mp->mod_stats->ms_ckpt_cnt.fmds_value.ui64++; 8457c478bd9Sstevel@tonic-gate mp->mod_stats->ms_ckpt_time.fmds_value.ui64 += gethrtime() - now; 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_CKPT, "saved checkpoint of %s (%llu)\n", 8487c478bd9Sstevel@tonic-gate mp->mod_name, mp->mod_gen); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Utility function to retrieve a pointer to a section's header and verify that 8537c478bd9Sstevel@tonic-gate * it is of the expected type or it is a FCF_SECT_NONE reference. 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate static const fcf_sec_t * 8567c478bd9Sstevel@tonic-gate fmd_ckpt_secptr(fmd_ckpt_t *ckp, fcf_secidx_t sid, uint_t type) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate const fcf_sec_t *sp = (void *)(ckp->ckp_buf + 8597c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * sid); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate return (sid < ckp->ckp_secs && (sp->fcfs_type == type || 8627c478bd9Sstevel@tonic-gate sp->fcfs_type == FCF_SECT_NONE) ? sp : NULL); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * Utility function to retrieve the data pointer for a particular section. The 8677c478bd9Sstevel@tonic-gate * validity of the header values has already been checked by fmd_ckpt_open(). 8687c478bd9Sstevel@tonic-gate */ 8697c478bd9Sstevel@tonic-gate static const void * 8707c478bd9Sstevel@tonic-gate fmd_ckpt_dataptr(fmd_ckpt_t *ckp, const fcf_sec_t *sp) 8717c478bd9Sstevel@tonic-gate { 8727c478bd9Sstevel@tonic-gate return (ckp->ckp_buf + sp->fcfs_offset); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * Utility function to retrieve the end of the data region for a particular 8777c478bd9Sstevel@tonic-gate * section. The validity of this value has been confirmed by fmd_ckpt_open(). 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate static const void * 8807c478bd9Sstevel@tonic-gate fmd_ckpt_datalim(fmd_ckpt_t *ckp, const fcf_sec_t *sp) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate return (ckp->ckp_buf + sp->fcfs_offset + sp->fcfs_size); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * Utility function to retrieve a string pointer (fcf_stridx_t). If the string 8877c478bd9Sstevel@tonic-gate * index is valid, the string data is returned; otherwise 'defstr' is returned. 8887c478bd9Sstevel@tonic-gate */ 8897c478bd9Sstevel@tonic-gate static const char * 8907c478bd9Sstevel@tonic-gate fmd_ckpt_strptr(fmd_ckpt_t *ckp, fcf_stridx_t sid, const char *defstr) 8917c478bd9Sstevel@tonic-gate { 8927c478bd9Sstevel@tonic-gate return (sid < ckp->ckp_strn ? ckp->ckp_strs + sid : defstr); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate static void 8967c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(fmd_ckpt_t *ckp, fcf_secidx_t sid, 8977c478bd9Sstevel@tonic-gate void (*func)(void *, fmd_event_t *), void *arg) 8987c478bd9Sstevel@tonic-gate { 8997c478bd9Sstevel@tonic-gate const fcf_event_t *fcfe; 9007c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 9017c478bd9Sstevel@tonic-gate fmd_timeval_t ftv; 9027c478bd9Sstevel@tonic-gate fmd_log_t *lp, *errlp; 9037c478bd9Sstevel@tonic-gate uint_t i, n; 9047c478bd9Sstevel@tonic-gate uint32_t e_maj, e_min; 9057c478bd9Sstevel@tonic-gate uint64_t e_ino; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_EVENTS)) == NULL) { 9087c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 9097c478bd9Sstevel@tonic-gate "invalid link to section %u: expected events\n", sid); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if (sp->fcfs_size == 0) 9137c478bd9Sstevel@tonic-gate return; /* empty events section or type none */ 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate fcfe = fmd_ckpt_dataptr(ckp, sp); 9167c478bd9Sstevel@tonic-gate n = sp->fcfs_size / sp->fcfs_entsize; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * Hold the reader lock on log pointers to block log rotation during 9207c478bd9Sstevel@tonic-gate * the section restore so that we can safely insert refs to d_errlog. 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&fmd.d_log_lock); 9237c478bd9Sstevel@tonic-gate errlp = fmd.d_errlog; 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate e_maj = major(errlp->log_stat.st_dev); 9267c478bd9Sstevel@tonic-gate e_min = minor(errlp->log_stat.st_dev); 9277c478bd9Sstevel@tonic-gate e_ino = errlp->log_stat.st_ino; 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 93047911a7dScy152378 fmd_event_t *ep; 93147911a7dScy152378 9327c478bd9Sstevel@tonic-gate ftv.ftv_sec = fcfe->fcfe_todsec; 9337c478bd9Sstevel@tonic-gate ftv.ftv_nsec = fcfe->fcfe_todnsec; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate if (e_ino == fcfe->fcfe_inode && 9367c478bd9Sstevel@tonic-gate e_maj == fcfe->fcfe_major && 9377c478bd9Sstevel@tonic-gate e_min == fcfe->fcfe_minor) 9387c478bd9Sstevel@tonic-gate lp = errlp; 9397c478bd9Sstevel@tonic-gate else 9407c478bd9Sstevel@tonic-gate lp = NULL; 9417c478bd9Sstevel@tonic-gate 94247911a7dScy152378 ep = fmd_event_recreate(FMD_EVT_PROTOCOL, 94347911a7dScy152378 &ftv, NULL, NULL, lp, fcfe->fcfe_offset, 0); 94447911a7dScy152378 fmd_event_hold(ep); 94547911a7dScy152378 func(arg, ep); 94647911a7dScy152378 fmd_event_rele(ep); 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate fcfe = (fcf_event_t *)((uintptr_t)fcfe + sp->fcfs_entsize); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&fmd.d_log_lock); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 954d9638e54Smws static int 9557c478bd9Sstevel@tonic-gate fmd_ckpt_restore_suspects(fmd_ckpt_t *ckp, fmd_case_t *cp, fcf_secidx_t sid) 9567c478bd9Sstevel@tonic-gate { 9577c478bd9Sstevel@tonic-gate const fcf_nvl_t *fcfn, *endn; 9587c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 9597c478bd9Sstevel@tonic-gate nvlist_t *nvl; 9607c478bd9Sstevel@tonic-gate int err, i; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_NVLISTS)) == NULL) { 9637c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 9647c478bd9Sstevel@tonic-gate "invalid link to section %u: expected nvlists\n", sid); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate fcfn = fmd_ckpt_dataptr(ckp, sp); 9687c478bd9Sstevel@tonic-gate endn = fmd_ckpt_datalim(ckp, sp); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate for (i = 0; fcfn < endn; i++) { 9717c478bd9Sstevel@tonic-gate char *data = (char *)fcfn + sp->fcfs_entsize; 9727c478bd9Sstevel@tonic-gate size_t size = (size_t)fcfn->fcfn_size; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (fcfn->fcfn_size > (size_t)((char *)endn - data)) { 9757c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "nvlist %u [%d] " 9767c478bd9Sstevel@tonic-gate "size %u exceeds buffer\n", sid, i, size); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate if ((err = nvlist_xunpack(data, size, &nvl, &fmd.d_nva)) != 0) { 9807c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "failed to " 9817c478bd9Sstevel@tonic-gate "unpack nvlist %u [%d]: %s\n", sid, i, 9827c478bd9Sstevel@tonic-gate fmd_strerror(err)); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate fmd_case_insert_suspect(cp, nvl); 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate size = sp->fcfs_entsize + fcfn->fcfn_size; 9887c478bd9Sstevel@tonic-gate size = P2ROUNDUP(size, sizeof (uint64_t)); 9897c478bd9Sstevel@tonic-gate fcfn = (fcf_nvl_t *)((uintptr_t)fcfn + size); 9907c478bd9Sstevel@tonic-gate } 991d9638e54Smws 992d9638e54Smws return (i); 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate static void 9967c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(fmd_ckpt_t *ckp, fmd_module_t *mp, 9977c478bd9Sstevel@tonic-gate fmd_case_t *cp, fcf_secidx_t sid) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate const fcf_sec_t *sp, *dsp; 10007c478bd9Sstevel@tonic-gate const fcf_buf_t *fcfb; 10017c478bd9Sstevel@tonic-gate uint_t i, n; 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_BUFS)) == NULL) { 10047c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 10057c478bd9Sstevel@tonic-gate "invalid link to section %u: expected bufs\n", sid); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate if (sp->fcfs_size == 0) 10097c478bd9Sstevel@tonic-gate return; /* empty events section or type none */ 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate fcfb = fmd_ckpt_dataptr(ckp, sp); 10127c478bd9Sstevel@tonic-gate n = sp->fcfs_size / sp->fcfs_entsize; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 10157c478bd9Sstevel@tonic-gate dsp = fmd_ckpt_secptr(ckp, fcfb->fcfb_data, FCF_SECT_BUFFER); 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate if (dsp == NULL) { 10187c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "invalid %u " 10197c478bd9Sstevel@tonic-gate "buffer link %u\n", sid, fcfb->fcfb_data); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate fmd_buf_write((fmd_hdl_t *)mp, cp, 10237c478bd9Sstevel@tonic-gate fmd_ckpt_strptr(ckp, fcfb->fcfb_name, "<CORRUPT>"), 10247c478bd9Sstevel@tonic-gate ckp->ckp_buf + dsp->fcfs_offset, dsp->fcfs_size); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate fcfb = (fcf_buf_t *)((uintptr_t)fcfb + sp->fcfs_entsize); 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate static void 10317c478bd9Sstevel@tonic-gate fmd_ckpt_restore_case(fmd_ckpt_t *ckp, fmd_module_t *mp, const fcf_sec_t *sp) 10327c478bd9Sstevel@tonic-gate { 10337c478bd9Sstevel@tonic-gate const fcf_case_t *fcfc = fmd_ckpt_dataptr(ckp, sp); 10347c478bd9Sstevel@tonic-gate const char *uuid = fmd_ckpt_strptr(ckp, fcfc->fcfc_uuid, NULL); 10357c478bd9Sstevel@tonic-gate fmd_case_t *cp; 1036d9638e54Smws int n; 10377c478bd9Sstevel@tonic-gate 1038d9638e54Smws if (uuid == NULL || fcfc->fcfc_state > FCF_CASE_CLOSE_WAIT) { 10397c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "corrupt %u case uuid " 10407c478bd9Sstevel@tonic-gate "and/or state\n", (uint_t)(sp - ckp->ckp_secp)); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 10447c478bd9Sstevel@tonic-gate 1045d9638e54Smws if ((cp = fmd_case_recreate(mp, NULL, 1046567cc2e6Sstephh fcfc->fcfc_state != FCF_CASE_UNSOLVED ? FCF_CASE_SOLVED : 1047d9638e54Smws FMD_CASE_UNSOLVED, uuid, NULL)) == NULL) { 10487c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 10497c478bd9Sstevel@tonic-gate "duplicate case uuid: %s\n", uuid); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfc->fcfc_principal, 10537c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_case_insert_principal, cp); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfc->fcfc_events, 10567c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_case_insert_event, cp); 10577c478bd9Sstevel@tonic-gate 1058c7d6cfd6SStephen Hanson /* 1059c7d6cfd6SStephen Hanson * Once solved, treat suspects from resource cache as master copy. 1060*cbf75e67SStephen Hanson * 1061*cbf75e67SStephen Hanson * If !fmd.d_running, this module must be a builtin, and so we don't 1062*cbf75e67SStephen Hanson * want to restore suspects or call fmd_case_transition_update() at this 1063*cbf75e67SStephen Hanson * stage. The suspects will be added later from the resource cache. 1064*cbf75e67SStephen Hanson * Calling fmd_case_transition("SOLVED") is OK here as the state is 1065*cbf75e67SStephen Hanson * already solved, so all it does is update the case flags. 1066c7d6cfd6SStephen Hanson */ 1067*cbf75e67SStephen Hanson if (fmd.d_running && (n = ((fmd_case_impl_t *)cp)->ci_nsuspects) == 0) 1068d9638e54Smws n = fmd_ckpt_restore_suspects(ckp, cp, fcfc->fcfc_suspects); 10697c478bd9Sstevel@tonic-gate 1070*cbf75e67SStephen Hanson if (!fmd.d_running) 1071*cbf75e67SStephen Hanson fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1072*cbf75e67SStephen Hanson else if (fcfc->fcfc_state == FCF_CASE_SOLVED) 10730b9e3e76Smws fmd_case_transition_update(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1074d9638e54Smws else if (fcfc->fcfc_state == FCF_CASE_CLOSE_WAIT && n != 0) 1075d9638e54Smws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_SOLVED); 1076d9638e54Smws else if (fcfc->fcfc_state == FCF_CASE_CLOSE_WAIT && n == 0) 1077d9638e54Smws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, 0); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 10807c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(ckp, mp, cp, fcfc->fcfc_bufs); 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate 10837c478bd9Sstevel@tonic-gate static void 10847c478bd9Sstevel@tonic-gate fmd_ckpt_restore_serd(fmd_ckpt_t *ckp, fmd_module_t *mp, const fcf_sec_t *sp) 10857c478bd9Sstevel@tonic-gate { 10867c478bd9Sstevel@tonic-gate const fcf_serd_t *fcfd = fmd_ckpt_dataptr(ckp, sp); 10877c478bd9Sstevel@tonic-gate uint_t i, n = sp->fcfs_size / sp->fcfs_entsize; 10887c478bd9Sstevel@tonic-gate const fcf_sec_t *esp; 10897c478bd9Sstevel@tonic-gate const char *s; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 10927c478bd9Sstevel@tonic-gate esp = fmd_ckpt_secptr(ckp, fcfd->fcfd_events, FCF_SECT_EVENTS); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate if (esp == NULL) { 10957c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 10967c478bd9Sstevel@tonic-gate "invalid events link %u\n", fcfd->fcfd_events); 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate if ((s = fmd_ckpt_strptr(ckp, fcfd->fcfd_name, NULL)) == NULL) { 11007c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 11017c478bd9Sstevel@tonic-gate "serd name %u is corrupt\n", fcfd->fcfd_name); 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate fmd_serd_create((fmd_hdl_t *)mp, s, fcfd->fcfd_n, fcfd->fcfd_t); 11057c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfd->fcfd_events, 11087c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_serd_eng_record, 11097c478bd9Sstevel@tonic-gate fmd_serd_eng_lookup(&mp->mod_serds, s)); 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 11127c478bd9Sstevel@tonic-gate fcfd = (fcf_serd_t *)((uintptr_t)fcfd + sp->fcfs_entsize); 11137c478bd9Sstevel@tonic-gate } 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate static void 11177c478bd9Sstevel@tonic-gate fmd_ckpt_restore_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate const fcf_module_t *fcfm = fmd_ckpt_dataptr(ckp, ckp->ckp_modp); 11207c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 11217c478bd9Sstevel@tonic-gate uint_t i; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (strcmp(mp->mod_name, fmd_ckpt_strptr(ckp, fcfm->fcfm_name, "")) || 11247c478bd9Sstevel@tonic-gate strcmp(mp->mod_path, fmd_ckpt_strptr(ckp, fcfm->fcfm_path, ""))) { 11257c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 11267c478bd9Sstevel@tonic-gate "checkpoint is not for module %s\n", mp->mod_name); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate for (i = 0; i < ckp->ckp_secs; i++) { 11307c478bd9Sstevel@tonic-gate sp = (void *)(ckp->ckp_buf + 11317c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * i); 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate switch (sp->fcfs_type) { 11347c478bd9Sstevel@tonic-gate case FCF_SECT_CASE: 11357c478bd9Sstevel@tonic-gate fmd_ckpt_restore_case(ckp, mp, sp); 11367c478bd9Sstevel@tonic-gate break; 11377c478bd9Sstevel@tonic-gate case FCF_SECT_SERD: 11387c478bd9Sstevel@tonic-gate fmd_ckpt_restore_serd(ckp, mp, sp); 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(ckp, mp, NULL, fcfm->fcfm_bufs); 11447c478bd9Sstevel@tonic-gate mp->mod_gen = ckp->ckp_hdr->fcfh_cgen; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Restore a checkpoint for the specified module. Any errors which occur 11497c478bd9Sstevel@tonic-gate * during restore will call fmd_ckpt_error() or trigger an fmd_api_error(), 11507c478bd9Sstevel@tonic-gate * either of which will automatically unlock the module and trigger an abort. 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate void 11537c478bd9Sstevel@tonic-gate fmd_ckpt_restore(fmd_module_t *mp) 11547c478bd9Sstevel@tonic-gate { 11557c478bd9Sstevel@tonic-gate fmd_ckpt_t ckp; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_ckpt_restore.fmds_value.bool == FMD_B_FALSE) 11587c478bd9Sstevel@tonic-gate return; /* never restore checkpoints for this module */ 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore begin %s", mp->mod_name)); 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate if (fmd_ckpt_open(&ckp, mp) == -1) { 11637c478bd9Sstevel@tonic-gate if (errno != ENOENT) 11647c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_OPEN, "can't open %s", ckp.ckp_src); 11657c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore end %s", mp->mod_name)); 11667c478bd9Sstevel@tonic-gate return; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate ASSERT(!fmd_module_locked(mp)); 11707c478bd9Sstevel@tonic-gate fmd_ckpt_restore_module(&ckp, mp); 11717c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 11727c478bd9Sstevel@tonic-gate fmd_module_clrdirty(mp); 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore end %s", mp->mod_name)); 11757c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_CKPT, "restored checkpoint of %s\n", mp->mod_name); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * Delete the module's checkpoint file. This is used by the ckpt.zero property 11807c478bd9Sstevel@tonic-gate * code or by the fmadm reset RPC service path to force a checkpoint delete. 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate void 11837c478bd9Sstevel@tonic-gate fmd_ckpt_delete(fmd_module_t *mp) 11847c478bd9Sstevel@tonic-gate { 11857c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), 11887c478bd9Sstevel@tonic-gate "%s/%s", mp->mod_ckpt, mp->mod_name); 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "delete %s ckpt", mp->mod_name)); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate if (unlink(path) != 0 && errno != ENOENT) 11937c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_DELETE, "failed to delete %s", path); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * Move aside the module's checkpoint file if checkpoint restore has failed. 11987c478bd9Sstevel@tonic-gate * We rename the file rather than deleting it in the hopes that someone might 11997c478bd9Sstevel@tonic-gate * send it to us for post-mortem analysis of whether we have a checkpoint bug. 12007c478bd9Sstevel@tonic-gate */ 12017c478bd9Sstevel@tonic-gate void 12027c478bd9Sstevel@tonic-gate fmd_ckpt_rename(fmd_module_t *mp) 12037c478bd9Sstevel@tonic-gate { 12047c478bd9Sstevel@tonic-gate char src[PATH_MAX], dst[PATH_MAX]; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate (void) snprintf(src, sizeof (src), "%s/%s", mp->mod_ckpt, mp->mod_name); 12077c478bd9Sstevel@tonic-gate (void) snprintf(dst, sizeof (dst), "%s-", src); 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "rename %s ckpt", mp->mod_name)); 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (rename(src, dst) != 0 && errno != ENOENT) 12127c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_DELETE, "failed to rename %s", src); 12137c478bd9Sstevel@tonic-gate } 1214