10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*1052Sdilpreet * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * FMD Log File Subsystem 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * Events are written to one of two log files as they are received or created; 330Sstevel@tonic-gate * the error log tracks all ereport.* events received on the inbound event 340Sstevel@tonic-gate * transport, and the fault log tracks all list.* events generated by fmd or 350Sstevel@tonic-gate * its client modules. In addition, we use the same log file format to cache 360Sstevel@tonic-gate * state and events associated with ASRUs that are named in a diagnosis. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * The log files use the exacct format manipulated by libexacct(3LIB) and 390Sstevel@tonic-gate * originally defined in PSARC 1999/119. However, the exacct library was 400Sstevel@tonic-gate * designed primarily for read-only clients and without the synchronous i/o 410Sstevel@tonic-gate * considerations and seeking required for fmd, so we use libexacct here only 420Sstevel@tonic-gate * to read and write the file headers and to pack data from memory into a file 430Sstevel@tonic-gate * bytestream. All of the i/o and file offset manipulations are performed by 440Sstevel@tonic-gate * the fmd code below. Our exacct file management uses the following grammar: 450Sstevel@tonic-gate * 460Sstevel@tonic-gate * file := hdr toc event* 47*1052Sdilpreet * hdr := EXD_FMA_LABEL EXD_FMA_VERSION EXD_FMA_OSREL EXD_FMA_OSVER 48*1052Sdilpreet * EXD_FMA_PLAT EXD_FMA_UUID 490Sstevel@tonic-gate * toc := EXD_FMA_OFFSET 50*1052Sdilpreet * event := EXD_FMA_TODSEC EXD_FMA_TODNSEC EXD_FMA_NVLIST evref* or legacy evref 51*1052Sdilpreet * evref := EXD_FMA_UUID EXD_FMA_OFFSET 52*1052Sdilpreet * legacy evref := EXD_FMA_MAJOR EXD_FMA_MINOR EXD_FMA_INODE EXD_FMA_OFFSET 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * Any event can be uniquely identified by the tuple (file, offset) where file 55*1052Sdilpreet * is encoded as (uuid) when we are cross-linking files. For legacy file 56*1052Sdilpreet * formats we still support encoding the reference as (major, minor, inode). 57*1052Sdilpreet * Note that we break out of the file's dev_t into its two 32-bit components to 580Sstevel@tonic-gate * permit development of either 32-bit or 64-bit log readers and writers; the 590Sstevel@tonic-gate * LFS APIs do not yet export a 64-bit dev_t to fstat64(), so there is no way 600Sstevel@tonic-gate * for a 32-bit application to retrieve and store a 64-bit dev_t. 610Sstevel@tonic-gate * 620Sstevel@tonic-gate * In order to replay events in the event of an fmd crash, events are initially 630Sstevel@tonic-gate * written to the error log using the group catalog tag EXD_GROUP_RFMA by the 640Sstevel@tonic-gate * fmd_log_append() function. Later, once an event transitions from the 650Sstevel@tonic-gate * received state to one of its other states (see fmd_event.c for details), 660Sstevel@tonic-gate * fmd_log_commit() is used to overwrite the tag with EXD_GROUP_FMA, indicating 670Sstevel@tonic-gate * that the event is fully processed and no longer needs to be replayed. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate #include <sys/types.h> 710Sstevel@tonic-gate #include <sys/mkdev.h> 720Sstevel@tonic-gate #include <sys/statvfs.h> 730Sstevel@tonic-gate #include <sys/fm/protocol.h> 740Sstevel@tonic-gate #include <sys/exacct_impl.h> 75*1052Sdilpreet #include <uuid/uuid.h> 760Sstevel@tonic-gate 770Sstevel@tonic-gate #include <unistd.h> 780Sstevel@tonic-gate #include <limits.h> 790Sstevel@tonic-gate #include <fcntl.h> 800Sstevel@tonic-gate #include <ctype.h> 810Sstevel@tonic-gate 820Sstevel@tonic-gate #include <fmd_alloc.h> 830Sstevel@tonic-gate #include <fmd_error.h> 840Sstevel@tonic-gate #include <fmd_string.h> 850Sstevel@tonic-gate #include <fmd_event.h> 860Sstevel@tonic-gate #include <fmd_conf.h> 870Sstevel@tonic-gate #include <fmd_subr.h> 880Sstevel@tonic-gate #include <fmd_case.h> 890Sstevel@tonic-gate #include <fmd_log.h> 900Sstevel@tonic-gate 910Sstevel@tonic-gate #include <fmd.h> 920Sstevel@tonic-gate 930Sstevel@tonic-gate #define CAT_FMA_RGROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_RFMA) 940Sstevel@tonic-gate #define CAT_FMA_GROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_FMA) 950Sstevel@tonic-gate 960Sstevel@tonic-gate #define CAT_FMA_LABEL (EXT_STRING | EXC_DEFAULT | EXD_FMA_LABEL) 970Sstevel@tonic-gate #define CAT_FMA_VERSION (EXT_STRING | EXC_DEFAULT | EXD_FMA_VERSION) 980Sstevel@tonic-gate #define CAT_FMA_OSREL (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSREL) 990Sstevel@tonic-gate #define CAT_FMA_OSVER (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSVER) 1000Sstevel@tonic-gate #define CAT_FMA_PLAT (EXT_STRING | EXC_DEFAULT | EXD_FMA_PLAT) 101*1052Sdilpreet #define CAT_FMA_UUID (EXT_STRING | EXC_DEFAULT | EXD_FMA_UUID) 1020Sstevel@tonic-gate #define CAT_FMA_TODSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODSEC) 1030Sstevel@tonic-gate #define CAT_FMA_TODNSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODNSEC) 1040Sstevel@tonic-gate #define CAT_FMA_NVLIST (EXT_RAW | EXC_DEFAULT | EXD_FMA_NVLIST) 1050Sstevel@tonic-gate #define CAT_FMA_MAJOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MAJOR) 1060Sstevel@tonic-gate #define CAT_FMA_MINOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MINOR) 1070Sstevel@tonic-gate #define CAT_FMA_INODE (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_INODE) 1080Sstevel@tonic-gate #define CAT_FMA_OFFSET (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_OFFSET) 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static ssize_t 1110Sstevel@tonic-gate fmd_log_write(fmd_log_t *lp, const void *buf, size_t n) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate ssize_t resid = n; 1140Sstevel@tonic-gate ssize_t len; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lp->log_lock)); 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate while (resid != 0) { 1190Sstevel@tonic-gate if ((len = write(lp->log_fd, buf, resid)) <= 0) 1200Sstevel@tonic-gate break; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate resid -= len; 1230Sstevel@tonic-gate buf = (char *)buf + len; 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (resid == n && n != 0) 1270Sstevel@tonic-gate return (-1); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate return (n - resid); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate static int 1330Sstevel@tonic-gate fmd_log_write_hdr(fmd_log_t *lp, const char *tag) 1340Sstevel@tonic-gate { 135*1052Sdilpreet ea_object_t hdr, toc, i0, i1, i2, i3, i4, i5, i6; 1360Sstevel@tonic-gate const char *osrel, *osver, *plat; 1370Sstevel@tonic-gate off64_t off = 0; 1380Sstevel@tonic-gate int err = 0; 139*1052Sdilpreet uuid_t uuid; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "osrelease", &osrel); 1420Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "osversion", &osver); 1430Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "platform", &plat); 144*1052Sdilpreet (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &lp->log_uuidlen); 145*1052Sdilpreet 146*1052Sdilpreet lp->log_uuid = fmd_zalloc(lp->log_uuidlen + 1, FMD_SLEEP); 147*1052Sdilpreet uuid_generate(uuid); 148*1052Sdilpreet uuid_unparse(uuid, lp->log_uuid); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate err |= ea_set_group(&hdr, CAT_FMA_GROUP); 1510Sstevel@tonic-gate err |= ea_set_group(&toc, CAT_FMA_GROUP); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate err |= ea_set_item(&i0, CAT_FMA_LABEL, tag, 0); 1540Sstevel@tonic-gate err |= ea_set_item(&i1, CAT_FMA_VERSION, fmd.d_version, 0); 1550Sstevel@tonic-gate err |= ea_set_item(&i2, CAT_FMA_OSREL, osrel, 0); 1560Sstevel@tonic-gate err |= ea_set_item(&i3, CAT_FMA_OSVER, osver, 0); 1570Sstevel@tonic-gate err |= ea_set_item(&i4, CAT_FMA_PLAT, plat, 0); 158*1052Sdilpreet err |= ea_set_item(&i5, CAT_FMA_UUID, lp->log_uuid, 0); 159*1052Sdilpreet err |= ea_set_item(&i6, CAT_FMA_OFFSET, &off, 0); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i0); 1620Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i1); 1630Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i2); 1640Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i3); 1650Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i4); 166*1052Sdilpreet (void) ea_attach_to_group(&hdr, &i5); 167*1052Sdilpreet (void) ea_attach_to_group(&toc, &i6); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate if (err == 0) { 1700Sstevel@tonic-gate size_t hdr_size = ea_pack_object(&hdr, NULL, 0); 1710Sstevel@tonic-gate size_t toc_size = ea_pack_object(&toc, NULL, 0); 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate size_t size = hdr_size + toc_size; 1740Sstevel@tonic-gate void *buf = fmd_alloc(size, FMD_SLEEP); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate (void) ea_pack_object(&hdr, buf, hdr_size); 1770Sstevel@tonic-gate (void) ea_pack_object(&toc, (char *)buf + hdr_size, toc_size); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate if ((lp->log_off = lseek64(lp->log_fd, 0, SEEK_END)) == -1L) 1800Sstevel@tonic-gate fmd_panic("failed to seek log %s", lp->log_name); 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if (fmd_log_write(lp, buf, size) != size) 1830Sstevel@tonic-gate err = errno; /* save errno for fmd_set_errno() below */ 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate fmd_free(buf, size); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate lp->log_toc = lp->log_off + hdr_size; 1880Sstevel@tonic-gate lp->log_beg = lp->log_off + hdr_size + toc_size; 1890Sstevel@tonic-gate lp->log_off = lp->log_off + hdr_size + toc_size; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if (lp->log_off != lseek64(lp->log_fd, 0, SEEK_END)) 1920Sstevel@tonic-gate fmd_panic("eof off != log_off 0x%llx\n", lp->log_off); 1930Sstevel@tonic-gate } else 1940Sstevel@tonic-gate err = EFMD_LOG_EXACCT; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate (void) ea_free_item(&i0, EUP_ALLOC); 1970Sstevel@tonic-gate (void) ea_free_item(&i1, EUP_ALLOC); 1980Sstevel@tonic-gate (void) ea_free_item(&i2, EUP_ALLOC); 1990Sstevel@tonic-gate (void) ea_free_item(&i3, EUP_ALLOC); 2000Sstevel@tonic-gate (void) ea_free_item(&i4, EUP_ALLOC); 2010Sstevel@tonic-gate (void) ea_free_item(&i5, EUP_ALLOC); 202*1052Sdilpreet (void) ea_free_item(&i6, EUP_ALLOC); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate return (err ? fmd_set_errno(err) : 0); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate static int 2080Sstevel@tonic-gate fmd_log_check_err(fmd_log_t *lp, int err, const char *msg) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate int eaerr = ea_error(); 2110Sstevel@tonic-gate char buf[BUFSIZ]; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", 2140Sstevel@tonic-gate lp->log_name, msg, eaerr != EXR_OK ? 2150Sstevel@tonic-gate fmd_ea_strerror(eaerr) : "catalog tag mismatch"); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate fmd_error(err, buf); 2180Sstevel@tonic-gate return (fmd_set_errno(err)); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate static int 2220Sstevel@tonic-gate fmd_log_check_hdr(fmd_log_t *lp, const char *tag) 2230Sstevel@tonic-gate { 2240Sstevel@tonic-gate int got_version = 0, got_label = 0; 2250Sstevel@tonic-gate ea_object_t *grp, *obj; 2260Sstevel@tonic-gate off64_t hdr_off, hdr_size; 2270Sstevel@tonic-gate int dvers, fvers; 2280Sstevel@tonic-gate const char *p; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate ea_clear(&lp->log_ea); /* resync exacct file */ 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate if ((hdr_off = lseek64(lp->log_fd, 0, SEEK_CUR)) == -1L) 2330Sstevel@tonic-gate fmd_panic("failed to seek log %s", lp->log_name); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Read the first group of log meta-data: the write-once read-only 2370Sstevel@tonic-gate * file header. We read all records in this group, ignoring all but 2380Sstevel@tonic-gate * the VERSION and LABEL, which are required and must be verified. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL || 2410Sstevel@tonic-gate grp->eo_catalog != CAT_FMA_GROUP) { 2420Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2430Sstevel@tonic-gate return (fmd_log_check_err(lp, EFMD_LOG_INVAL, 2440Sstevel@tonic-gate "invalid fma hdr record group")); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) { 2480Sstevel@tonic-gate switch (obj->eo_catalog) { 2490Sstevel@tonic-gate case CAT_FMA_VERSION: 2500Sstevel@tonic-gate for (dvers = 0, p = fmd.d_version; 2510Sstevel@tonic-gate *p != '\0'; p++) { 2520Sstevel@tonic-gate if (isdigit(*p)) 2530Sstevel@tonic-gate dvers = dvers * 10 + (*p - '0'); 2540Sstevel@tonic-gate else 2550Sstevel@tonic-gate break; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate for (fvers = 0, p = obj->eo_item.ei_string; 2590Sstevel@tonic-gate *p != '\0'; p++) { 2600Sstevel@tonic-gate if (isdigit(*p)) 2610Sstevel@tonic-gate fvers = fvers * 10 + (*p - '0'); 2620Sstevel@tonic-gate else 2630Sstevel@tonic-gate break; 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate if (fvers > dvers) { 2670Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: log version " 2680Sstevel@tonic-gate "%s is not supported by this daemon\n", 2690Sstevel@tonic-gate lp->log_name, obj->eo_item.ei_string); 2700Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2710Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_VERSION)); 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate got_version++; 2750Sstevel@tonic-gate break; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate case CAT_FMA_LABEL: 2780Sstevel@tonic-gate if (strcmp(obj->eo_item.ei_string, tag) != 0) { 2790Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: log tag '%s' " 2800Sstevel@tonic-gate "does not matched expected tag '%s'\n", 2810Sstevel@tonic-gate lp->log_name, obj->eo_item.ei_string, tag); 2820Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2830Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_INVAL)); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate got_label++; 2860Sstevel@tonic-gate break; 287*1052Sdilpreet case CAT_FMA_UUID: 288*1052Sdilpreet lp->log_uuid = fmd_strdup(obj->eo_item.ei_string, 289*1052Sdilpreet FMD_SLEEP); 290*1052Sdilpreet lp->log_uuidlen = strlen(lp->log_uuid); 291*1052Sdilpreet break; 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate hdr_size = ea_pack_object(grp, NULL, 0); 2960Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate if (!got_version || !got_label) { 2990Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: fmd hdr record group did not " 3000Sstevel@tonic-gate "include mandatory version and/or label\n", lp->log_name); 3010Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_INVAL)); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * Read the second group of log meta-data: the table of contents. We 3060Sstevel@tonic-gate * expect this group to contain an OFFSET object indicating the current 3070Sstevel@tonic-gate * value of log_skip. We save this in our fmd_log_t and then return. 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL || 3100Sstevel@tonic-gate grp->eo_catalog != CAT_FMA_GROUP || grp->eo_group.eg_nobjs < 1 || 3110Sstevel@tonic-gate grp->eo_group.eg_objs->eo_catalog != CAT_FMA_OFFSET) { 3120Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 3130Sstevel@tonic-gate return (fmd_log_check_err(lp, EFMD_LOG_INVAL, 3140Sstevel@tonic-gate "invalid fma toc record group")); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate lp->log_toc = hdr_off + hdr_size; 3180Sstevel@tonic-gate lp->log_beg = hdr_off + hdr_size + ea_pack_object(grp, NULL, 0); 3190Sstevel@tonic-gate lp->log_off = lseek64(lp->log_fd, 0, SEEK_END); 3200Sstevel@tonic-gate lp->log_skip = grp->eo_group.eg_objs->eo_item.ei_uint64; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate if (lp->log_skip > lp->log_off) { 3230Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: skip %llx exceeds file size; " 3240Sstevel@tonic-gate "resetting to zero\n", lp->log_name, lp->log_skip); 3250Sstevel@tonic-gate lp->log_skip = 0; 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 3290Sstevel@tonic-gate return (0); 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate static int 3330Sstevel@tonic-gate fmd_log_open_exacct(fmd_log_t *lp, int aflags, int oflags) 3340Sstevel@tonic-gate { 3350Sstevel@tonic-gate int fd = dup(lp->log_fd); 3360Sstevel@tonic-gate const char *creator; 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "log.creator", &creator); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (ea_fdopen(&lp->log_ea, fd, creator, aflags, oflags) != 0) { 3410Sstevel@tonic-gate fmd_error(EFMD_LOG_EXACCT, "%s: failed to open log file: %s\n", 3420Sstevel@tonic-gate lp->log_name, fmd_ea_strerror(ea_error())); 3430Sstevel@tonic-gate (void) close(fd); 3440Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_EXACCT)); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate lp->log_flags |= FMD_LF_EAOPEN; 3480Sstevel@tonic-gate return (0); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate static fmd_log_t * 3520Sstevel@tonic-gate fmd_log_xopen(const char *root, const char *name, const char *tag, int oflags) 3530Sstevel@tonic-gate { 3540Sstevel@tonic-gate fmd_log_t *lp = fmd_zalloc(sizeof (fmd_log_t), FMD_SLEEP); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate char buf[PATH_MAX]; 3570Sstevel@tonic-gate size_t len; 3580Sstevel@tonic-gate int err; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate (void) pthread_mutex_init(&lp->log_lock, NULL); 3610Sstevel@tonic-gate (void) pthread_cond_init(&lp->log_cv, NULL); 3620Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate len = strlen(root) + strlen(name) + 2; /* for "/" and "\0" */ 3650Sstevel@tonic-gate lp->log_name = fmd_alloc(len, FMD_SLEEP); 3660Sstevel@tonic-gate (void) snprintf(lp->log_name, len, "%s/%s", root, name); 3670Sstevel@tonic-gate lp->log_tag = fmd_strdup(tag, FMD_SLEEP); 3680Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "log.minfree", &lp->log_minfree); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (strcmp(lp->log_tag, FMD_LOG_ERROR) == 0) 3710Sstevel@tonic-gate lp->log_flags |= FMD_LF_REPLAY; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate top: 3740Sstevel@tonic-gate if ((lp->log_fd = open64(lp->log_name, oflags, 0644)) == -1 || 3750Sstevel@tonic-gate fstat64(lp->log_fd, &lp->log_stat) == -1) { 3760Sstevel@tonic-gate fmd_error(EFMD_LOG_OPEN, "failed to open log %s", lp->log_name); 3770Sstevel@tonic-gate fmd_log_close(lp); 3780Sstevel@tonic-gate return (NULL); 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * If our open() created the log file, use libexacct to write a header 3830Sstevel@tonic-gate * and position the file just after the header (EO_TAIL). If the log 3840Sstevel@tonic-gate * file already existed, use libexacct to validate the header and again 3850Sstevel@tonic-gate * position the file just after the header (EO_HEAD). Note that we lie 3860Sstevel@tonic-gate * to libexacct about 'oflags' in order to achieve the desired result. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate if (lp->log_stat.st_size == 0) { 3890Sstevel@tonic-gate err = fmd_log_open_exacct(lp, EO_VALID_HDR | EO_TAIL, 3900Sstevel@tonic-gate O_CREAT | O_WRONLY) || fmd_log_write_hdr(lp, tag); 3910Sstevel@tonic-gate } else { 3920Sstevel@tonic-gate err = fmd_log_open_exacct(lp, EO_VALID_HDR | EO_HEAD, 3930Sstevel@tonic-gate O_RDONLY) || fmd_log_check_hdr(lp, tag); 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * If ea_fdopen() failed and the log was pre-existing, attempt to move 3980Sstevel@tonic-gate * it aside and start a new one. If we created the log but failed to 3990Sstevel@tonic-gate * initialize it, then we have no choice but to give up (e.g. EROFS). 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate if (err) { 4020Sstevel@tonic-gate fmd_error(EFMD_LOG_OPEN, 4030Sstevel@tonic-gate "failed to initialize log %s", lp->log_name); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if (lp->log_flags & FMD_LF_EAOPEN) { 4060Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_EAOPEN; 4070Sstevel@tonic-gate (void) ea_close(&lp->log_ea); 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate (void) close(lp->log_fd); 4110Sstevel@tonic-gate lp->log_fd = -1; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate if (lp->log_stat.st_size != 0 && snprintf(buf, 4140Sstevel@tonic-gate sizeof (buf), "%s-", lp->log_name) < PATH_MAX && 4150Sstevel@tonic-gate rename(lp->log_name, buf) == 0) { 4160Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "mv %s to %s", lp->log_name, buf)); 4170Sstevel@tonic-gate if (oflags & O_CREAT) 4180Sstevel@tonic-gate goto top; 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate fmd_log_close(lp); 4220Sstevel@tonic-gate return (NULL); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate lp->log_refs++; 4260Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate return (lp); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate fmd_log_t * 4320Sstevel@tonic-gate fmd_log_tryopen(const char *root, const char *name, const char *tag) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate return (fmd_log_xopen(root, name, tag, O_RDWR | O_SYNC)); 4350Sstevel@tonic-gate } 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate fmd_log_t * 4380Sstevel@tonic-gate fmd_log_open(const char *root, const char *name, const char *tag) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate return (fmd_log_xopen(root, name, tag, O_RDWR | O_CREAT | O_SYNC)); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate void 4440Sstevel@tonic-gate fmd_log_close(fmd_log_t *lp) 4450Sstevel@tonic-gate { 4460Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lp->log_lock)); 4470Sstevel@tonic-gate ASSERT(lp->log_refs == 0); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate if ((lp->log_flags & FMD_LF_EAOPEN) && ea_close(&lp->log_ea) != 0) { 4500Sstevel@tonic-gate fmd_error(EFMD_LOG_CLOSE, "failed to close log %s: %s\n", 4510Sstevel@tonic-gate lp->log_name, fmd_ea_strerror(ea_error())); 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate if (lp->log_fd >= 0 && close(lp->log_fd) != 0) { 4550Sstevel@tonic-gate fmd_error(EFMD_LOG_CLOSE, 4560Sstevel@tonic-gate "failed to close log %s", lp->log_name); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate fmd_strfree(lp->log_name); 4600Sstevel@tonic-gate fmd_strfree(lp->log_tag); 461*1052Sdilpreet if (lp->log_uuid != NULL) 462*1052Sdilpreet fmd_free(lp->log_uuid, lp->log_uuidlen + 1); 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate fmd_free(lp, sizeof (fmd_log_t)); 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate void 4680Sstevel@tonic-gate fmd_log_hold_pending(fmd_log_t *lp) 4690Sstevel@tonic-gate { 4700Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate lp->log_refs++; 4730Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 4760Sstevel@tonic-gate lp->log_pending++; 4770Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate void 4840Sstevel@tonic-gate fmd_log_hold(fmd_log_t *lp) 4850Sstevel@tonic-gate { 4860Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 4870Sstevel@tonic-gate lp->log_refs++; 4880Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 4890Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate void 4930Sstevel@tonic-gate fmd_log_rele(fmd_log_t *lp) 4940Sstevel@tonic-gate { 4950Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 4960Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate if (--lp->log_refs == 0) 4990Sstevel@tonic-gate fmd_log_close(lp); 5000Sstevel@tonic-gate else 5010Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate void 5050Sstevel@tonic-gate fmd_log_append(fmd_log_t *lp, fmd_event_t *e, fmd_case_t *cp) 5060Sstevel@tonic-gate { 5070Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 5080Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 5090Sstevel@tonic-gate int err = 0; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate ea_object_t grp0, grp1, i0, i1, i2, *items; 512*1052Sdilpreet ea_object_t **fe = NULL; 513*1052Sdilpreet size_t nvsize, easize, itsize, frsize; 5140Sstevel@tonic-gate char *nvbuf, *eabuf; 5150Sstevel@tonic-gate statvfs64_t stv; 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->ev_lock); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate ASSERT(ep->ev_flags & FMD_EVF_VOLATILE); 5200Sstevel@tonic-gate ASSERT(ep->ev_log == NULL); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate (void) nvlist_size(ep->ev_nvl, &nvsize, NV_ENCODE_XDR); 5230Sstevel@tonic-gate nvbuf = fmd_alloc(nvsize, FMD_SLEEP); 5240Sstevel@tonic-gate (void) nvlist_pack(ep->ev_nvl, &nvbuf, &nvsize, NV_ENCODE_XDR, 0); 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) 5270Sstevel@tonic-gate err |= ea_set_group(&grp0, CAT_FMA_RGROUP); 5280Sstevel@tonic-gate else 5290Sstevel@tonic-gate err |= ea_set_group(&grp0, CAT_FMA_GROUP); 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate err |= ea_set_item(&i0, CAT_FMA_TODSEC, &ep->ev_time.ftv_sec, 0); 5320Sstevel@tonic-gate err |= ea_set_item(&i1, CAT_FMA_TODNSEC, &ep->ev_time.ftv_nsec, 0); 5330Sstevel@tonic-gate err |= ea_set_item(&i2, CAT_FMA_NVLIST, nvbuf, nvsize); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate if (err != 0) { 5360Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->ev_lock); 5370Sstevel@tonic-gate err = EFMD_LOG_EXACCT; 5380Sstevel@tonic-gate goto exerr; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i0); 5420Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i1); 5430Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i2); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * If this event has a case associated with it (i.e. it is a list), 5470Sstevel@tonic-gate * then allocate a block of ea_object_t's and fill in a group for 5480Sstevel@tonic-gate * each event saved in the case's item list. For each such group, 5490Sstevel@tonic-gate * we attach it to grp1, which in turn will be attached to grp0. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate if (cp != NULL) { 552*1052Sdilpreet ea_object_t *egrp, *ip, **fp; 5530Sstevel@tonic-gate fmd_event_impl_t *eip; 5540Sstevel@tonic-gate fmd_case_item_t *cit; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate (void) ea_set_group(&grp1, CAT_FMA_GROUP); 557*1052Sdilpreet frsize = sizeof (ea_object_t *) * cip->ci_nitems; 5580Sstevel@tonic-gate itsize = sizeof (ea_object_t) * cip->ci_nitems * 5; 5590Sstevel@tonic-gate items = ip = fmd_alloc(itsize, FMD_SLEEP); 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) { 5620Sstevel@tonic-gate major_t maj; 5630Sstevel@tonic-gate minor_t min; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate eip = (fmd_event_impl_t *)cit->cit_event; 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (eip->ev_log == NULL) 5680Sstevel@tonic-gate continue; /* event was never logged */ 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate maj = major(eip->ev_log->log_stat.st_dev); 5710Sstevel@tonic-gate min = minor(eip->ev_log->log_stat.st_dev); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate (void) ea_set_group(ip, CAT_FMA_GROUP); 5740Sstevel@tonic-gate egrp = ip++; /* first obj is group */ 5750Sstevel@tonic-gate 576*1052Sdilpreet /* 577*1052Sdilpreet * If the event log file is in legacy format, 578*1052Sdilpreet * then write the xref to the file in the legacy 579*1052Sdilpreet * maj/min/inode method else write it using the 580*1052Sdilpreet * file uuid. 581*1052Sdilpreet */ 582*1052Sdilpreet if (eip->ev_log->log_uuid == NULL) { 583*1052Sdilpreet (void) ea_set_item(ip, CAT_FMA_MAJOR, &maj, 0); 584*1052Sdilpreet (void) ea_attach_to_group(egrp, ip++); 585*1052Sdilpreet (void) ea_set_item(ip, CAT_FMA_MINOR, &min, 0); 586*1052Sdilpreet (void) ea_attach_to_group(egrp, ip++); 587*1052Sdilpreet (void) ea_set_item(ip, CAT_FMA_INODE, 588*1052Sdilpreet &eip->ev_log->log_stat.st_ino, 0); 589*1052Sdilpreet (void) ea_attach_to_group(egrp, ip++); 590*1052Sdilpreet } else { 591*1052Sdilpreet if (ea_set_item(ip, CAT_FMA_UUID, 592*1052Sdilpreet eip->ev_log->log_uuid, 0) == -1) { 593*1052Sdilpreet err = EFMD_LOG_EXACCT; 594*1052Sdilpreet goto exerrcp; 595*1052Sdilpreet } 596*1052Sdilpreet if (fe == NULL) 597*1052Sdilpreet fe = fp = fmd_zalloc(frsize, FMD_SLEEP); 598*1052Sdilpreet *fp++ = ip; 599*1052Sdilpreet (void) ea_attach_to_group(egrp, ip++); 600*1052Sdilpreet } 6010Sstevel@tonic-gate (void) ea_set_item(ip, CAT_FMA_OFFSET, &eip->ev_off, 0); 6020Sstevel@tonic-gate (void) ea_attach_to_group(egrp, ip++); 6030Sstevel@tonic-gate (void) ea_attach_to_group(&grp1, egrp); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &grp1); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate easize = ea_pack_object(&grp0, NULL, 0); 6090Sstevel@tonic-gate eabuf = fmd_alloc(easize, FMD_SLEEP); 6100Sstevel@tonic-gate (void) ea_pack_object(&grp0, eabuf, easize); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* 6130Sstevel@tonic-gate * Before writing the record, check to see if this would cause the free 6140Sstevel@tonic-gate * space in the filesystem to drop below our minfree threshold. If so, 6150Sstevel@tonic-gate * don't bother attempting the write and instead pretend it failed. As 6160Sstevel@tonic-gate * fmd(1M) runs as root, it will be able to access the space "reserved" 6170Sstevel@tonic-gate * for root, and therefore can run the system of out of disk space in a 6180Sstevel@tonic-gate * heavy error load situation, violating the basic design principle of 6190Sstevel@tonic-gate * fmd(1M) that we don't want to make a bad situation even worse. 6200Sstevel@tonic-gate */ 6210Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if (lp->log_minfree != 0 && fstatvfs64(lp->log_fd, &stv) == 0 && 6240Sstevel@tonic-gate stv.f_bavail * stv.f_frsize < lp->log_minfree + easize) { 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "append %s crosses minfree", lp->log_tag)); 6270Sstevel@tonic-gate err = EFMD_LOG_MINFREE; 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate } else if (fmd_log_write(lp, eabuf, easize) == easize) { 6300Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "append %s %p off=0x%llx", 6310Sstevel@tonic-gate lp->log_tag, (void *)ep, (u_longlong_t)lp->log_off)); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_VOLATILE; 6340Sstevel@tonic-gate ep->ev_log = lp; 6350Sstevel@tonic-gate ep->ev_off = lp->log_off; 6360Sstevel@tonic-gate ep->ev_len = easize; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 6390Sstevel@tonic-gate lp->log_pending++; 6400Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate lp->log_refs++; 6440Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 6450Sstevel@tonic-gate lp->log_off += easize; 6460Sstevel@tonic-gate } else { 6470Sstevel@tonic-gate err = errno; /* save errno for fmd_error() call below */ 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * If we can't write append the record, seek the file back to 6510Sstevel@tonic-gate * the original location and truncate it there in order to make 6520Sstevel@tonic-gate * sure the file is always in a sane state w.r.t. libexacct. 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate (void) lseek64(lp->log_fd, lp->log_off, SEEK_SET); 6550Sstevel@tonic-gate (void) ftruncate64(lp->log_fd, lp->log_off); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 6590Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->ev_lock); 6600Sstevel@tonic-gate 661*1052Sdilpreet fmd_free(eabuf, easize); 662*1052Sdilpreet 663*1052Sdilpreet exerrcp: 664*1052Sdilpreet if (cp != NULL) { 665*1052Sdilpreet if (fe != NULL) { 666*1052Sdilpreet ea_object_t **fp = fe; 667*1052Sdilpreet int i = 0; 668*1052Sdilpreet 669*1052Sdilpreet for (; *fp != NULL && i < cip->ci_nitems; i++) 670*1052Sdilpreet (void) ea_free_item(*fp++, EUP_ALLOC); 671*1052Sdilpreet fmd_free(fe, frsize); 672*1052Sdilpreet } 673*1052Sdilpreet 6740Sstevel@tonic-gate fmd_free(items, itsize); 675*1052Sdilpreet } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate exerr: 6780Sstevel@tonic-gate fmd_free(nvbuf, nvsize); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate (void) ea_free_item(&i0, EUP_ALLOC); 6810Sstevel@tonic-gate (void) ea_free_item(&i1, EUP_ALLOC); 6820Sstevel@tonic-gate (void) ea_free_item(&i2, EUP_ALLOC); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate /* 6850Sstevel@tonic-gate * Keep track of out-of-space errors using global statistics. As we're 6860Sstevel@tonic-gate * out of disk space, it's unlikely the EFMD_LOG_APPEND will be logged. 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate if (err == ENOSPC || err == EFMD_LOG_MINFREE) { 6890Sstevel@tonic-gate fmd_stat_t *sp; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if (lp == fmd.d_errlog) 6920Sstevel@tonic-gate sp = &fmd.d_stats->ds_err_enospc; 6930Sstevel@tonic-gate else if (lp == fmd.d_fltlog) 6940Sstevel@tonic-gate sp = &fmd.d_stats->ds_flt_enospc; 6950Sstevel@tonic-gate else 6960Sstevel@tonic-gate sp = &fmd.d_stats->ds_oth_enospc; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_stats_lock); 6990Sstevel@tonic-gate sp->fmds_value.ui64++; 7000Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_stats_lock); 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate if (err != 0) { 7040Sstevel@tonic-gate fmd_error(EFMD_LOG_APPEND, "failed to log_append %s %p: %s\n", 7050Sstevel@tonic-gate lp->log_tag, (void *)ep, fmd_strerror(err)); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * Commit an event to the log permanently, indicating that it should not be 7110Sstevel@tonic-gate * replayed on restart. This is done by overwriting the event group's catalog 7120Sstevel@tonic-gate * code with EXD_GROUP_FMA (from EXD_GROUP_RFMA used in fmd_log_append()). We 7130Sstevel@tonic-gate * use pwrite64() to update the existing word directly, using somewhat guilty 7140Sstevel@tonic-gate * knowledge that exacct stores the 32-bit catalog word first for each object. 7150Sstevel@tonic-gate * Since we are overwriting an existing log location using pwrite64() and hold 7160Sstevel@tonic-gate * the event lock, we do not need to hold the log_lock during the i/o. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate void 7190Sstevel@tonic-gate fmd_log_commit(fmd_log_t *lp, fmd_event_t *e) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 7220Sstevel@tonic-gate ea_catalog_t c; 7230Sstevel@tonic-gate int err = 0; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 7260Sstevel@tonic-gate return; /* log does not require replay tagging */ 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ep->ev_lock)); 7290Sstevel@tonic-gate ASSERT(ep->ev_log == lp && ep->ev_off != 0); 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate c = CAT_FMA_GROUP; 7320Sstevel@tonic-gate exacct_order32(&c); 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate if (pwrite64(lp->log_fd, &c, sizeof (c), ep->ev_off) == sizeof (c)) { 7350Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "commit %s %p", lp->log_tag, (void *)ep)); 7360Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_REPLAY; 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate /* 7390Sstevel@tonic-gate * If we have committed the event, check to see if the TOC skip 7400Sstevel@tonic-gate * offset needs to be updated, and decrement the pending count. 7410Sstevel@tonic-gate */ 7420Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate if (lp->log_skip == ep->ev_off) { 7450Sstevel@tonic-gate lp->log_flags |= FMD_LF_DIRTY; 7460Sstevel@tonic-gate lp->log_skip += ep->ev_len; 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 7500Sstevel@tonic-gate lp->log_pending--; 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 7530Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate } else { 7560Sstevel@tonic-gate fmd_error(EFMD_LOG_COMMIT, "failed to log_commit %s %p: %s\n", 7570Sstevel@tonic-gate lp->log_tag, (void *)ep, fmd_strerror(err)); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate /* 7620Sstevel@tonic-gate * If we need to destroy an event and it wasn't able to be committed, we permit 7630Sstevel@tonic-gate * the owner to decommit from ever trying again. This operation decrements the 7640Sstevel@tonic-gate * pending count on the log and broadcasts to anyone waiting on log_cv. 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate void 7670Sstevel@tonic-gate fmd_log_decommit(fmd_log_t *lp, fmd_event_t *e) 7680Sstevel@tonic-gate { 7690Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 7720Sstevel@tonic-gate return; /* log does not require replay tagging */ 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ep->ev_lock)); 7750Sstevel@tonic-gate ASSERT(ep->ev_log == lp); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "decommit %s %p", lp->log_tag, (void *)ep)); 7800Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_REPLAY; 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 7830Sstevel@tonic-gate lp->log_pending--; 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 7860Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate static fmd_event_t * 7900Sstevel@tonic-gate fmd_log_unpack(fmd_log_t *lp, ea_object_t *grp, off64_t off) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate fmd_timeval_t ftv = { -1ULL, -1ULL }; 7930Sstevel@tonic-gate nvlist_t *nvl = NULL; 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate ea_object_t *obj; 7960Sstevel@tonic-gate char *class; 7970Sstevel@tonic-gate int err; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) { 8000Sstevel@tonic-gate switch (obj->eo_catalog) { 8010Sstevel@tonic-gate case CAT_FMA_NVLIST: 8020Sstevel@tonic-gate if ((err = nvlist_xunpack(obj->eo_item.ei_raw, 8030Sstevel@tonic-gate obj->eo_item.ei_size, &nvl, &fmd.d_nva)) != 0) { 8040Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack " 8050Sstevel@tonic-gate "log nvpair: %s\n", fmd_strerror(err)); 8060Sstevel@tonic-gate return (NULL); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate break; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate case CAT_FMA_TODSEC: 8110Sstevel@tonic-gate ftv.ftv_sec = obj->eo_item.ei_uint64; 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate case CAT_FMA_TODNSEC: 8150Sstevel@tonic-gate ftv.ftv_nsec = obj->eo_item.ei_uint64; 8160Sstevel@tonic-gate break; 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate if (nvl == NULL || ftv.ftv_sec == -1ULL || ftv.ftv_nsec == -1ULL) { 8210Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack log event: " 8220Sstevel@tonic-gate "required object(s) missing from record group\n"); 8230Sstevel@tonic-gate nvlist_free(nvl); 8240Sstevel@tonic-gate return (NULL); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) { 8280Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack log event: " 8290Sstevel@tonic-gate "record is missing required '%s' nvpair\n", FM_CLASS); 8300Sstevel@tonic-gate nvlist_free(nvl); 8310Sstevel@tonic-gate return (NULL); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate return (fmd_event_recreate(FMD_EVT_PROTOCOL, 8350Sstevel@tonic-gate &ftv, nvl, class, lp, off, ea_pack_object(grp, NULL, 0))); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * Replay event(s) from the specified log by invoking the specified callback 8400Sstevel@tonic-gate * function 'func' for each event. If the log has the FMD_LF_REPLAY flag set, 8410Sstevel@tonic-gate * we replay all events after log_skip that have the FMA_RGROUP group tag. 8420Sstevel@tonic-gate * This mode is used for the error telemetry log. If the log does not have 8430Sstevel@tonic-gate * this flag set (used for ASRU logs), only the most recent event is replayed. 8440Sstevel@tonic-gate */ 8450Sstevel@tonic-gate void 8460Sstevel@tonic-gate fmd_log_replay(fmd_log_t *lp, fmd_log_f *func, void *data) 8470Sstevel@tonic-gate { 8480Sstevel@tonic-gate ea_object_t obj, *grp; 8490Sstevel@tonic-gate ea_object_type_t type; 8500Sstevel@tonic-gate ea_catalog_t c; 8510Sstevel@tonic-gate fmd_event_t *ep; 8520Sstevel@tonic-gate off64_t off, skp; 8530Sstevel@tonic-gate uint_t n = 0; 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate if (lp->log_stat.st_size == 0 && (lp->log_flags & FMD_LF_REPLAY)) { 8580Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 8590Sstevel@tonic-gate return; /* we just created this log: never replay events */ 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate while (lp->log_flags & FMD_LF_BUSY) 8630Sstevel@tonic-gate (void) pthread_cond_wait(&lp->log_cv, &lp->log_lock); 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate if (lp->log_off == lp->log_beg) { 8660Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 8670Sstevel@tonic-gate return; /* no records appended yet */ 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate lp->log_flags |= FMD_LF_BUSY; 8710Sstevel@tonic-gate skp = lp->log_skip; 8720Sstevel@tonic-gate ea_clear(&lp->log_ea); /* resync exacct file */ 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate /* 8750Sstevel@tonic-gate * If FMD_LF_REPLAY is set, begin our replay at either log_skip (if it 8760Sstevel@tonic-gate * is non-zero) or at log_beg. Otherwise replay from the end (log_off) 8770Sstevel@tonic-gate */ 8780Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 8790Sstevel@tonic-gate off = MAX(lp->log_beg, lp->log_skip); 8800Sstevel@tonic-gate c = CAT_FMA_RGROUP; 8810Sstevel@tonic-gate } else { 8820Sstevel@tonic-gate off = lp->log_off; 8830Sstevel@tonic-gate c = CAT_FMA_GROUP; 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate if (lseek64(lp->log_fd, off, SEEK_SET) != off) { 8870Sstevel@tonic-gate fmd_panic("failed to seek %s to 0x%llx\n", 8880Sstevel@tonic-gate lp->log_name, (u_longlong_t)off); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate /* 8920Sstevel@tonic-gate * If FMD_LF_REPLAY is not set, back up to the start of the previous 8930Sstevel@tonic-gate * object and make sure this object is an EO_GROUP; otherwise return. 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY) && 8960Sstevel@tonic-gate (type = ea_previous_object(&lp->log_ea, &obj)) != EO_GROUP) { 8970Sstevel@tonic-gate fmd_error(EFMD_LOG_REPLAY, "last log object is of unexpected " 8980Sstevel@tonic-gate "type %d (log may be truncated or corrupt)\n", type); 8990Sstevel@tonic-gate goto out; 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate while ((grp = ea_get_object_tree(&lp->log_ea, 1)) != NULL) { 9030Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 9040Sstevel@tonic-gate off -= ea_pack_object(grp, NULL, 0); 9050Sstevel@tonic-gate else if (n == 0 && grp->eo_catalog == CAT_FMA_GROUP) 9060Sstevel@tonic-gate skp = off; /* update skip */ 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* 9090Sstevel@tonic-gate * We temporarily drop log_lock around the call to unpack the 9100Sstevel@tonic-gate * event, hold it, and perform the callback, because these 9110Sstevel@tonic-gate * operations may try to acquire log_lock to bump log_refs. 9120Sstevel@tonic-gate * We cannot lose control because the FMD_LF_BUSY flag is set. 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate if (grp->eo_catalog == c && 9170Sstevel@tonic-gate (ep = fmd_log_unpack(lp, grp, off)) != NULL) { 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "replay %s %p off %llx", 9200Sstevel@tonic-gate lp->log_tag, (void *)ep, (u_longlong_t)off)); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate fmd_event_hold(ep); 9230Sstevel@tonic-gate func(lp, ep, data); 9240Sstevel@tonic-gate fmd_event_rele(ep); 9250Sstevel@tonic-gate n++; 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 9290Sstevel@tonic-gate off += ea_pack_object(grp, NULL, 0); 9300Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate if (ea_error() != EXR_EOF) { 9340Sstevel@tonic-gate fmd_error(EFMD_LOG_REPLAY, "failed to replay %s event at " 9350Sstevel@tonic-gate "offset 0x%llx: %s\n", lp->log_name, (u_longlong_t)off, 9360Sstevel@tonic-gate fmd_ea_strerror(ea_error())); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate if (n == 0) 9400Sstevel@tonic-gate skp = off; /* if no replays, move skip to where we ended up */ 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate out: 9430Sstevel@tonic-gate if (lseek64(lp->log_fd, lp->log_off, SEEK_SET) != lp->log_off) { 9440Sstevel@tonic-gate fmd_panic("failed to seek %s to 0x%llx\n", 9450Sstevel@tonic-gate lp->log_name, (u_longlong_t)lp->log_off); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (skp != lp->log_skip) { 9490Sstevel@tonic-gate lp->log_flags |= FMD_LF_DIRTY; 9500Sstevel@tonic-gate lp->log_skip = skp; 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_BUSY; 9540Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 9550Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate void 9590Sstevel@tonic-gate fmd_log_update(fmd_log_t *lp) 9600Sstevel@tonic-gate { 9610Sstevel@tonic-gate ea_object_t toc, item; 9620Sstevel@tonic-gate off64_t skip = 0; 9630Sstevel@tonic-gate size_t size; 9640Sstevel@tonic-gate void *buf; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate if (lp->log_flags & FMD_LF_DIRTY) { 9690Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_DIRTY; 9700Sstevel@tonic-gate skip = lp->log_skip; 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * If the skip needs to be updated, construct a TOC record group 9770Sstevel@tonic-gate * containing the skip offset and overwrite the TOC in-place. 9780Sstevel@tonic-gate */ 9790Sstevel@tonic-gate if (skip != 0 && ea_set_group(&toc, CAT_FMA_GROUP) == 0 && 9800Sstevel@tonic-gate ea_set_item(&item, CAT_FMA_OFFSET, &skip, 0) == 0) { 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate (void) ea_attach_to_group(&toc, &item); 9830Sstevel@tonic-gate size = ea_pack_object(&toc, NULL, 0); 9840Sstevel@tonic-gate buf = fmd_alloc(size, FMD_SLEEP); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate (void) ea_pack_object(&toc, buf, size); 9870Sstevel@tonic-gate ASSERT(lp->log_toc + size == lp->log_beg); 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate if (pwrite64(lp->log_fd, buf, size, lp->log_toc) == size) { 9900Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "updated skip to %llx", skip)); 9910Sstevel@tonic-gate } else { 9920Sstevel@tonic-gate fmd_error(EFMD_LOG_UPDATE, 9930Sstevel@tonic-gate "failed to log_update %s", lp->log_tag); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate fmd_free(buf, size); 9970Sstevel@tonic-gate (void) ea_free_item(&item, EUP_ALLOC); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate /* 10020Sstevel@tonic-gate * Rotate the specified log by renaming its underlying file to a staging file 10030Sstevel@tonic-gate * that can be handed off to logadm(1M) or an administrator script. If the 10040Sstevel@tonic-gate * rename succeeds, open a new log file using the old path and return it. 10050Sstevel@tonic-gate * Note that we are relying our caller to use some higher-level mechanism to 10060Sstevel@tonic-gate * ensure that fmd_log_rotate() cannot be called while other threads are 10070Sstevel@tonic-gate * attempting fmd_log_append() using the same log (fmd's d_log_lock is used 10080Sstevel@tonic-gate * for the global errlog and fltlog). 10090Sstevel@tonic-gate */ 10100Sstevel@tonic-gate fmd_log_t * 10110Sstevel@tonic-gate fmd_log_rotate(fmd_log_t *lp) 10120Sstevel@tonic-gate { 10130Sstevel@tonic-gate char npath[PATH_MAX]; 10140Sstevel@tonic-gate fmd_log_t *nlp; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate (void) snprintf(npath, sizeof (npath), "%s.0-", lp->log_name); 10170Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate /* 10200Sstevel@tonic-gate * Check for any pending commits to drain before proceeding. We can't 10210Sstevel@tonic-gate * rotate the log out if commits are pending because if we die after 10220Sstevel@tonic-gate * the log is moved aside, we won't be able to replay them on restart. 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate if (lp->log_pending != 0) { 10250Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10260Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTBUSY); 10270Sstevel@tonic-gate return (NULL); 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate if (rename(lp->log_name, npath) != 0) { 10310Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10320Sstevel@tonic-gate fmd_error(EFMD_LOG_ROTATE, "failed to rename %s", lp->log_name); 10330Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTATE); 10340Sstevel@tonic-gate return (NULL); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate if ((nlp = fmd_log_open("", lp->log_name, lp->log_tag)) == NULL) { 10380Sstevel@tonic-gate (void) rename(npath, lp->log_name); 10390Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10400Sstevel@tonic-gate fmd_error(EFMD_LOG_ROTATE, "failed to reopen %s", lp->log_name); 10410Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTATE); 10420Sstevel@tonic-gate return (NULL); 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate /* 10460Sstevel@tonic-gate * If we've rotated the log, no pending events exist so we don't have 10470Sstevel@tonic-gate * any more commits coming, and our caller should have arranged for 10480Sstevel@tonic-gate * no more calls to append. As such, we can close log_fd for good. 10490Sstevel@tonic-gate */ 10500Sstevel@tonic-gate if (lp->log_flags & FMD_LF_EAOPEN) { 10510Sstevel@tonic-gate (void) ea_close(&lp->log_ea); 10520Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_EAOPEN; 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate (void) close(lp->log_fd); 10560Sstevel@tonic-gate lp->log_fd = -1; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10590Sstevel@tonic-gate return (nlp); 10600Sstevel@tonic-gate } 1061