1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <strings.h> 34*7c478bd9Sstevel@tonic-gate #include <unistd.h> 35*7c478bd9Sstevel@tonic-gate #include <limits.h> 36*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include <fmd_module.h> 39*7c478bd9Sstevel@tonic-gate #include <fmd_error.h> 40*7c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 41*7c478bd9Sstevel@tonic-gate #include <fmd_case.h> 42*7c478bd9Sstevel@tonic-gate #include <fmd_serd.h> 43*7c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 44*7c478bd9Sstevel@tonic-gate #include <fmd_conf.h> 45*7c478bd9Sstevel@tonic-gate #include <fmd_event.h> 46*7c478bd9Sstevel@tonic-gate #include <fmd_log.h> 47*7c478bd9Sstevel@tonic-gate #include <fmd_api.h> 48*7c478bd9Sstevel@tonic-gate #include <fmd_ckpt.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include <fmd.h> 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #define P2ROUNDUP(x, align) (-(-(x) & -(align))) 53*7c478bd9Sstevel@tonic-gate #define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0) 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* 56*7c478bd9Sstevel@tonic-gate * The fmd_ckpt_t structure is used to manage all of the state needed by the 57*7c478bd9Sstevel@tonic-gate * various subroutines that save and restore checkpoints. The structure is 58*7c478bd9Sstevel@tonic-gate * initialized using fmd_ckpt_create() or fmd_ckpt_open() and is destroyed 59*7c478bd9Sstevel@tonic-gate * by fmd_ckpt_destroy(). Refer to the subroutines below for more details. 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate typedef struct fmd_ckpt { 62*7c478bd9Sstevel@tonic-gate char ckp_src[PATH_MAX]; /* ckpt input or output filename */ 63*7c478bd9Sstevel@tonic-gate char ckp_dst[PATH_MAX]; /* ckpt rename filename */ 64*7c478bd9Sstevel@tonic-gate uchar_t *ckp_buf; /* data buffer base address */ 65*7c478bd9Sstevel@tonic-gate fcf_hdr_t *ckp_hdr; /* file header pointer */ 66*7c478bd9Sstevel@tonic-gate uchar_t *ckp_ptr; /* data buffer pointer */ 67*7c478bd9Sstevel@tonic-gate size_t ckp_size; /* data buffer size */ 68*7c478bd9Sstevel@tonic-gate fcf_sec_t *ckp_secp; /* section header table pointer */ 69*7c478bd9Sstevel@tonic-gate fcf_sec_t *ckp_modp; /* section header for module */ 70*7c478bd9Sstevel@tonic-gate uint_t ckp_secs; /* number of sections */ 71*7c478bd9Sstevel@tonic-gate char *ckp_strs; /* string table base pointer */ 72*7c478bd9Sstevel@tonic-gate char *ckp_strp; /* string table pointer */ 73*7c478bd9Sstevel@tonic-gate size_t ckp_strn; /* string table size */ 74*7c478bd9Sstevel@tonic-gate int ckp_fd; /* output descriptor */ 75*7c478bd9Sstevel@tonic-gate fmd_module_t *ckp_mp; /* checkpoint module */ 76*7c478bd9Sstevel@tonic-gate void *ckp_arg; /* private arg for callbacks */ 77*7c478bd9Sstevel@tonic-gate } fmd_ckpt_t; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate typedef struct fmd_ckpt_desc { 80*7c478bd9Sstevel@tonic-gate uint64_t secd_size; /* minimum section size */ 81*7c478bd9Sstevel@tonic-gate uint32_t secd_entsize; /* minimum section entry size */ 82*7c478bd9Sstevel@tonic-gate uint32_t secd_align; /* section alignment */ 83*7c478bd9Sstevel@tonic-gate } fmd_ckpt_desc_t; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * Table of FCF section descriptions. Here we record the minimum size for each 87*7c478bd9Sstevel@tonic-gate * section (for use during restore) and the expected entry size and alignment 88*7c478bd9Sstevel@tonic-gate * for each section (for use during both checkpoint and restore). 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate static const fmd_ckpt_desc_t _fmd_ckpt_sections[] = { 91*7c478bd9Sstevel@tonic-gate { 0, 0, sizeof (uint8_t) }, /* NONE */ 92*7c478bd9Sstevel@tonic-gate { 1, 0, sizeof (char) }, /* STRTAB */ 93*7c478bd9Sstevel@tonic-gate { sizeof (fcf_module_t), 0, sizeof (uint32_t) }, /* MODULE */ 94*7c478bd9Sstevel@tonic-gate { sizeof (fcf_case_t), 0, sizeof (uint32_t) }, /* CASE */ 95*7c478bd9Sstevel@tonic-gate { sizeof (fcf_buf_t), sizeof (fcf_buf_t), sizeof (uint32_t) }, /* BUFS */ 96*7c478bd9Sstevel@tonic-gate { 0, 0, _MAX_ALIGNMENT }, /* BUFFER */ 97*7c478bd9Sstevel@tonic-gate { sizeof (fcf_serd_t), sizeof (fcf_serd_t), sizeof (uint64_t) }, /* SERD */ 98*7c478bd9Sstevel@tonic-gate { sizeof (fcf_event_t), sizeof (fcf_event_t), sizeof (uint64_t) }, /* EVENTS */ 99*7c478bd9Sstevel@tonic-gate { sizeof (fcf_nvl_t), sizeof (fcf_nvl_t), sizeof (uint64_t) }, /* NVLISTS */ 100*7c478bd9Sstevel@tonic-gate }; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate static int 103*7c478bd9Sstevel@tonic-gate fmd_ckpt_create(fmd_ckpt_t *ckp, fmd_module_t *mp) 104*7c478bd9Sstevel@tonic-gate { 105*7c478bd9Sstevel@tonic-gate const char *dir = mp->mod_ckpt; 106*7c478bd9Sstevel@tonic-gate const char *name = mp->mod_name; 107*7c478bd9Sstevel@tonic-gate mode_t mode; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate bzero(ckp, sizeof (fmd_ckpt_t)); 110*7c478bd9Sstevel@tonic-gate ckp->ckp_mp = mp; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate ckp->ckp_size = sizeof (fcf_hdr_t); 113*7c478bd9Sstevel@tonic-gate ckp->ckp_strn = 1; /* for \0 */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_src, PATH_MAX, "%s/%s+", dir, name); 116*7c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_dst, PATH_MAX, "%s/%s", dir, name); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate (void) unlink(ckp->ckp_src); 119*7c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.mode", &mode); 120*7c478bd9Sstevel@tonic-gate ckp->ckp_fd = open64(ckp->ckp_src, O_WRONLY | O_CREAT | O_EXCL, mode); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate return (ckp->ckp_fd); 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 126*7c478bd9Sstevel@tonic-gate static int 127*7c478bd9Sstevel@tonic-gate fmd_ckpt_inval(fmd_ckpt_t *ckp, const char *format, ...) 128*7c478bd9Sstevel@tonic-gate { 129*7c478bd9Sstevel@tonic-gate va_list ap; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate va_start(ap, format); 132*7c478bd9Sstevel@tonic-gate fmd_verror(EFMD_CKPT_INVAL, format, ap); 133*7c478bd9Sstevel@tonic-gate va_end(ap); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, ckp->ckp_size); 136*7c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_CKPT_INVAL)); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate static int 140*7c478bd9Sstevel@tonic-gate fmd_ckpt_open(fmd_ckpt_t *ckp, fmd_module_t *mp) 141*7c478bd9Sstevel@tonic-gate { 142*7c478bd9Sstevel@tonic-gate struct stat64 st; 143*7c478bd9Sstevel@tonic-gate uint64_t seclen; 144*7c478bd9Sstevel@tonic-gate uint_t i; 145*7c478bd9Sstevel@tonic-gate int err; 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate bzero(ckp, sizeof (fmd_ckpt_t)); 148*7c478bd9Sstevel@tonic-gate ckp->ckp_mp = mp; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate (void) snprintf(ckp->ckp_src, PATH_MAX, "%s/%s", 151*7c478bd9Sstevel@tonic-gate mp->mod_ckpt, mp->mod_name); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate if ((ckp->ckp_fd = open(ckp->ckp_src, O_RDONLY)) == -1) 154*7c478bd9Sstevel@tonic-gate return (-1); /* failed to open checkpoint file */ 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate if (fstat64(ckp->ckp_fd, &st) == -1) { 157*7c478bd9Sstevel@tonic-gate err = errno; 158*7c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 159*7c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate ckp->ckp_buf = fmd_alloc(st.st_size, FMD_SLEEP); 163*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr = (void *)ckp->ckp_buf; 164*7c478bd9Sstevel@tonic-gate ckp->ckp_size = read(ckp->ckp_fd, ckp->ckp_buf, st.st_size); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate if (ckp->ckp_size != st.st_size || ckp->ckp_size < sizeof (fcf_hdr_t) || 167*7c478bd9Sstevel@tonic-gate ckp->ckp_size != ckp->ckp_hdr->fcfh_filesz) { 168*7c478bd9Sstevel@tonic-gate err = ckp->ckp_size == (size_t)-1L ? errno : EFMD_CKPT_SHORT; 169*7c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, st.st_size); 170*7c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 171*7c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 175*7c478bd9Sstevel@tonic-gate ckp->ckp_fd = -1; 176*7c478bd9Sstevel@tonic-gate 177*7c478bd9Sstevel@tonic-gate /* 178*7c478bd9Sstevel@tonic-gate * Once we've read in a consistent copy of the FCF file and we're sure 179*7c478bd9Sstevel@tonic-gate * the header can be accessed, go through it and make sure everything 180*7c478bd9Sstevel@tonic-gate * is valid. We also check that unused bits are zero so we can expand 181*7c478bd9Sstevel@tonic-gate * to use them safely in the future and support old files if needed. 182*7c478bd9Sstevel@tonic-gate */ 183*7c478bd9Sstevel@tonic-gate if (bcmp(&ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG0], 184*7c478bd9Sstevel@tonic-gate FCF_MAG_STRING, FCF_MAG_STRLEN) != 0) 185*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint magic string\n")); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_MODEL] != FCF_MODEL_NATIVE) 188*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint data model\n")); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_ENCODING] != FCF_ENCODE_NATIVE) 191*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint data encoding\n")); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION] != FCF_VERSION_1) { 194*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint version %u\n", 195*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION])); 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate for (i = FCF_ID_PAD; i < FCF_ID_SIZE; i++) { 199*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_ident[i] != 0) { 200*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 201*7c478bd9Sstevel@tonic-gate "bad checkpoint padding at id[%d]", i)); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate } 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_flags & ~FCF_FL_VALID) 206*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "bad checkpoint flags\n")); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_pad != 0) 209*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "reserved field in use\n")); 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_hdrsize < sizeof (fcf_hdr_t) || 212*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secsize < sizeof (fcf_sec_t)) { 213*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 214*7c478bd9Sstevel@tonic-gate "bad header and/or section size\n")); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate seclen = (uint64_t)ckp->ckp_hdr->fcfh_secnum * 218*7c478bd9Sstevel@tonic-gate (uint64_t)ckp->ckp_hdr->fcfh_secsize; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate if (ckp->ckp_hdr->fcfh_secoff > ckp->ckp_size || 221*7c478bd9Sstevel@tonic-gate seclen > ckp->ckp_size || 222*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + seclen > ckp->ckp_size || 223*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + seclen < ckp->ckp_hdr->fcfh_secoff) 224*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "truncated section headers\n")); 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate if (!IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secoff, sizeof (uint64_t)) || 227*7c478bd9Sstevel@tonic-gate !IS_P2ALIGNED(ckp->ckp_hdr->fcfh_secsize, sizeof (uint64_t))) 228*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "misaligned section headers\n")); 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Once the header is validated, iterate over the section headers 232*7c478bd9Sstevel@tonic-gate * ensuring that each one is valid w.r.t. offset, alignment, and size. 233*7c478bd9Sstevel@tonic-gate * We also pick up the string table pointer during this pass. 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate ckp->ckp_secp = (void *)(ckp->ckp_buf + ckp->ckp_hdr->fcfh_secoff); 236*7c478bd9Sstevel@tonic-gate ckp->ckp_secs = ckp->ckp_hdr->fcfh_secnum; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate for (i = 0; i < ckp->ckp_secs; i++) { 239*7c478bd9Sstevel@tonic-gate fcf_sec_t *sp = (void *)(ckp->ckp_buf + 240*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * i); 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate const fmd_ckpt_desc_t *dp = &_fmd_ckpt_sections[sp->fcfs_type]; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate if (sp->fcfs_flags != 0) { 245*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has invalid " 246*7c478bd9Sstevel@tonic-gate "section flags (0x%x)\n", i, sp->fcfs_flags)); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (sp->fcfs_align & (sp->fcfs_align - 1)) { 250*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has invalid " 251*7c478bd9Sstevel@tonic-gate "alignment (%u)\n", i, sp->fcfs_align)); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate if (sp->fcfs_offset & (sp->fcfs_align - 1)) { 255*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u is not properly" 256*7c478bd9Sstevel@tonic-gate " aligned (offset %llu)\n", i, sp->fcfs_offset)); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate if (sp->fcfs_entsize != 0 && 260*7c478bd9Sstevel@tonic-gate (sp->fcfs_entsize & (sp->fcfs_align - 1)) != 0) { 261*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has misaligned " 262*7c478bd9Sstevel@tonic-gate "entsize %u\n", i, sp->fcfs_entsize)); 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if (sp->fcfs_offset > ckp->ckp_size || 266*7c478bd9Sstevel@tonic-gate sp->fcfs_size > ckp->ckp_size || 267*7c478bd9Sstevel@tonic-gate sp->fcfs_offset + sp->fcfs_size > ckp->ckp_size || 268*7c478bd9Sstevel@tonic-gate sp->fcfs_offset + sp->fcfs_size < sp->fcfs_offset) { 269*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has corrupt " 270*7c478bd9Sstevel@tonic-gate "size or offset\n", i)); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate if (sp->fcfs_type >= sizeof (_fmd_ckpt_sections) / 274*7c478bd9Sstevel@tonic-gate sizeof (_fmd_ckpt_sections[0])) { 275*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has unknown " 276*7c478bd9Sstevel@tonic-gate "section type %u\n", i, sp->fcfs_type)); 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate if (sp->fcfs_align != dp->secd_align) { 280*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has align %u " 281*7c478bd9Sstevel@tonic-gate "(not %u)\n", i, sp->fcfs_align, dp->secd_align)); 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if (sp->fcfs_size < dp->secd_size || 285*7c478bd9Sstevel@tonic-gate sp->fcfs_entsize < dp->secd_entsize) { 286*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section %u has short " 287*7c478bd9Sstevel@tonic-gate "size or entsize\n", i)); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate switch (sp->fcfs_type) { 291*7c478bd9Sstevel@tonic-gate case FCF_SECT_STRTAB: 292*7c478bd9Sstevel@tonic-gate if (ckp->ckp_strs != NULL) { 293*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "multiple string " 294*7c478bd9Sstevel@tonic-gate "tables are present in checkpoint file\n")); 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate ckp->ckp_strs = (char *)ckp->ckp_buf + sp->fcfs_offset; 298*7c478bd9Sstevel@tonic-gate ckp->ckp_strn = sp->fcfs_size; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate if (ckp->ckp_strs[ckp->ckp_strn - 1] != '\0') { 301*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "string table %u " 302*7c478bd9Sstevel@tonic-gate "is missing terminating nul byte\n", i)); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate break; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate case FCF_SECT_MODULE: 307*7c478bd9Sstevel@tonic-gate if (ckp->ckp_modp != NULL) { 308*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "multiple module " 309*7c478bd9Sstevel@tonic-gate "sects are present in checkpoint file\n")); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate ckp->ckp_modp = sp; 312*7c478bd9Sstevel@tonic-gate break; 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * Ensure that the first section is an empty one of type FCF_SECT_NONE. 318*7c478bd9Sstevel@tonic-gate * This is done to ensure that links can use index 0 as a null section. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate if (ckp->ckp_secs == 0 || ckp->ckp_secp->fcfs_type != FCF_SECT_NONE || 321*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_entsize != 0 || ckp->ckp_secp->fcfs_size != 0) { 322*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, "section 0 is not of the " 323*7c478bd9Sstevel@tonic-gate "appropriate size and/or attributes (SECT_NONE)\n")); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate if (ckp->ckp_modp == NULL) { 327*7c478bd9Sstevel@tonic-gate return (fmd_ckpt_inval(ckp, 328*7c478bd9Sstevel@tonic-gate "no module section found in file\n")); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate return (0); 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate static void 335*7c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(fmd_ckpt_t *ckp) 336*7c478bd9Sstevel@tonic-gate { 337*7c478bd9Sstevel@tonic-gate if (ckp->ckp_buf != NULL) 338*7c478bd9Sstevel@tonic-gate fmd_free(ckp->ckp_buf, ckp->ckp_size); 339*7c478bd9Sstevel@tonic-gate if (ckp->ckp_fd >= 0) 340*7c478bd9Sstevel@tonic-gate (void) close(ckp->ckp_fd); 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * fmd_ckpt_error() is used as a wrapper around fmd_error() for ckpt routines. 345*7c478bd9Sstevel@tonic-gate * It calls fmd_module_unlock() on behalf of its caller, logs the error, and 346*7c478bd9Sstevel@tonic-gate * then aborts the API call and the surrounding module entry point by doing an 347*7c478bd9Sstevel@tonic-gate * fmd_module_abort(), which longjmps to the place where we entered the module. 348*7c478bd9Sstevel@tonic-gate * Depending on the type of error and conf settings, we will reset or fail. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 351*7c478bd9Sstevel@tonic-gate static void 352*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(fmd_ckpt_t *ckp, int err, const char *format, ...) 353*7c478bd9Sstevel@tonic-gate { 354*7c478bd9Sstevel@tonic-gate fmd_module_t *mp = ckp->ckp_mp; 355*7c478bd9Sstevel@tonic-gate va_list ap; 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate va_start(ap, format); 358*7c478bd9Sstevel@tonic-gate fmd_verror(err, format, ap); 359*7c478bd9Sstevel@tonic-gate va_end(ap); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate if (fmd_module_locked(mp)) 362*7c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(ckp); 365*7c478bd9Sstevel@tonic-gate fmd_module_abort(mp, err); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate static fcf_secidx_t 369*7c478bd9Sstevel@tonic-gate fmd_ckpt_section(fmd_ckpt_t *ckp, const void *data, uint_t type, uint64_t size) 370*7c478bd9Sstevel@tonic-gate { 371*7c478bd9Sstevel@tonic-gate const fmd_ckpt_desc_t *dp; 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate ASSERT(type < sizeof (_fmd_ckpt_sections) / sizeof (fmd_ckpt_desc_t)); 374*7c478bd9Sstevel@tonic-gate dp = &_fmd_ckpt_sections[type]; 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *) 377*7c478bd9Sstevel@tonic-gate P2ROUNDUP((uintptr_t)ckp->ckp_ptr, dp->secd_align); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_type = type; 380*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_align = dp->secd_align; 381*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_flags = 0; 382*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_entsize = dp->secd_entsize; 383*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_offset = (size_t)(ckp->ckp_ptr - ckp->ckp_buf); 384*7c478bd9Sstevel@tonic-gate ckp->ckp_secp->fcfs_size = size; 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate /* 387*7c478bd9Sstevel@tonic-gate * If the data pointer is non-NULL, copy the data to our buffer; else 388*7c478bd9Sstevel@tonic-gate * the caller is responsible for doing so and updating ckp->ckp_ptr. 389*7c478bd9Sstevel@tonic-gate */ 390*7c478bd9Sstevel@tonic-gate if (data != NULL) { 391*7c478bd9Sstevel@tonic-gate bcopy(data, ckp->ckp_ptr, size); 392*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr += size; 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate ckp->ckp_secp++; 396*7c478bd9Sstevel@tonic-gate return (ckp->ckp_secs++); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate static fcf_stridx_t 400*7c478bd9Sstevel@tonic-gate fmd_ckpt_string(fmd_ckpt_t *ckp, const char *s) 401*7c478bd9Sstevel@tonic-gate { 402*7c478bd9Sstevel@tonic-gate fcf_stridx_t idx = (fcf_stridx_t)(ckp->ckp_strp - ckp->ckp_strs); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate (void) strcpy(ckp->ckp_strp, s); 405*7c478bd9Sstevel@tonic-gate ckp->ckp_strp += strlen(s) + 1; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate return (idx); 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate static int 411*7c478bd9Sstevel@tonic-gate fmd_ckpt_alloc(fmd_ckpt_t *ckp, uint64_t gen) 412*7c478bd9Sstevel@tonic-gate { 413*7c478bd9Sstevel@tonic-gate /* 414*7c478bd9Sstevel@tonic-gate * We've added up all the sections by now: add two more for SECT_NONE 415*7c478bd9Sstevel@tonic-gate * and SECT_STRTAB, and add the size of the section header table and 416*7c478bd9Sstevel@tonic-gate * string table to the total size. We know that the fcf_hdr_t is 417*7c478bd9Sstevel@tonic-gate * aligned so that that fcf_sec_t's can follow it, and that fcf_sec_t 418*7c478bd9Sstevel@tonic-gate * is aligned so that any section can follow it, so no extra padding 419*7c478bd9Sstevel@tonic-gate * bytes need to be allocated between any of these items. 420*7c478bd9Sstevel@tonic-gate */ 421*7c478bd9Sstevel@tonic-gate ckp->ckp_secs += 2; /* for FCF_SECT_NONE and FCF_SECT_STRTAB */ 422*7c478bd9Sstevel@tonic-gate ckp->ckp_size += sizeof (fcf_sec_t) * ckp->ckp_secs; 423*7c478bd9Sstevel@tonic-gate ckp->ckp_size += ckp->ckp_strn; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "alloc fcf buf size %u", ckp->ckp_size)); 426*7c478bd9Sstevel@tonic-gate ckp->ckp_buf = fmd_zalloc(ckp->ckp_size, FMD_NOSLEEP); 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate if (ckp->ckp_buf == NULL) 429*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr = (void *)ckp->ckp_buf; 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG0] = FCF_MAG_MAG0; 434*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG1] = FCF_MAG_MAG1; 435*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG2] = FCF_MAG_MAG2; 436*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MAG3] = FCF_MAG_MAG3; 437*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_MODEL] = FCF_MODEL_NATIVE; 438*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_ENCODING] = FCF_ENCODE_NATIVE; 439*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_ident[FCF_ID_VERSION] = FCF_VERSION; 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_hdrsize = sizeof (fcf_hdr_t); 442*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secsize = sizeof (fcf_sec_t); 443*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secnum = ckp->ckp_secs; 444*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff = sizeof (fcf_hdr_t); 445*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_filesz = ckp->ckp_size; 446*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_cgen = gen; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate ckp->ckp_secs = 0; /* reset section counter for second pass */ 449*7c478bd9Sstevel@tonic-gate ckp->ckp_secp = (void *)(ckp->ckp_buf + sizeof (fcf_hdr_t)); 450*7c478bd9Sstevel@tonic-gate ckp->ckp_strs = (char *)ckp->ckp_buf + ckp->ckp_size - ckp->ckp_strn; 451*7c478bd9Sstevel@tonic-gate ckp->ckp_strp = ckp->ckp_strs + 1; /* use first byte as \0 */ 452*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *)(ckp->ckp_secp + ckp->ckp_hdr->fcfh_secnum); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, NULL, FCF_SECT_NONE, 0); 455*7c478bd9Sstevel@tonic-gate return (0); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate static int 459*7c478bd9Sstevel@tonic-gate fmd_ckpt_commit(fmd_ckpt_t *ckp) 460*7c478bd9Sstevel@tonic-gate { 461*7c478bd9Sstevel@tonic-gate fcf_sec_t *secbase = (void *)(ckp->ckp_buf + sizeof (fcf_hdr_t)); 462*7c478bd9Sstevel@tonic-gate size_t stroff = ckp->ckp_size - ckp->ckp_strn; 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * Before committing the checkpoint, we assert that fmd_ckpt_t's sizes 466*7c478bd9Sstevel@tonic-gate * and current pointer locations all add up appropriately. Any ASSERTs 467*7c478bd9Sstevel@tonic-gate * which trip here likely indicate an inconsistency in the code for the 468*7c478bd9Sstevel@tonic-gate * reservation pass and the buffer update pass of the FCF subroutines. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate ASSERT((size_t)(ckp->ckp_ptr - ckp->ckp_buf) == stroff); 471*7c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, NULL, FCF_SECT_STRTAB, ckp->ckp_strn); 472*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr += ckp->ckp_strn; /* string table is already filled in */ 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_secs == ckp->ckp_hdr->fcfh_secnum); 475*7c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_secp == secbase + ckp->ckp_hdr->fcfh_secnum); 476*7c478bd9Sstevel@tonic-gate ASSERT(ckp->ckp_ptr == ckp->ckp_buf + ckp->ckp_hdr->fcfh_filesz); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate if (write(ckp->ckp_fd, ckp->ckp_buf, ckp->ckp_size) != ckp->ckp_size || 479*7c478bd9Sstevel@tonic-gate fsync(ckp->ckp_fd) != 0 || close(ckp->ckp_fd) != 0) 480*7c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate ckp->ckp_fd = -1; /* fd is now closed */ 483*7c478bd9Sstevel@tonic-gate return (rename(ckp->ckp_src, ckp->ckp_dst) != 0); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate static void 487*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(fmd_ckpt_t *ckp, size_t size, size_t align) 488*7c478bd9Sstevel@tonic-gate { 489*7c478bd9Sstevel@tonic-gate if (size != 0) { 490*7c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, align) + size; 491*7c478bd9Sstevel@tonic-gate ckp->ckp_secs++; 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate static void 496*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_buf(fmd_buf_t *bp, fmd_ckpt_t *ckp) 497*7c478bd9Sstevel@tonic-gate { 498*7c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, _MAX_ALIGNMENT) + bp->buf_size; 499*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(bp->buf_name) + 1; 500*7c478bd9Sstevel@tonic-gate ckp->ckp_secs++; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate static void 504*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_buf(fmd_buf_t *bp, fmd_ckpt_t *ckp) 505*7c478bd9Sstevel@tonic-gate { 506*7c478bd9Sstevel@tonic-gate fcf_buf_t *fcfb = ckp->ckp_arg; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate fcfb->fcfb_name = fmd_ckpt_string(ckp, bp->buf_name); 509*7c478bd9Sstevel@tonic-gate fcfb->fcfb_data = fmd_ckpt_section(ckp, 510*7c478bd9Sstevel@tonic-gate bp->buf_data, FCF_SECT_BUFFER, bp->buf_size); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate ckp->ckp_arg = fcfb + 1; 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate static void 516*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(fmd_ckpt_t *ckp, fmd_event_t *e) 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate fcf_event_t *fcfe = (void *)ckp->ckp_ptr; 519*7c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 520*7c478bd9Sstevel@tonic-gate fmd_log_t *lp = ep->ev_log; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate fcfe->fcfe_todsec = ep->ev_time.ftv_sec; 523*7c478bd9Sstevel@tonic-gate fcfe->fcfe_todnsec = ep->ev_time.ftv_nsec; 524*7c478bd9Sstevel@tonic-gate fcfe->fcfe_major = lp ? major(lp->log_stat.st_dev) : -1U; 525*7c478bd9Sstevel@tonic-gate fcfe->fcfe_minor = lp ? minor(lp->log_stat.st_dev) : -1U; 526*7c478bd9Sstevel@tonic-gate fcfe->fcfe_inode = lp ? lp->log_stat.st_ino : -1ULL; 527*7c478bd9Sstevel@tonic-gate fcfe->fcfe_offset = ep->ev_off; 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr += sizeof (fcf_event_t); 530*7c478bd9Sstevel@tonic-gate } 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate static void 533*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_nvlist(fmd_ckpt_t *ckp, nvlist_t *nvl) 534*7c478bd9Sstevel@tonic-gate { 535*7c478bd9Sstevel@tonic-gate fcf_nvl_t *fcfn = (void *)ckp->ckp_ptr; 536*7c478bd9Sstevel@tonic-gate char *nvbuf = (char *)ckp->ckp_ptr + sizeof (fcf_nvl_t); 537*7c478bd9Sstevel@tonic-gate size_t nvsize = 0; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate (void) nvlist_size(nvl, &nvsize, NV_ENCODE_NATIVE); 540*7c478bd9Sstevel@tonic-gate fcfn->fcfn_size = (uint64_t)nvsize; 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate (void) nvlist_pack(nvl, &nvbuf, &nvsize, NV_ENCODE_NATIVE, 0); 543*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr += sizeof (fcf_nvl_t) + nvsize; 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate ckp->ckp_ptr = (uchar_t *) 546*7c478bd9Sstevel@tonic-gate P2ROUNDUP((uintptr_t)ckp->ckp_ptr, sizeof (uint64_t)); 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate static void 550*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_serd(fmd_serd_eng_t *sgp, fmd_ckpt_t *ckp) 551*7c478bd9Sstevel@tonic-gate { 552*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, 553*7c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * sgp->sg_count, sizeof (uint64_t)); 554*7c478bd9Sstevel@tonic-gate 555*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(sgp->sg_name) + 1; 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate static void 559*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_serd(fmd_serd_eng_t *sgp, fmd_ckpt_t *ckp) 560*7c478bd9Sstevel@tonic-gate { 561*7c478bd9Sstevel@tonic-gate fcf_serd_t *fcfd = ckp->ckp_arg; 562*7c478bd9Sstevel@tonic-gate fcf_secidx_t evsec = FCF_SECT_NONE; 563*7c478bd9Sstevel@tonic-gate fmd_serd_elem_t *sep; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate if (sgp->sg_count != 0) { 566*7c478bd9Sstevel@tonic-gate evsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 567*7c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * sgp->sg_count); 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate for (sep = fmd_list_next(&sgp->sg_list); 570*7c478bd9Sstevel@tonic-gate sep != NULL; sep = fmd_list_next(sep)) 571*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, sep->se_event); 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate fcfd->fcfd_name = fmd_ckpt_string(ckp, sgp->sg_name); 575*7c478bd9Sstevel@tonic-gate fcfd->fcfd_events = evsec; 576*7c478bd9Sstevel@tonic-gate fcfd->fcfd_pad = 0; 577*7c478bd9Sstevel@tonic-gate fcfd->fcfd_n = sgp->sg_n; 578*7c478bd9Sstevel@tonic-gate fcfd->fcfd_t = sgp->sg_t; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate ckp->ckp_arg = fcfd + 1; 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate static void 584*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_case(fmd_ckpt_t *ckp, fmd_case_t *cp) 585*7c478bd9Sstevel@tonic-gate { 586*7c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 587*7c478bd9Sstevel@tonic-gate fmd_case_susp_t *cis; 588*7c478bd9Sstevel@tonic-gate uint_t n; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate n = fmd_buf_hash_count(&cip->ci_bufs); 591*7c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&cip->ci_bufs, (fmd_buf_f *)fmd_ckpt_resv_buf, ckp); 592*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_buf_t) * n, sizeof (uint32_t)); 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate if (cip->ci_principal != NULL) 595*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_event_t), sizeof (uint64_t)); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, 598*7c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * cip->ci_nitems, sizeof (uint64_t)); 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate if (cip->ci_nsuspects != 0) 601*7c478bd9Sstevel@tonic-gate ckp->ckp_size = P2ROUNDUP(ckp->ckp_size, sizeof (uint64_t)); 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate cip->ci_nvsz = 0; /* compute size of packed suspect nvlist array */ 604*7c478bd9Sstevel@tonic-gate 605*7c478bd9Sstevel@tonic-gate for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) { 606*7c478bd9Sstevel@tonic-gate size_t nvsize = 0; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate (void) nvlist_size(cis->cis_nvl, &nvsize, NV_ENCODE_NATIVE); 609*7c478bd9Sstevel@tonic-gate cip->ci_nvsz += sizeof (fcf_nvl_t) + nvsize; 610*7c478bd9Sstevel@tonic-gate cip->ci_nvsz = P2ROUNDUP(cip->ci_nvsz, sizeof (uint64_t)); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, cip->ci_nvsz, sizeof (uint64_t)); 614*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_case_t), sizeof (uint32_t)); 615*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(cip->ci_uuid) + 1; 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate static void 619*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_case(fmd_ckpt_t *ckp, fmd_case_t *cp) 620*7c478bd9Sstevel@tonic-gate { 621*7c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate fmd_case_item_t *cit; 624*7c478bd9Sstevel@tonic-gate fmd_case_susp_t *cis; 625*7c478bd9Sstevel@tonic-gate fcf_case_t fcfc; 626*7c478bd9Sstevel@tonic-gate uint_t n; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate fcf_secidx_t bufsec = FCF_SECIDX_NONE; 629*7c478bd9Sstevel@tonic-gate fcf_secidx_t evsec = FCF_SECIDX_NONE; 630*7c478bd9Sstevel@tonic-gate fcf_secidx_t nvsec = FCF_SECIDX_NONE; 631*7c478bd9Sstevel@tonic-gate fcf_secidx_t prsec = FCF_SECIDX_NONE; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate if ((n = fmd_buf_hash_count(&cip->ci_bufs)) != 0) { 634*7c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_buf_t) * n; 635*7c478bd9Sstevel@tonic-gate fcf_buf_t *bufs = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 636*7c478bd9Sstevel@tonic-gate 637*7c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&cip->ci_bufs, 638*7c478bd9Sstevel@tonic-gate (fmd_buf_f *)fmd_ckpt_save_buf, ckp); 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate bufsec = fmd_ckpt_section(ckp, bufs, FCF_SECT_BUFS, size); 641*7c478bd9Sstevel@tonic-gate fmd_free(bufs, size); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate if (cip->ci_principal != NULL) { 645*7c478bd9Sstevel@tonic-gate prsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 646*7c478bd9Sstevel@tonic-gate sizeof (fcf_event_t)); 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, cip->ci_principal); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate if (cip->ci_nitems != 0) { 652*7c478bd9Sstevel@tonic-gate evsec = fmd_ckpt_section(ckp, NULL, FCF_SECT_EVENTS, 653*7c478bd9Sstevel@tonic-gate sizeof (fcf_event_t) * cip->ci_nitems); 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) 656*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_event(ckp, cit->cit_event); 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate if (cip->ci_nsuspects != 0) { 660*7c478bd9Sstevel@tonic-gate nvsec = fmd_ckpt_section(ckp, NULL, 661*7c478bd9Sstevel@tonic-gate FCF_SECT_NVLISTS, cip->ci_nvsz); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) 664*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_nvlist(ckp, cis->cis_nvl); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate fcfc.fcfc_uuid = fmd_ckpt_string(ckp, cip->ci_uuid); 668*7c478bd9Sstevel@tonic-gate fcfc.fcfc_bufs = bufsec; 669*7c478bd9Sstevel@tonic-gate fcfc.fcfc_principal = prsec; 670*7c478bd9Sstevel@tonic-gate fcfc.fcfc_events = evsec; 671*7c478bd9Sstevel@tonic-gate fcfc.fcfc_suspects = nvsec; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate switch (cip->ci_state) { 674*7c478bd9Sstevel@tonic-gate case FMD_CASE_UNSOLVED: 675*7c478bd9Sstevel@tonic-gate fcfc.fcfc_state = FCF_CASE_UNSOLVED; 676*7c478bd9Sstevel@tonic-gate break; 677*7c478bd9Sstevel@tonic-gate case FMD_CASE_SOLVED: 678*7c478bd9Sstevel@tonic-gate fcfc.fcfc_state = FCF_CASE_SOLVED; 679*7c478bd9Sstevel@tonic-gate break; 680*7c478bd9Sstevel@tonic-gate case FMD_CASE_CLOSED: 681*7c478bd9Sstevel@tonic-gate fcfc.fcfc_state = FCF_CASE_CLOSED; 682*7c478bd9Sstevel@tonic-gate break; 683*7c478bd9Sstevel@tonic-gate default: 684*7c478bd9Sstevel@tonic-gate fmd_panic("case %p (%s) has invalid state %u", 685*7c478bd9Sstevel@tonic-gate (void *)cp, cip->ci_uuid, cip->ci_state); 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, &fcfc, FCF_SECT_CASE, sizeof (fcf_case_t)); 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate static void 692*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 693*7c478bd9Sstevel@tonic-gate { 694*7c478bd9Sstevel@tonic-gate fmd_case_t *cp; 695*7c478bd9Sstevel@tonic-gate uint_t n; 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); cp; cp = fmd_list_next(cp)) 698*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_case(ckp, cp); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate n = fmd_serd_hash_count(&mp->mod_serds); 701*7c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 702*7c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_ckpt_resv_serd, ckp); 703*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_serd_t) * n, sizeof (uint64_t)); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate n = fmd_buf_hash_count(&mp->mod_bufs); 706*7c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&mp->mod_bufs, (fmd_buf_f *)fmd_ckpt_resv_buf, ckp); 707*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_buf_t) * n, sizeof (uint32_t)); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv(ckp, sizeof (fcf_module_t), sizeof (uint32_t)); 710*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_name) + 1; 711*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_path) + 1; 712*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_info->fmdi_desc) + 1; 713*7c478bd9Sstevel@tonic-gate ckp->ckp_strn += strlen(mp->mod_info->fmdi_vers) + 1; 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate static void 717*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate fcf_secidx_t bufsec = FCF_SECIDX_NONE; 720*7c478bd9Sstevel@tonic-gate fcf_module_t fcfm; 721*7c478bd9Sstevel@tonic-gate fmd_case_t *cp; 722*7c478bd9Sstevel@tonic-gate uint_t n; 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate for (cp = fmd_list_next(&mp->mod_cases); cp; cp = fmd_list_next(cp)) 725*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_case(ckp, cp); 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate if ((n = fmd_serd_hash_count(&mp->mod_serds)) != 0) { 728*7c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_serd_t) * n; 729*7c478bd9Sstevel@tonic-gate fcf_serd_t *serds = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate fmd_serd_hash_apply(&mp->mod_serds, 732*7c478bd9Sstevel@tonic-gate (fmd_serd_eng_f *)fmd_ckpt_save_serd, ckp); 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, serds, FCF_SECT_SERD, size); 735*7c478bd9Sstevel@tonic-gate fmd_free(serds, size); 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate if ((n = fmd_buf_hash_count(&mp->mod_bufs)) != 0) { 739*7c478bd9Sstevel@tonic-gate size_t size = sizeof (fcf_buf_t) * n; 740*7c478bd9Sstevel@tonic-gate fcf_buf_t *bufs = ckp->ckp_arg = fmd_alloc(size, FMD_SLEEP); 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate fmd_buf_hash_apply(&mp->mod_bufs, 743*7c478bd9Sstevel@tonic-gate (fmd_buf_f *)fmd_ckpt_save_buf, ckp); 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate bufsec = fmd_ckpt_section(ckp, bufs, FCF_SECT_BUFS, size); 746*7c478bd9Sstevel@tonic-gate fmd_free(bufs, size); 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate fcfm.fcfm_name = fmd_ckpt_string(ckp, mp->mod_name); 750*7c478bd9Sstevel@tonic-gate fcfm.fcfm_path = fmd_ckpt_string(ckp, mp->mod_path); 751*7c478bd9Sstevel@tonic-gate fcfm.fcfm_desc = fmd_ckpt_string(ckp, mp->mod_info->fmdi_desc); 752*7c478bd9Sstevel@tonic-gate fcfm.fcfm_vers = fmd_ckpt_string(ckp, mp->mod_info->fmdi_vers); 753*7c478bd9Sstevel@tonic-gate fcfm.fcfm_bufs = bufsec; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate (void) fmd_ckpt_section(ckp, &fcfm, 756*7c478bd9Sstevel@tonic-gate FCF_SECT_MODULE, sizeof (fcf_module_t)); 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate void 760*7c478bd9Sstevel@tonic-gate fmd_ckpt_save(fmd_module_t *mp) 761*7c478bd9Sstevel@tonic-gate { 762*7c478bd9Sstevel@tonic-gate struct stat64 st; 763*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 764*7c478bd9Sstevel@tonic-gate mode_t dirmode; 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate hrtime_t now = gethrtime(); 767*7c478bd9Sstevel@tonic-gate fmd_ckpt_t ckp; 768*7c478bd9Sstevel@tonic-gate int err; 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate ASSERT(fmd_module_locked(mp)); 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate /* 773*7c478bd9Sstevel@tonic-gate * If checkpointing is disabled for the module, just return. We must 774*7c478bd9Sstevel@tonic-gate * commit the module state anyway to transition pending log events. 775*7c478bd9Sstevel@tonic-gate */ 776*7c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_ckpt_save.fmds_value.bool == FMD_B_FALSE) { 777*7c478bd9Sstevel@tonic-gate fmd_module_commit(mp); 778*7c478bd9Sstevel@tonic-gate return; 779*7c478bd9Sstevel@tonic-gate } 780*7c478bd9Sstevel@tonic-gate 781*7c478bd9Sstevel@tonic-gate if (!(mp->mod_flags & (FMD_MOD_MDIRTY | FMD_MOD_CDIRTY))) 782*7c478bd9Sstevel@tonic-gate return; /* no checkpoint is necessary for this module */ 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt save begin %s %llu", 785*7c478bd9Sstevel@tonic-gate mp->mod_name, mp->mod_gen + 1)); 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate * If the per-module checkpoint directory isn't found or isn't of type 789*7c478bd9Sstevel@tonic-gate * directory, move aside whatever is there (if anything) and attempt 790*7c478bd9Sstevel@tonic-gate * to mkdir(2) a new module checkpoint directory. If this fails, we 791*7c478bd9Sstevel@tonic-gate * have no choice but to abort the checkpoint and try again later. 792*7c478bd9Sstevel@tonic-gate */ 793*7c478bd9Sstevel@tonic-gate if (stat64(mp->mod_ckpt, &st) != 0 || !S_ISDIR(st.st_mode)) { 794*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s-", mp->mod_ckpt); 795*7c478bd9Sstevel@tonic-gate (void) rename(mp->mod_ckpt, path); 796*7c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "ckpt.dirmode", &dirmode); 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate if (mkdir(mp->mod_ckpt, dirmode) != 0) { 799*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_MKDIR, 800*7c478bd9Sstevel@tonic-gate "failed to mkdir %s", mp->mod_ckpt); 801*7c478bd9Sstevel@tonic-gate return; /* return without clearing dirty bits */ 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* 806*7c478bd9Sstevel@tonic-gate * Create a temporary file to write out the checkpoint into, and create 807*7c478bd9Sstevel@tonic-gate * a fmd_ckpt_t structure to manage construction of the checkpoint. We 808*7c478bd9Sstevel@tonic-gate * then figure out how much space will be required, and allocate it. 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate if (fmd_ckpt_create(&ckp, mp) == -1) { 811*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_CREATE, "failed to create %s", ckp.ckp_src); 812*7c478bd9Sstevel@tonic-gate return; 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate fmd_ckpt_resv_module(&ckp, mp); 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate if (fmd_ckpt_alloc(&ckp, mp->mod_gen + 1) != 0) { 818*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_NOMEM, "failed to build %s", ckp.ckp_src); 819*7c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 820*7c478bd9Sstevel@tonic-gate return; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* 824*7c478bd9Sstevel@tonic-gate * Fill in the checkpoint content, write it to disk, sync it, and then 825*7c478bd9Sstevel@tonic-gate * atomically rename it to the destination path. If this fails, we 826*7c478bd9Sstevel@tonic-gate * have no choice but to leave all our dirty bits set and return. 827*7c478bd9Sstevel@tonic-gate */ 828*7c478bd9Sstevel@tonic-gate fmd_ckpt_save_module(&ckp, mp); 829*7c478bd9Sstevel@tonic-gate err = fmd_ckpt_commit(&ckp); 830*7c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate if (err != 0) { 833*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_COMMIT, "failed to commit %s", ckp.ckp_dst); 834*7c478bd9Sstevel@tonic-gate return; /* return without clearing dirty bits */ 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate fmd_module_commit(mp); 838*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt save end %s", mp->mod_name)); 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate mp->mod_stats->ms_ckpt_cnt.fmds_value.ui64++; 841*7c478bd9Sstevel@tonic-gate mp->mod_stats->ms_ckpt_time.fmds_value.ui64 += gethrtime() - now; 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_CKPT, "saved checkpoint of %s (%llu)\n", 844*7c478bd9Sstevel@tonic-gate mp->mod_name, mp->mod_gen); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /* 848*7c478bd9Sstevel@tonic-gate * Utility function to retrieve a pointer to a section's header and verify that 849*7c478bd9Sstevel@tonic-gate * it is of the expected type or it is a FCF_SECT_NONE reference. 850*7c478bd9Sstevel@tonic-gate */ 851*7c478bd9Sstevel@tonic-gate static const fcf_sec_t * 852*7c478bd9Sstevel@tonic-gate fmd_ckpt_secptr(fmd_ckpt_t *ckp, fcf_secidx_t sid, uint_t type) 853*7c478bd9Sstevel@tonic-gate { 854*7c478bd9Sstevel@tonic-gate const fcf_sec_t *sp = (void *)(ckp->ckp_buf + 855*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * sid); 856*7c478bd9Sstevel@tonic-gate 857*7c478bd9Sstevel@tonic-gate return (sid < ckp->ckp_secs && (sp->fcfs_type == type || 858*7c478bd9Sstevel@tonic-gate sp->fcfs_type == FCF_SECT_NONE) ? sp : NULL); 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate /* 862*7c478bd9Sstevel@tonic-gate * Utility function to retrieve the data pointer for a particular section. The 863*7c478bd9Sstevel@tonic-gate * validity of the header values has already been checked by fmd_ckpt_open(). 864*7c478bd9Sstevel@tonic-gate */ 865*7c478bd9Sstevel@tonic-gate static const void * 866*7c478bd9Sstevel@tonic-gate fmd_ckpt_dataptr(fmd_ckpt_t *ckp, const fcf_sec_t *sp) 867*7c478bd9Sstevel@tonic-gate { 868*7c478bd9Sstevel@tonic-gate return (ckp->ckp_buf + sp->fcfs_offset); 869*7c478bd9Sstevel@tonic-gate } 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * Utility function to retrieve the end of the data region for a particular 873*7c478bd9Sstevel@tonic-gate * section. The validity of this value has been confirmed by fmd_ckpt_open(). 874*7c478bd9Sstevel@tonic-gate */ 875*7c478bd9Sstevel@tonic-gate static const void * 876*7c478bd9Sstevel@tonic-gate fmd_ckpt_datalim(fmd_ckpt_t *ckp, const fcf_sec_t *sp) 877*7c478bd9Sstevel@tonic-gate { 878*7c478bd9Sstevel@tonic-gate return (ckp->ckp_buf + sp->fcfs_offset + sp->fcfs_size); 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate /* 882*7c478bd9Sstevel@tonic-gate * Utility function to retrieve a string pointer (fcf_stridx_t). If the string 883*7c478bd9Sstevel@tonic-gate * index is valid, the string data is returned; otherwise 'defstr' is returned. 884*7c478bd9Sstevel@tonic-gate */ 885*7c478bd9Sstevel@tonic-gate static const char * 886*7c478bd9Sstevel@tonic-gate fmd_ckpt_strptr(fmd_ckpt_t *ckp, fcf_stridx_t sid, const char *defstr) 887*7c478bd9Sstevel@tonic-gate { 888*7c478bd9Sstevel@tonic-gate return (sid < ckp->ckp_strn ? ckp->ckp_strs + sid : defstr); 889*7c478bd9Sstevel@tonic-gate } 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate static void 892*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(fmd_ckpt_t *ckp, fcf_secidx_t sid, 893*7c478bd9Sstevel@tonic-gate void (*func)(void *, fmd_event_t *), void *arg) 894*7c478bd9Sstevel@tonic-gate { 895*7c478bd9Sstevel@tonic-gate const fcf_event_t *fcfe; 896*7c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 897*7c478bd9Sstevel@tonic-gate fmd_timeval_t ftv; 898*7c478bd9Sstevel@tonic-gate fmd_log_t *lp, *errlp; 899*7c478bd9Sstevel@tonic-gate uint_t i, n; 900*7c478bd9Sstevel@tonic-gate uint32_t e_maj, e_min; 901*7c478bd9Sstevel@tonic-gate uint64_t e_ino; 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_EVENTS)) == NULL) { 904*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 905*7c478bd9Sstevel@tonic-gate "invalid link to section %u: expected events\n", sid); 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate 908*7c478bd9Sstevel@tonic-gate if (sp->fcfs_size == 0) 909*7c478bd9Sstevel@tonic-gate return; /* empty events section or type none */ 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate fcfe = fmd_ckpt_dataptr(ckp, sp); 912*7c478bd9Sstevel@tonic-gate n = sp->fcfs_size / sp->fcfs_entsize; 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* 915*7c478bd9Sstevel@tonic-gate * Hold the reader lock on log pointers to block log rotation during 916*7c478bd9Sstevel@tonic-gate * the section restore so that we can safely insert refs to d_errlog. 917*7c478bd9Sstevel@tonic-gate */ 918*7c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&fmd.d_log_lock); 919*7c478bd9Sstevel@tonic-gate errlp = fmd.d_errlog; 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate e_maj = major(errlp->log_stat.st_dev); 922*7c478bd9Sstevel@tonic-gate e_min = minor(errlp->log_stat.st_dev); 923*7c478bd9Sstevel@tonic-gate e_ino = errlp->log_stat.st_ino; 924*7c478bd9Sstevel@tonic-gate 925*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 926*7c478bd9Sstevel@tonic-gate ftv.ftv_sec = fcfe->fcfe_todsec; 927*7c478bd9Sstevel@tonic-gate ftv.ftv_nsec = fcfe->fcfe_todnsec; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate if (e_ino == fcfe->fcfe_inode && 930*7c478bd9Sstevel@tonic-gate e_maj == fcfe->fcfe_major && 931*7c478bd9Sstevel@tonic-gate e_min == fcfe->fcfe_minor) 932*7c478bd9Sstevel@tonic-gate lp = errlp; 933*7c478bd9Sstevel@tonic-gate else 934*7c478bd9Sstevel@tonic-gate lp = NULL; 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate func(arg, fmd_event_recreate(FMD_EVT_PROTOCOL, 937*7c478bd9Sstevel@tonic-gate &ftv, NULL, NULL, lp, fcfe->fcfe_offset, 0)); 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate fcfe = (fcf_event_t *)((uintptr_t)fcfe + sp->fcfs_entsize); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&fmd.d_log_lock); 943*7c478bd9Sstevel@tonic-gate } 944*7c478bd9Sstevel@tonic-gate 945*7c478bd9Sstevel@tonic-gate static void 946*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_suspects(fmd_ckpt_t *ckp, fmd_case_t *cp, fcf_secidx_t sid) 947*7c478bd9Sstevel@tonic-gate { 948*7c478bd9Sstevel@tonic-gate const fcf_nvl_t *fcfn, *endn; 949*7c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 950*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 951*7c478bd9Sstevel@tonic-gate int err, i; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_NVLISTS)) == NULL) { 954*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 955*7c478bd9Sstevel@tonic-gate "invalid link to section %u: expected nvlists\n", sid); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate fcfn = fmd_ckpt_dataptr(ckp, sp); 959*7c478bd9Sstevel@tonic-gate endn = fmd_ckpt_datalim(ckp, sp); 960*7c478bd9Sstevel@tonic-gate 961*7c478bd9Sstevel@tonic-gate for (i = 0; fcfn < endn; i++) { 962*7c478bd9Sstevel@tonic-gate char *data = (char *)fcfn + sp->fcfs_entsize; 963*7c478bd9Sstevel@tonic-gate size_t size = (size_t)fcfn->fcfn_size; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate if (fcfn->fcfn_size > (size_t)((char *)endn - data)) { 966*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "nvlist %u [%d] " 967*7c478bd9Sstevel@tonic-gate "size %u exceeds buffer\n", sid, i, size); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate if ((err = nvlist_xunpack(data, size, &nvl, &fmd.d_nva)) != 0) { 971*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "failed to " 972*7c478bd9Sstevel@tonic-gate "unpack nvlist %u [%d]: %s\n", sid, i, 973*7c478bd9Sstevel@tonic-gate fmd_strerror(err)); 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate fmd_case_insert_suspect(cp, nvl); 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate size = sp->fcfs_entsize + fcfn->fcfn_size; 979*7c478bd9Sstevel@tonic-gate size = P2ROUNDUP(size, sizeof (uint64_t)); 980*7c478bd9Sstevel@tonic-gate fcfn = (fcf_nvl_t *)((uintptr_t)fcfn + size); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate static void 985*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(fmd_ckpt_t *ckp, fmd_module_t *mp, 986*7c478bd9Sstevel@tonic-gate fmd_case_t *cp, fcf_secidx_t sid) 987*7c478bd9Sstevel@tonic-gate { 988*7c478bd9Sstevel@tonic-gate const fcf_sec_t *sp, *dsp; 989*7c478bd9Sstevel@tonic-gate const fcf_buf_t *fcfb; 990*7c478bd9Sstevel@tonic-gate uint_t i, n; 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate if ((sp = fmd_ckpt_secptr(ckp, sid, FCF_SECT_BUFS)) == NULL) { 993*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 994*7c478bd9Sstevel@tonic-gate "invalid link to section %u: expected bufs\n", sid); 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate if (sp->fcfs_size == 0) 998*7c478bd9Sstevel@tonic-gate return; /* empty events section or type none */ 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate fcfb = fmd_ckpt_dataptr(ckp, sp); 1001*7c478bd9Sstevel@tonic-gate n = sp->fcfs_size / sp->fcfs_entsize; 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 1004*7c478bd9Sstevel@tonic-gate dsp = fmd_ckpt_secptr(ckp, fcfb->fcfb_data, FCF_SECT_BUFFER); 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate if (dsp == NULL) { 1007*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "invalid %u " 1008*7c478bd9Sstevel@tonic-gate "buffer link %u\n", sid, fcfb->fcfb_data); 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate 1011*7c478bd9Sstevel@tonic-gate fmd_buf_write((fmd_hdl_t *)mp, cp, 1012*7c478bd9Sstevel@tonic-gate fmd_ckpt_strptr(ckp, fcfb->fcfb_name, "<CORRUPT>"), 1013*7c478bd9Sstevel@tonic-gate ckp->ckp_buf + dsp->fcfs_offset, dsp->fcfs_size); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate fcfb = (fcf_buf_t *)((uintptr_t)fcfb + sp->fcfs_entsize); 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate } 1018*7c478bd9Sstevel@tonic-gate 1019*7c478bd9Sstevel@tonic-gate static void 1020*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_case(fmd_ckpt_t *ckp, fmd_module_t *mp, const fcf_sec_t *sp) 1021*7c478bd9Sstevel@tonic-gate { 1022*7c478bd9Sstevel@tonic-gate const fcf_case_t *fcfc = fmd_ckpt_dataptr(ckp, sp); 1023*7c478bd9Sstevel@tonic-gate const char *uuid = fmd_ckpt_strptr(ckp, fcfc->fcfc_uuid, NULL); 1024*7c478bd9Sstevel@tonic-gate fmd_case_t *cp; 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate if (uuid == NULL || fcfc->fcfc_state > FCF_CASE_CLOSED) { 1027*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, "corrupt %u case uuid " 1028*7c478bd9Sstevel@tonic-gate "and/or state\n", (uint_t)(sp - ckp->ckp_secp)); 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate 1031*7c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate if ((cp = fmd_case_recreate(mp, uuid)) == NULL) { 1034*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 1035*7c478bd9Sstevel@tonic-gate "duplicate case uuid: %s\n", uuid); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfc->fcfc_principal, 1039*7c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_case_insert_principal, cp); 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfc->fcfc_events, 1042*7c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_case_insert_event, cp); 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_suspects(ckp, cp, fcfc->fcfc_suspects); 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate if (fcfc->fcfc_state == FCF_CASE_SOLVED) 1047*7c478bd9Sstevel@tonic-gate fmd_case_transition(cp, FMD_CASE_SOLVED); 1048*7c478bd9Sstevel@tonic-gate else if (fcfc->fcfc_state == FMD_CASE_CLOSED) 1049*7c478bd9Sstevel@tonic-gate fmd_case_transition(cp, FMD_CASE_CLOSED); 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 1052*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(ckp, mp, cp, fcfc->fcfc_bufs); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate static void 1056*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_serd(fmd_ckpt_t *ckp, fmd_module_t *mp, const fcf_sec_t *sp) 1057*7c478bd9Sstevel@tonic-gate { 1058*7c478bd9Sstevel@tonic-gate const fcf_serd_t *fcfd = fmd_ckpt_dataptr(ckp, sp); 1059*7c478bd9Sstevel@tonic-gate uint_t i, n = sp->fcfs_size / sp->fcfs_entsize; 1060*7c478bd9Sstevel@tonic-gate const fcf_sec_t *esp; 1061*7c478bd9Sstevel@tonic-gate const char *s; 1062*7c478bd9Sstevel@tonic-gate 1063*7c478bd9Sstevel@tonic-gate for (i = 0; i < n; i++) { 1064*7c478bd9Sstevel@tonic-gate esp = fmd_ckpt_secptr(ckp, fcfd->fcfd_events, FCF_SECT_EVENTS); 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate if (esp == NULL) { 1067*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 1068*7c478bd9Sstevel@tonic-gate "invalid events link %u\n", fcfd->fcfd_events); 1069*7c478bd9Sstevel@tonic-gate } 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate if ((s = fmd_ckpt_strptr(ckp, fcfd->fcfd_name, NULL)) == NULL) { 1072*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 1073*7c478bd9Sstevel@tonic-gate "serd name %u is corrupt\n", fcfd->fcfd_name); 1074*7c478bd9Sstevel@tonic-gate } 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate fmd_serd_create((fmd_hdl_t *)mp, s, fcfd->fcfd_n, fcfd->fcfd_t); 1077*7c478bd9Sstevel@tonic-gate fmd_module_lock(mp); 1078*7c478bd9Sstevel@tonic-gate 1079*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_events(ckp, fcfd->fcfd_events, 1080*7c478bd9Sstevel@tonic-gate (void (*)(void *, fmd_event_t *))fmd_serd_eng_record, 1081*7c478bd9Sstevel@tonic-gate fmd_serd_eng_lookup(&mp->mod_serds, s)); 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate fmd_module_unlock(mp); 1084*7c478bd9Sstevel@tonic-gate fcfd = (fcf_serd_t *)((uintptr_t)fcfd + sp->fcfs_entsize); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate static void 1089*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_module(fmd_ckpt_t *ckp, fmd_module_t *mp) 1090*7c478bd9Sstevel@tonic-gate { 1091*7c478bd9Sstevel@tonic-gate const fcf_module_t *fcfm = fmd_ckpt_dataptr(ckp, ckp->ckp_modp); 1092*7c478bd9Sstevel@tonic-gate const fcf_sec_t *sp; 1093*7c478bd9Sstevel@tonic-gate uint_t i; 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate if (strcmp(mp->mod_name, fmd_ckpt_strptr(ckp, fcfm->fcfm_name, "")) || 1096*7c478bd9Sstevel@tonic-gate strcmp(mp->mod_path, fmd_ckpt_strptr(ckp, fcfm->fcfm_path, ""))) { 1097*7c478bd9Sstevel@tonic-gate fmd_ckpt_error(ckp, EFMD_CKPT_INVAL, 1098*7c478bd9Sstevel@tonic-gate "checkpoint is not for module %s\n", mp->mod_name); 1099*7c478bd9Sstevel@tonic-gate } 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate for (i = 0; i < ckp->ckp_secs; i++) { 1102*7c478bd9Sstevel@tonic-gate sp = (void *)(ckp->ckp_buf + 1103*7c478bd9Sstevel@tonic-gate ckp->ckp_hdr->fcfh_secoff + ckp->ckp_hdr->fcfh_secsize * i); 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate switch (sp->fcfs_type) { 1106*7c478bd9Sstevel@tonic-gate case FCF_SECT_CASE: 1107*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_case(ckp, mp, sp); 1108*7c478bd9Sstevel@tonic-gate break; 1109*7c478bd9Sstevel@tonic-gate case FCF_SECT_SERD: 1110*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_serd(ckp, mp, sp); 1111*7c478bd9Sstevel@tonic-gate break; 1112*7c478bd9Sstevel@tonic-gate } 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate 1115*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_bufs(ckp, mp, NULL, fcfm->fcfm_bufs); 1116*7c478bd9Sstevel@tonic-gate mp->mod_gen = ckp->ckp_hdr->fcfh_cgen; 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* 1120*7c478bd9Sstevel@tonic-gate * Restore a checkpoint for the specified module. Any errors which occur 1121*7c478bd9Sstevel@tonic-gate * during restore will call fmd_ckpt_error() or trigger an fmd_api_error(), 1122*7c478bd9Sstevel@tonic-gate * either of which will automatically unlock the module and trigger an abort. 1123*7c478bd9Sstevel@tonic-gate */ 1124*7c478bd9Sstevel@tonic-gate void 1125*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore(fmd_module_t *mp) 1126*7c478bd9Sstevel@tonic-gate { 1127*7c478bd9Sstevel@tonic-gate fmd_ckpt_t ckp; 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate if (mp->mod_stats->ms_ckpt_restore.fmds_value.bool == FMD_B_FALSE) 1130*7c478bd9Sstevel@tonic-gate return; /* never restore checkpoints for this module */ 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore begin %s", mp->mod_name)); 1133*7c478bd9Sstevel@tonic-gate 1134*7c478bd9Sstevel@tonic-gate if (fmd_ckpt_open(&ckp, mp) == -1) { 1135*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) 1136*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_OPEN, "can't open %s", ckp.ckp_src); 1137*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore end %s", mp->mod_name)); 1138*7c478bd9Sstevel@tonic-gate return; 1139*7c478bd9Sstevel@tonic-gate } 1140*7c478bd9Sstevel@tonic-gate 1141*7c478bd9Sstevel@tonic-gate ASSERT(!fmd_module_locked(mp)); 1142*7c478bd9Sstevel@tonic-gate fmd_ckpt_restore_module(&ckp, mp); 1143*7c478bd9Sstevel@tonic-gate fmd_ckpt_destroy(&ckp); 1144*7c478bd9Sstevel@tonic-gate fmd_module_clrdirty(mp); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "ckpt restore end %s", mp->mod_name)); 1147*7c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_CKPT, "restored checkpoint of %s\n", mp->mod_name); 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate /* 1151*7c478bd9Sstevel@tonic-gate * Delete the module's checkpoint file. This is used by the ckpt.zero property 1152*7c478bd9Sstevel@tonic-gate * code or by the fmadm reset RPC service path to force a checkpoint delete. 1153*7c478bd9Sstevel@tonic-gate */ 1154*7c478bd9Sstevel@tonic-gate void 1155*7c478bd9Sstevel@tonic-gate fmd_ckpt_delete(fmd_module_t *mp) 1156*7c478bd9Sstevel@tonic-gate { 1157*7c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), 1160*7c478bd9Sstevel@tonic-gate "%s/%s", mp->mod_ckpt, mp->mod_name); 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "delete %s ckpt", mp->mod_name)); 1163*7c478bd9Sstevel@tonic-gate 1164*7c478bd9Sstevel@tonic-gate if (unlink(path) != 0 && errno != ENOENT) 1165*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_DELETE, "failed to delete %s", path); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * Move aside the module's checkpoint file if checkpoint restore has failed. 1170*7c478bd9Sstevel@tonic-gate * We rename the file rather than deleting it in the hopes that someone might 1171*7c478bd9Sstevel@tonic-gate * send it to us for post-mortem analysis of whether we have a checkpoint bug. 1172*7c478bd9Sstevel@tonic-gate */ 1173*7c478bd9Sstevel@tonic-gate void 1174*7c478bd9Sstevel@tonic-gate fmd_ckpt_rename(fmd_module_t *mp) 1175*7c478bd9Sstevel@tonic-gate { 1176*7c478bd9Sstevel@tonic-gate char src[PATH_MAX], dst[PATH_MAX]; 1177*7c478bd9Sstevel@tonic-gate 1178*7c478bd9Sstevel@tonic-gate (void) snprintf(src, sizeof (src), "%s/%s", mp->mod_ckpt, mp->mod_name); 1179*7c478bd9Sstevel@tonic-gate (void) snprintf(dst, sizeof (dst), "%s-", src); 1180*7c478bd9Sstevel@tonic-gate 1181*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_CKPT, "rename %s ckpt", mp->mod_name)); 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate if (rename(src, dst) != 0 && errno != ENOENT) 1184*7c478bd9Sstevel@tonic-gate fmd_error(EFMD_CKPT_DELETE, "failed to rename %s", src); 1185*7c478bd9Sstevel@tonic-gate } 1186