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