/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <strings.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <fmd_module.h>
#include <fmd_error.h>
#include <fmd_alloc.h>
#include <fmd_case.h>
#include <fmd_serd.h>
#include <fmd_subr.h>
#include <fmd_conf.h>
#include <fmd_event.h>
#include <fmd_log.h>
#include <fmd_api.h>
#include <fmd_ckpt.h>
#include <fmd.h>
/*
* The fmd_ckpt_t structure is used to manage all of the state needed by the
* various subroutines that save and restore checkpoints. The structure is
* initialized using fmd_ckpt_create() or fmd_ckpt_open() and is destroyed
* by fmd_ckpt_destroy(). Refer to the subroutines below for more details.
*/
typedef struct fmd_ckpt {
} fmd_ckpt_t;
typedef struct fmd_ckpt_desc {
/*
* Table of FCF section descriptions. Here we record the minimum size for each
* section (for use during restore) and the expected entry size and alignment
* for each section (for use during both checkpoint and restore).
*/
{ 0, 0, sizeof (uint8_t) }, /* NONE */
{ 1, 0, sizeof (char) }, /* STRTAB */
{ 0, 0, _MAX_ALIGNMENT }, /* BUFFER */
};
static int
{
}
/*PRINTFLIKE2*/
static int
{
return (fmd_set_errno(EFMD_CKPT_INVAL));
}
static int
{
uint_t i;
int err;
return (-1); /* failed to open checkpoint file */
return (fmd_set_errno(err));
}
return (fmd_set_errno(err));
}
/*
* Once we've read in a consistent copy of the FCF file and we're sure
* the header can be accessed, go through it and make sure everything
* is valid. We also check that unused bits are zero so we can expand
* to use them safely in the future and support old files if needed.
*/
FCF_MAG_STRING, FCF_MAG_STRLEN) != 0)
}
for (i = FCF_ID_PAD; i < FCF_ID_SIZE; i++) {
return (fmd_ckpt_inval(ckp,
"bad checkpoint padding at id[%d]", i));
}
}
return (fmd_ckpt_inval(ckp,
}
/*
* Once the header is validated, iterate over the section headers
* ensuring that each one is valid w.r.t. offset, alignment, and size.
* We also pick up the string table pointer during this pass.
*/
if (sp->fcfs_flags != 0) {
}
}
}
if (sp->fcfs_entsize != 0 &&
}
"size or offset\n", i));
}
sizeof (_fmd_ckpt_sections[0])) {
}
}
"size or entsize\n", i));
}
case FCF_SECT_STRTAB:
"tables are present in checkpoint file\n"));
}
"is missing terminating nul byte\n", i));
}
break;
case FCF_SECT_MODULE:
"sects are present in checkpoint file\n"));
}
break;
}
}
/*
* Ensure that the first section is an empty one of type FCF_SECT_NONE.
* This is done to ensure that links can use index 0 as a null section.
*/
}
return (fmd_ckpt_inval(ckp,
"no module section found in file\n"));
}
return (0);
}
static void
{
}
/*
* fmd_ckpt_error() is used as a wrapper around fmd_error() for ckpt routines.
* It calls fmd_module_unlock() on behalf of its caller, logs the error, and
* then aborts the API call and the surrounding module entry point by doing an
* fmd_module_abort(), which longjmps to the place where we entered the module.
* Depending on the type of error and conf settings, we will reset or fail.
*/
/*PRINTFLIKE3*/
static void
{
if (fmd_module_locked(mp))
}
static fcf_secidx_t
{
/*
* If the data pointer is non-NULL, copy the data to our buffer; else
* the caller is responsible for doing so and updating ckp->ckp_ptr.
*/
}
}
static fcf_stridx_t
{
return (idx);
}
static int
{
/*
* We've added up all the sections by now: add two more for SECT_NONE
* and SECT_STRTAB, and add the size of the section header table and
* string table to the total size. We know that the fcf_hdr_t is
* aligned so that that fcf_sec_t's can follow it, and that fcf_sec_t
* is aligned so that any section can follow it, so no extra padding
* bytes need to be allocated between any of these items.
*/
return (-1); /* errno is set for us */
return (0);
}
static int
{
/*
* Before committing the checkpoint, we assert that fmd_ckpt_t's sizes
* and current pointer locations all add up appropriately. Any ASSERTs
* which trip here likely indicate an inconsistency in the code for the
* reservation pass and the buffer update pass of the FCF subroutines.
*/
return (-1); /* errno is set for us */
}
static void
{
if (size != 0) {
}
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
static void
{
}
}
static void
{
uint_t n;
return; /* do not checkpoint cases from remote transports */
if (cip->ci_nsuspects != 0)
}
}
static void
{
uint_t n;
return; /* do not checkpoint cases from remote transports */
}
sizeof (fcf_event_t));
}
}
if (cip->ci_nsuspects != 0) {
}
case FMD_CASE_UNSOLVED:
break;
case FMD_CASE_SOLVED:
break;
case FMD_CASE_CLOSE_WAIT:
break;
default:
fmd_panic("case %p (%s) has invalid state %u",
}
}
static void
{
uint_t n;
}
static void
{
uint_t n;
}
}
FCF_SECT_MODULE, sizeof (fcf_module_t));
}
void
{
int err;
/*
* If checkpointing is disabled for the module, just return. We must
* commit the module state anyway to transition pending log events.
*/
return;
}
return; /* no checkpoint is necessary for this module */
/*
* If the per-module checkpoint directory isn't found or isn't of type
* directory, move aside whatever is there (if anything) and attempt
* to mkdir(2) a new module checkpoint directory. If this fails, we
* have no choice but to abort the checkpoint and try again later.
*/
return; /* return without clearing dirty bits */
}
}
/*
* Create a temporary file to write out the checkpoint into, and create
* a fmd_ckpt_t structure to manage construction of the checkpoint. We
* then figure out how much space will be required, and allocate it.
*/
return;
}
return;
}
/*
* Fill in the checkpoint content, write it to disk, sync it, and then
* atomically rename it to the destination path. If this fails, we
* have no choice but to leave all our dirty bits set and return.
*/
if (err != 0) {
return; /* return without clearing dirty bits */
}
}
/*
* Utility function to retrieve a pointer to a section's header and verify that
* it is of the expected type or it is a FCF_SECT_NONE reference.
*/
static const fcf_sec_t *
{
}
/*
* Utility function to retrieve the data pointer for a particular section. The
* validity of the header values has already been checked by fmd_ckpt_open().
*/
static const void *
{
}
/*
* Utility function to retrieve the end of the data region for a particular
* section. The validity of this value has been confirmed by fmd_ckpt_open().
*/
static const void *
{
}
/*
* Utility function to retrieve a string pointer (fcf_stridx_t). If the string
* index is valid, the string data is returned; otherwise 'defstr' is returned.
*/
static const char *
{
}
static void
{
uint_t i, n;
"invalid link to section %u: expected events\n", sid);
}
return; /* empty events section or type none */
/*
* Hold the reader lock on log pointers to block log rotation during
* the section restore so that we can safely insert refs to d_errlog.
*/
for (i = 0; i < n; i++) {
else
}
}
static int
{
int err, i;
"invalid link to section %u: expected nvlists\n", sid);
}
}
"unpack nvlist %u [%d]: %s\n", sid, i,
fmd_strerror(err));
}
}
return (i);
}
static void
{
uint_t i, n;
"invalid link to section %u: expected bufs\n", sid);
}
return; /* empty events section or type none */
for (i = 0; i < n; i++) {
}
}
}
static void
{
int n;
}
"duplicate case uuid: %s\n", uuid);
}
/*
* Once solved, treat suspects from resource cache as master copy.
*
* If !fmd.d_running, this module must be a builtin, and so we don't
* want to restore suspects or call fmd_case_transition_update() at this
* stage. The suspects will be added later from the resource cache.
* Calling fmd_case_transition("SOLVED") is OK here as the state is
* already solved, so all it does is update the case flags.
*/
}
static void
{
const char *s;
for (i = 0; i < n; i++) {
}
}
(void (*)(void *, fmd_event_t *))fmd_serd_eng_record,
}
}
static void
{
uint_t i;
}
case FCF_SECT_CASE:
break;
case FCF_SECT_SERD:
break;
}
}
}
/*
* Restore a checkpoint for the specified module. Any errors which occur
* during restore will call fmd_ckpt_error() or trigger an fmd_api_error(),
* either of which will automatically unlock the module and trigger an abort.
*/
void
{
return; /* never restore checkpoints for this module */
return;
}
}
/*
* Delete the module's checkpoint file. This is used by the ckpt.zero property
* code or by the fmadm reset RPC service path to force a checkpoint delete.
*/
void
{
}
/*
* Move aside the module's checkpoint file if checkpoint restore has failed.
* We rename the file rather than deleting it in the hopes that someone might
* send it to us for post-mortem analysis of whether we have a checkpoint bug.
*/
void
{
}