17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*9dd0f810Scindi * Common Development and Distribution License (the "License"). 6*9dd0f810Scindi * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21d9638e54Smws 227c478bd9Sstevel@tonic-gate /* 23*9dd0f810Scindi * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * FMD Log File Subsystem 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * Events are written to one of two log files as they are received or created; 337c478bd9Sstevel@tonic-gate * the error log tracks all ereport.* events received on the inbound event 347c478bd9Sstevel@tonic-gate * transport, and the fault log tracks all list.* events generated by fmd or 357c478bd9Sstevel@tonic-gate * its client modules. In addition, we use the same log file format to cache 367c478bd9Sstevel@tonic-gate * state and events associated with ASRUs that are named in a diagnosis. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * The log files use the exacct format manipulated by libexacct(3LIB) and 397c478bd9Sstevel@tonic-gate * originally defined in PSARC 1999/119. However, the exacct library was 407c478bd9Sstevel@tonic-gate * designed primarily for read-only clients and without the synchronous i/o 417c478bd9Sstevel@tonic-gate * considerations and seeking required for fmd, so we use libexacct here only 427c478bd9Sstevel@tonic-gate * to read and write the file headers and to pack data from memory into a file 437c478bd9Sstevel@tonic-gate * bytestream. All of the i/o and file offset manipulations are performed by 447c478bd9Sstevel@tonic-gate * the fmd code below. Our exacct file management uses the following grammar: 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate * file := hdr toc event* 477ee93e3bSdilpreet * hdr := EXD_FMA_LABEL EXD_FMA_VERSION EXD_FMA_OSREL EXD_FMA_OSVER 487ee93e3bSdilpreet * EXD_FMA_PLAT EXD_FMA_UUID 497c478bd9Sstevel@tonic-gate * toc := EXD_FMA_OFFSET 507ee93e3bSdilpreet * event := EXD_FMA_TODSEC EXD_FMA_TODNSEC EXD_FMA_NVLIST evref* or legacy evref 517ee93e3bSdilpreet * evref := EXD_FMA_UUID EXD_FMA_OFFSET 527ee93e3bSdilpreet * legacy evref := EXD_FMA_MAJOR EXD_FMA_MINOR EXD_FMA_INODE EXD_FMA_OFFSET 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * Any event can be uniquely identified by the tuple (file, offset) where file 557ee93e3bSdilpreet * is encoded as (uuid) when we are cross-linking files. For legacy file 567ee93e3bSdilpreet * formats we still support encoding the reference as (major, minor, inode). 577ee93e3bSdilpreet * Note that we break out of the file's dev_t into its two 32-bit components to 587c478bd9Sstevel@tonic-gate * permit development of either 32-bit or 64-bit log readers and writers; the 597c478bd9Sstevel@tonic-gate * LFS APIs do not yet export a 64-bit dev_t to fstat64(), so there is no way 607c478bd9Sstevel@tonic-gate * for a 32-bit application to retrieve and store a 64-bit dev_t. 617c478bd9Sstevel@tonic-gate * 627c478bd9Sstevel@tonic-gate * In order to replay events in the event of an fmd crash, events are initially 637c478bd9Sstevel@tonic-gate * written to the error log using the group catalog tag EXD_GROUP_RFMA by the 647c478bd9Sstevel@tonic-gate * fmd_log_append() function. Later, once an event transitions from the 657c478bd9Sstevel@tonic-gate * received state to one of its other states (see fmd_event.c for details), 667c478bd9Sstevel@tonic-gate * fmd_log_commit() is used to overwrite the tag with EXD_GROUP_FMA, indicating 677c478bd9Sstevel@tonic-gate * that the event is fully processed and no longer needs to be replayed. 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate #include <sys/types.h> 717c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 727c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 737c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 747c478bd9Sstevel@tonic-gate #include <sys/exacct_impl.h> 757ee93e3bSdilpreet #include <uuid/uuid.h> 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #include <unistd.h> 787c478bd9Sstevel@tonic-gate #include <limits.h> 797c478bd9Sstevel@tonic-gate #include <fcntl.h> 807c478bd9Sstevel@tonic-gate #include <ctype.h> 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 837c478bd9Sstevel@tonic-gate #include <fmd_error.h> 847c478bd9Sstevel@tonic-gate #include <fmd_string.h> 857c478bd9Sstevel@tonic-gate #include <fmd_event.h> 867c478bd9Sstevel@tonic-gate #include <fmd_conf.h> 877c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 887c478bd9Sstevel@tonic-gate #include <fmd_case.h> 897c478bd9Sstevel@tonic-gate #include <fmd_log.h> 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate #include <fmd.h> 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate #define CAT_FMA_RGROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_RFMA) 947c478bd9Sstevel@tonic-gate #define CAT_FMA_GROUP (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_FMA) 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate #define CAT_FMA_LABEL (EXT_STRING | EXC_DEFAULT | EXD_FMA_LABEL) 977c478bd9Sstevel@tonic-gate #define CAT_FMA_VERSION (EXT_STRING | EXC_DEFAULT | EXD_FMA_VERSION) 987c478bd9Sstevel@tonic-gate #define CAT_FMA_OSREL (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSREL) 997c478bd9Sstevel@tonic-gate #define CAT_FMA_OSVER (EXT_STRING | EXC_DEFAULT | EXD_FMA_OSVER) 1007c478bd9Sstevel@tonic-gate #define CAT_FMA_PLAT (EXT_STRING | EXC_DEFAULT | EXD_FMA_PLAT) 1017ee93e3bSdilpreet #define CAT_FMA_UUID (EXT_STRING | EXC_DEFAULT | EXD_FMA_UUID) 1027c478bd9Sstevel@tonic-gate #define CAT_FMA_TODSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODSEC) 1037c478bd9Sstevel@tonic-gate #define CAT_FMA_TODNSEC (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_TODNSEC) 1047c478bd9Sstevel@tonic-gate #define CAT_FMA_NVLIST (EXT_RAW | EXC_DEFAULT | EXD_FMA_NVLIST) 1057c478bd9Sstevel@tonic-gate #define CAT_FMA_MAJOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MAJOR) 1067c478bd9Sstevel@tonic-gate #define CAT_FMA_MINOR (EXT_UINT32 | EXC_DEFAULT | EXD_FMA_MINOR) 1077c478bd9Sstevel@tonic-gate #define CAT_FMA_INODE (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_INODE) 1087c478bd9Sstevel@tonic-gate #define CAT_FMA_OFFSET (EXT_UINT64 | EXC_DEFAULT | EXD_FMA_OFFSET) 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static ssize_t 1117c478bd9Sstevel@tonic-gate fmd_log_write(fmd_log_t *lp, const void *buf, size_t n) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate ssize_t resid = n; 1147c478bd9Sstevel@tonic-gate ssize_t len; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lp->log_lock)); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate while (resid != 0) { 1197c478bd9Sstevel@tonic-gate if ((len = write(lp->log_fd, buf, resid)) <= 0) 1207c478bd9Sstevel@tonic-gate break; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate resid -= len; 1237c478bd9Sstevel@tonic-gate buf = (char *)buf + len; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate if (resid == n && n != 0) 1277c478bd9Sstevel@tonic-gate return (-1); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate return (n - resid); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate static int 1337c478bd9Sstevel@tonic-gate fmd_log_write_hdr(fmd_log_t *lp, const char *tag) 1347c478bd9Sstevel@tonic-gate { 1357ee93e3bSdilpreet ea_object_t hdr, toc, i0, i1, i2, i3, i4, i5, i6; 1367c478bd9Sstevel@tonic-gate const char *osrel, *osver, *plat; 1377c478bd9Sstevel@tonic-gate off64_t off = 0; 1387c478bd9Sstevel@tonic-gate int err = 0; 1397ee93e3bSdilpreet uuid_t uuid; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "osrelease", &osrel); 1427c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "osversion", &osver); 1437c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "platform", &plat); 1447ee93e3bSdilpreet (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &lp->log_uuidlen); 1457ee93e3bSdilpreet 1467ee93e3bSdilpreet lp->log_uuid = fmd_zalloc(lp->log_uuidlen + 1, FMD_SLEEP); 1477ee93e3bSdilpreet uuid_generate(uuid); 1487ee93e3bSdilpreet uuid_unparse(uuid, lp->log_uuid); 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate err |= ea_set_group(&hdr, CAT_FMA_GROUP); 1517c478bd9Sstevel@tonic-gate err |= ea_set_group(&toc, CAT_FMA_GROUP); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate err |= ea_set_item(&i0, CAT_FMA_LABEL, tag, 0); 1547c478bd9Sstevel@tonic-gate err |= ea_set_item(&i1, CAT_FMA_VERSION, fmd.d_version, 0); 1557c478bd9Sstevel@tonic-gate err |= ea_set_item(&i2, CAT_FMA_OSREL, osrel, 0); 1567c478bd9Sstevel@tonic-gate err |= ea_set_item(&i3, CAT_FMA_OSVER, osver, 0); 1577c478bd9Sstevel@tonic-gate err |= ea_set_item(&i4, CAT_FMA_PLAT, plat, 0); 1587ee93e3bSdilpreet err |= ea_set_item(&i5, CAT_FMA_UUID, lp->log_uuid, 0); 1597ee93e3bSdilpreet err |= ea_set_item(&i6, CAT_FMA_OFFSET, &off, 0); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i0); 1627c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i1); 1637c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i2); 1647c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i3); 1657c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr, &i4); 1667ee93e3bSdilpreet (void) ea_attach_to_group(&hdr, &i5); 1677ee93e3bSdilpreet (void) ea_attach_to_group(&toc, &i6); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (err == 0) { 1707c478bd9Sstevel@tonic-gate size_t hdr_size = ea_pack_object(&hdr, NULL, 0); 1717c478bd9Sstevel@tonic-gate size_t toc_size = ea_pack_object(&toc, NULL, 0); 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate size_t size = hdr_size + toc_size; 1747c478bd9Sstevel@tonic-gate void *buf = fmd_alloc(size, FMD_SLEEP); 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate (void) ea_pack_object(&hdr, buf, hdr_size); 1777c478bd9Sstevel@tonic-gate (void) ea_pack_object(&toc, (char *)buf + hdr_size, toc_size); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if ((lp->log_off = lseek64(lp->log_fd, 0, SEEK_END)) == -1L) 1807c478bd9Sstevel@tonic-gate fmd_panic("failed to seek log %s", lp->log_name); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (fmd_log_write(lp, buf, size) != size) 1837c478bd9Sstevel@tonic-gate err = errno; /* save errno for fmd_set_errno() below */ 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate fmd_free(buf, size); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate lp->log_toc = lp->log_off + hdr_size; 1887c478bd9Sstevel@tonic-gate lp->log_beg = lp->log_off + hdr_size + toc_size; 1897c478bd9Sstevel@tonic-gate lp->log_off = lp->log_off + hdr_size + toc_size; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (lp->log_off != lseek64(lp->log_fd, 0, SEEK_END)) 1927c478bd9Sstevel@tonic-gate fmd_panic("eof off != log_off 0x%llx\n", lp->log_off); 1937c478bd9Sstevel@tonic-gate } else 1947c478bd9Sstevel@tonic-gate err = EFMD_LOG_EXACCT; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate (void) ea_free_item(&i0, EUP_ALLOC); 1977c478bd9Sstevel@tonic-gate (void) ea_free_item(&i1, EUP_ALLOC); 1987c478bd9Sstevel@tonic-gate (void) ea_free_item(&i2, EUP_ALLOC); 1997c478bd9Sstevel@tonic-gate (void) ea_free_item(&i3, EUP_ALLOC); 2007c478bd9Sstevel@tonic-gate (void) ea_free_item(&i4, EUP_ALLOC); 2017c478bd9Sstevel@tonic-gate (void) ea_free_item(&i5, EUP_ALLOC); 2027ee93e3bSdilpreet (void) ea_free_item(&i6, EUP_ALLOC); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate return (err ? fmd_set_errno(err) : 0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate static int 2087c478bd9Sstevel@tonic-gate fmd_log_check_err(fmd_log_t *lp, int err, const char *msg) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate int eaerr = ea_error(); 2117c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s: %s: %s\n", 2147c478bd9Sstevel@tonic-gate lp->log_name, msg, eaerr != EXR_OK ? 2157c478bd9Sstevel@tonic-gate fmd_ea_strerror(eaerr) : "catalog tag mismatch"); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate fmd_error(err, buf); 2187c478bd9Sstevel@tonic-gate return (fmd_set_errno(err)); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate static int 2227c478bd9Sstevel@tonic-gate fmd_log_check_hdr(fmd_log_t *lp, const char *tag) 2237c478bd9Sstevel@tonic-gate { 2247c478bd9Sstevel@tonic-gate int got_version = 0, got_label = 0; 2257c478bd9Sstevel@tonic-gate ea_object_t *grp, *obj; 2267c478bd9Sstevel@tonic-gate off64_t hdr_off, hdr_size; 2277c478bd9Sstevel@tonic-gate int dvers, fvers; 2287c478bd9Sstevel@tonic-gate const char *p; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate ea_clear(&lp->log_ea); /* resync exacct file */ 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if ((hdr_off = lseek64(lp->log_fd, 0, SEEK_CUR)) == -1L) 2337c478bd9Sstevel@tonic-gate fmd_panic("failed to seek log %s", lp->log_name); 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Read the first group of log meta-data: the write-once read-only 2377c478bd9Sstevel@tonic-gate * file header. We read all records in this group, ignoring all but 2387c478bd9Sstevel@tonic-gate * the VERSION and LABEL, which are required and must be verified. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL || 2417c478bd9Sstevel@tonic-gate grp->eo_catalog != CAT_FMA_GROUP) { 2427c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2437c478bd9Sstevel@tonic-gate return (fmd_log_check_err(lp, EFMD_LOG_INVAL, 2447c478bd9Sstevel@tonic-gate "invalid fma hdr record group")); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) { 2487c478bd9Sstevel@tonic-gate switch (obj->eo_catalog) { 2497c478bd9Sstevel@tonic-gate case CAT_FMA_VERSION: 2507c478bd9Sstevel@tonic-gate for (dvers = 0, p = fmd.d_version; 2517c478bd9Sstevel@tonic-gate *p != '\0'; p++) { 2527c478bd9Sstevel@tonic-gate if (isdigit(*p)) 2537c478bd9Sstevel@tonic-gate dvers = dvers * 10 + (*p - '0'); 2547c478bd9Sstevel@tonic-gate else 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate for (fvers = 0, p = obj->eo_item.ei_string; 2597c478bd9Sstevel@tonic-gate *p != '\0'; p++) { 2607c478bd9Sstevel@tonic-gate if (isdigit(*p)) 2617c478bd9Sstevel@tonic-gate fvers = fvers * 10 + (*p - '0'); 2627c478bd9Sstevel@tonic-gate else 2637c478bd9Sstevel@tonic-gate break; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate if (fvers > dvers) { 2677c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: log version " 2687c478bd9Sstevel@tonic-gate "%s is not supported by this daemon\n", 2697c478bd9Sstevel@tonic-gate lp->log_name, obj->eo_item.ei_string); 2707c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2717c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_VERSION)); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate got_version++; 2757c478bd9Sstevel@tonic-gate break; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate case CAT_FMA_LABEL: 2787c478bd9Sstevel@tonic-gate if (strcmp(obj->eo_item.ei_string, tag) != 0) { 2797c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: log tag '%s' " 2807c478bd9Sstevel@tonic-gate "does not matched expected tag '%s'\n", 2817c478bd9Sstevel@tonic-gate lp->log_name, obj->eo_item.ei_string, tag); 2827c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2837c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_INVAL)); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate got_label++; 2867c478bd9Sstevel@tonic-gate break; 2877ee93e3bSdilpreet case CAT_FMA_UUID: 2887ee93e3bSdilpreet lp->log_uuid = fmd_strdup(obj->eo_item.ei_string, 2897ee93e3bSdilpreet FMD_SLEEP); 2907ee93e3bSdilpreet lp->log_uuidlen = strlen(lp->log_uuid); 2917ee93e3bSdilpreet break; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate hdr_size = ea_pack_object(grp, NULL, 0); 2967c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if (!got_version || !got_label) { 2997c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: fmd hdr record group did not " 3007c478bd9Sstevel@tonic-gate "include mandatory version and/or label\n", lp->log_name); 3017c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_INVAL)); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * Read the second group of log meta-data: the table of contents. We 3067c478bd9Sstevel@tonic-gate * expect this group to contain an OFFSET object indicating the current 3077c478bd9Sstevel@tonic-gate * value of log_skip. We save this in our fmd_log_t and then return. 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if ((grp = ea_get_object_tree(&lp->log_ea, 1)) == NULL || 3107c478bd9Sstevel@tonic-gate grp->eo_catalog != CAT_FMA_GROUP || grp->eo_group.eg_nobjs < 1 || 3117c478bd9Sstevel@tonic-gate grp->eo_group.eg_objs->eo_catalog != CAT_FMA_OFFSET) { 3127c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 3137c478bd9Sstevel@tonic-gate return (fmd_log_check_err(lp, EFMD_LOG_INVAL, 3147c478bd9Sstevel@tonic-gate "invalid fma toc record group")); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate lp->log_toc = hdr_off + hdr_size; 3187c478bd9Sstevel@tonic-gate lp->log_beg = hdr_off + hdr_size + ea_pack_object(grp, NULL, 0); 3197c478bd9Sstevel@tonic-gate lp->log_off = lseek64(lp->log_fd, 0, SEEK_END); 3207c478bd9Sstevel@tonic-gate lp->log_skip = grp->eo_group.eg_objs->eo_item.ei_uint64; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate if (lp->log_skip > lp->log_off) { 3237c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_INVAL, "%s: skip %llx exceeds file size; " 3247c478bd9Sstevel@tonic-gate "resetting to zero\n", lp->log_name, lp->log_skip); 3257c478bd9Sstevel@tonic-gate lp->log_skip = 0; 3267c478bd9Sstevel@tonic-gate } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 3297c478bd9Sstevel@tonic-gate return (0); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate static int 3337c478bd9Sstevel@tonic-gate fmd_log_open_exacct(fmd_log_t *lp, int aflags, int oflags) 3347c478bd9Sstevel@tonic-gate { 3357c478bd9Sstevel@tonic-gate int fd = dup(lp->log_fd); 3367c478bd9Sstevel@tonic-gate const char *creator; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "log.creator", &creator); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if (ea_fdopen(&lp->log_ea, fd, creator, aflags, oflags) != 0) { 3417c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_EXACCT, "%s: failed to open log file: %s\n", 3427c478bd9Sstevel@tonic-gate lp->log_name, fmd_ea_strerror(ea_error())); 3437c478bd9Sstevel@tonic-gate (void) close(fd); 3447c478bd9Sstevel@tonic-gate return (fmd_set_errno(EFMD_LOG_EXACCT)); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate lp->log_flags |= FMD_LF_EAOPEN; 3487c478bd9Sstevel@tonic-gate return (0); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate static fmd_log_t * 3527c478bd9Sstevel@tonic-gate fmd_log_xopen(const char *root, const char *name, const char *tag, int oflags) 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate fmd_log_t *lp = fmd_zalloc(sizeof (fmd_log_t), FMD_SLEEP); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 357*9dd0f810Scindi char *slash = "/"; 3587c478bd9Sstevel@tonic-gate size_t len; 3597c478bd9Sstevel@tonic-gate int err; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&lp->log_lock, NULL); 3627c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&lp->log_cv, NULL); 3637c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 3647c478bd9Sstevel@tonic-gate 365*9dd0f810Scindi if (strcmp(root, "") == 0) 366*9dd0f810Scindi slash = ""; 367*9dd0f810Scindi len = strlen(root) + strlen(name) + strlen(slash) + 1; /* for "\0" */ 3687c478bd9Sstevel@tonic-gate lp->log_name = fmd_alloc(len, FMD_SLEEP); 369*9dd0f810Scindi (void) snprintf(lp->log_name, len, "%s%s%s", root, slash, name); 3707c478bd9Sstevel@tonic-gate lp->log_tag = fmd_strdup(tag, FMD_SLEEP); 3717c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "log.minfree", &lp->log_minfree); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate if (strcmp(lp->log_tag, FMD_LOG_ERROR) == 0) 3747c478bd9Sstevel@tonic-gate lp->log_flags |= FMD_LF_REPLAY; 3757c478bd9Sstevel@tonic-gate 376d9638e54Smws if (strcmp(lp->log_tag, FMD_LOG_XPRT) == 0) 377d9638e54Smws oflags &= ~O_SYNC; 378d9638e54Smws 3797c478bd9Sstevel@tonic-gate top: 3807c478bd9Sstevel@tonic-gate if ((lp->log_fd = open64(lp->log_name, oflags, 0644)) == -1 || 3817c478bd9Sstevel@tonic-gate fstat64(lp->log_fd, &lp->log_stat) == -1) { 3827c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_OPEN, "failed to open log %s", lp->log_name); 3837c478bd9Sstevel@tonic-gate fmd_log_close(lp); 3847c478bd9Sstevel@tonic-gate return (NULL); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 3887c478bd9Sstevel@tonic-gate * If our open() created the log file, use libexacct to write a header 3897c478bd9Sstevel@tonic-gate * and position the file just after the header (EO_TAIL). If the log 3907c478bd9Sstevel@tonic-gate * file already existed, use libexacct to validate the header and again 3917c478bd9Sstevel@tonic-gate * position the file just after the header (EO_HEAD). Note that we lie 3927c478bd9Sstevel@tonic-gate * to libexacct about 'oflags' in order to achieve the desired result. 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate if (lp->log_stat.st_size == 0) { 3957c478bd9Sstevel@tonic-gate err = fmd_log_open_exacct(lp, EO_VALID_HDR | EO_TAIL, 3967c478bd9Sstevel@tonic-gate O_CREAT | O_WRONLY) || fmd_log_write_hdr(lp, tag); 3977c478bd9Sstevel@tonic-gate } else { 3987c478bd9Sstevel@tonic-gate err = fmd_log_open_exacct(lp, EO_VALID_HDR | EO_HEAD, 3997c478bd9Sstevel@tonic-gate O_RDONLY) || fmd_log_check_hdr(lp, tag); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * If ea_fdopen() failed and the log was pre-existing, attempt to move 4047c478bd9Sstevel@tonic-gate * it aside and start a new one. If we created the log but failed to 4057c478bd9Sstevel@tonic-gate * initialize it, then we have no choice but to give up (e.g. EROFS). 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate if (err) { 4087c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_OPEN, 4097c478bd9Sstevel@tonic-gate "failed to initialize log %s", lp->log_name); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_EAOPEN) { 4127c478bd9Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_EAOPEN; 4137c478bd9Sstevel@tonic-gate (void) ea_close(&lp->log_ea); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate (void) close(lp->log_fd); 4177c478bd9Sstevel@tonic-gate lp->log_fd = -1; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if (lp->log_stat.st_size != 0 && snprintf(buf, 4207c478bd9Sstevel@tonic-gate sizeof (buf), "%s-", lp->log_name) < PATH_MAX && 4217c478bd9Sstevel@tonic-gate rename(lp->log_name, buf) == 0) { 4227c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "mv %s to %s", lp->log_name, buf)); 4237c478bd9Sstevel@tonic-gate if (oflags & O_CREAT) 4247c478bd9Sstevel@tonic-gate goto top; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate fmd_log_close(lp); 4287c478bd9Sstevel@tonic-gate return (NULL); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate lp->log_refs++; 4327c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate return (lp); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate fmd_log_t * 4387c478bd9Sstevel@tonic-gate fmd_log_tryopen(const char *root, const char *name, const char *tag) 4397c478bd9Sstevel@tonic-gate { 4407c478bd9Sstevel@tonic-gate return (fmd_log_xopen(root, name, tag, O_RDWR | O_SYNC)); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate fmd_log_t * 4447c478bd9Sstevel@tonic-gate fmd_log_open(const char *root, const char *name, const char *tag) 4457c478bd9Sstevel@tonic-gate { 4467c478bd9Sstevel@tonic-gate return (fmd_log_xopen(root, name, tag, O_RDWR | O_CREAT | O_SYNC)); 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate void 4507c478bd9Sstevel@tonic-gate fmd_log_close(fmd_log_t *lp) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lp->log_lock)); 4537c478bd9Sstevel@tonic-gate ASSERT(lp->log_refs == 0); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if ((lp->log_flags & FMD_LF_EAOPEN) && ea_close(&lp->log_ea) != 0) { 4567c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_CLOSE, "failed to close log %s: %s\n", 4577c478bd9Sstevel@tonic-gate lp->log_name, fmd_ea_strerror(ea_error())); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if (lp->log_fd >= 0 && close(lp->log_fd) != 0) { 4617c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_CLOSE, 4627c478bd9Sstevel@tonic-gate "failed to close log %s", lp->log_name); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate fmd_strfree(lp->log_name); 4667c478bd9Sstevel@tonic-gate fmd_strfree(lp->log_tag); 4677ee93e3bSdilpreet if (lp->log_uuid != NULL) 4687ee93e3bSdilpreet fmd_free(lp->log_uuid, lp->log_uuidlen + 1); 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate fmd_free(lp, sizeof (fmd_log_t)); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate void 4747c478bd9Sstevel@tonic-gate fmd_log_hold_pending(fmd_log_t *lp) 4757c478bd9Sstevel@tonic-gate { 4767c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate lp->log_refs++; 4797c478bd9Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 4827c478bd9Sstevel@tonic-gate lp->log_pending++; 4837c478bd9Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate void 4907c478bd9Sstevel@tonic-gate fmd_log_hold(fmd_log_t *lp) 4917c478bd9Sstevel@tonic-gate { 4927c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 4937c478bd9Sstevel@tonic-gate lp->log_refs++; 4947c478bd9Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 4957c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate void 4997c478bd9Sstevel@tonic-gate fmd_log_rele(fmd_log_t *lp) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 5027c478bd9Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate if (--lp->log_refs == 0) 5057c478bd9Sstevel@tonic-gate fmd_log_close(lp); 5067c478bd9Sstevel@tonic-gate else 5077c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate void 5117c478bd9Sstevel@tonic-gate fmd_log_append(fmd_log_t *lp, fmd_event_t *e, fmd_case_t *cp) 5127c478bd9Sstevel@tonic-gate { 5137c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 5147c478bd9Sstevel@tonic-gate fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 5157c478bd9Sstevel@tonic-gate int err = 0; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate ea_object_t grp0, grp1, i0, i1, i2, *items; 5187ee93e3bSdilpreet ea_object_t **fe = NULL; 5197ee93e3bSdilpreet size_t nvsize, easize, itsize, frsize; 5207c478bd9Sstevel@tonic-gate char *nvbuf, *eabuf; 5217c478bd9Sstevel@tonic-gate statvfs64_t stv; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ep->ev_lock); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate ASSERT(ep->ev_flags & FMD_EVF_VOLATILE); 5267c478bd9Sstevel@tonic-gate ASSERT(ep->ev_log == NULL); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate (void) nvlist_size(ep->ev_nvl, &nvsize, NV_ENCODE_XDR); 5297c478bd9Sstevel@tonic-gate nvbuf = fmd_alloc(nvsize, FMD_SLEEP); 5307c478bd9Sstevel@tonic-gate (void) nvlist_pack(ep->ev_nvl, &nvbuf, &nvsize, NV_ENCODE_XDR, 0); 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) 5337c478bd9Sstevel@tonic-gate err |= ea_set_group(&grp0, CAT_FMA_RGROUP); 5347c478bd9Sstevel@tonic-gate else 5357c478bd9Sstevel@tonic-gate err |= ea_set_group(&grp0, CAT_FMA_GROUP); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate err |= ea_set_item(&i0, CAT_FMA_TODSEC, &ep->ev_time.ftv_sec, 0); 5387c478bd9Sstevel@tonic-gate err |= ea_set_item(&i1, CAT_FMA_TODNSEC, &ep->ev_time.ftv_nsec, 0); 5397c478bd9Sstevel@tonic-gate err |= ea_set_item(&i2, CAT_FMA_NVLIST, nvbuf, nvsize); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (err != 0) { 5427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->ev_lock); 5437c478bd9Sstevel@tonic-gate err = EFMD_LOG_EXACCT; 5447c478bd9Sstevel@tonic-gate goto exerr; 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i0); 5487c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i1); 5497c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &i2); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * If this event has a case associated with it (i.e. it is a list), 5537c478bd9Sstevel@tonic-gate * then allocate a block of ea_object_t's and fill in a group for 5547c478bd9Sstevel@tonic-gate * each event saved in the case's item list. For each such group, 5557c478bd9Sstevel@tonic-gate * we attach it to grp1, which in turn will be attached to grp0. 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate if (cp != NULL) { 5587ee93e3bSdilpreet ea_object_t *egrp, *ip, **fp; 5597c478bd9Sstevel@tonic-gate fmd_event_impl_t *eip; 5607c478bd9Sstevel@tonic-gate fmd_case_item_t *cit; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate (void) ea_set_group(&grp1, CAT_FMA_GROUP); 5637ee93e3bSdilpreet frsize = sizeof (ea_object_t *) * cip->ci_nitems; 5647c478bd9Sstevel@tonic-gate itsize = sizeof (ea_object_t) * cip->ci_nitems * 5; 5657c478bd9Sstevel@tonic-gate items = ip = fmd_alloc(itsize, FMD_SLEEP); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate for (cit = cip->ci_items; cit != NULL; cit = cit->cit_next) { 5687c478bd9Sstevel@tonic-gate major_t maj; 5697c478bd9Sstevel@tonic-gate minor_t min; 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate eip = (fmd_event_impl_t *)cit->cit_event; 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate if (eip->ev_log == NULL) 5747c478bd9Sstevel@tonic-gate continue; /* event was never logged */ 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate maj = major(eip->ev_log->log_stat.st_dev); 5777c478bd9Sstevel@tonic-gate min = minor(eip->ev_log->log_stat.st_dev); 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate (void) ea_set_group(ip, CAT_FMA_GROUP); 5807c478bd9Sstevel@tonic-gate egrp = ip++; /* first obj is group */ 5817c478bd9Sstevel@tonic-gate 5827ee93e3bSdilpreet /* 5837ee93e3bSdilpreet * If the event log file is in legacy format, 5847ee93e3bSdilpreet * then write the xref to the file in the legacy 5857ee93e3bSdilpreet * maj/min/inode method else write it using the 5867ee93e3bSdilpreet * file uuid. 5877ee93e3bSdilpreet */ 5887ee93e3bSdilpreet if (eip->ev_log->log_uuid == NULL) { 5897c478bd9Sstevel@tonic-gate (void) ea_set_item(ip, CAT_FMA_MAJOR, &maj, 0); 5907c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(egrp, ip++); 5917c478bd9Sstevel@tonic-gate (void) ea_set_item(ip, CAT_FMA_MINOR, &min, 0); 5927c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(egrp, ip++); 5937c478bd9Sstevel@tonic-gate (void) ea_set_item(ip, CAT_FMA_INODE, 5947c478bd9Sstevel@tonic-gate &eip->ev_log->log_stat.st_ino, 0); 5957c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(egrp, ip++); 5967ee93e3bSdilpreet } else { 5977ee93e3bSdilpreet if (ea_set_item(ip, CAT_FMA_UUID, 5987ee93e3bSdilpreet eip->ev_log->log_uuid, 0) == -1) { 5997ee93e3bSdilpreet err = EFMD_LOG_EXACCT; 6007ee93e3bSdilpreet goto exerrcp; 6017ee93e3bSdilpreet } 6027ee93e3bSdilpreet if (fe == NULL) 6037ee93e3bSdilpreet fe = fp = fmd_zalloc(frsize, FMD_SLEEP); 6047ee93e3bSdilpreet *fp++ = ip; 6057ee93e3bSdilpreet (void) ea_attach_to_group(egrp, ip++); 6067ee93e3bSdilpreet } 6077c478bd9Sstevel@tonic-gate (void) ea_set_item(ip, CAT_FMA_OFFSET, &eip->ev_off, 0); 6087c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(egrp, ip++); 6097c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&grp1, egrp); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&grp0, &grp1); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate easize = ea_pack_object(&grp0, NULL, 0); 6157c478bd9Sstevel@tonic-gate eabuf = fmd_alloc(easize, FMD_SLEEP); 6167c478bd9Sstevel@tonic-gate (void) ea_pack_object(&grp0, eabuf, easize); 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* 6197c478bd9Sstevel@tonic-gate * Before writing the record, check to see if this would cause the free 6207c478bd9Sstevel@tonic-gate * space in the filesystem to drop below our minfree threshold. If so, 6217c478bd9Sstevel@tonic-gate * don't bother attempting the write and instead pretend it failed. As 6227c478bd9Sstevel@tonic-gate * fmd(1M) runs as root, it will be able to access the space "reserved" 6237c478bd9Sstevel@tonic-gate * for root, and therefore can run the system of out of disk space in a 6247c478bd9Sstevel@tonic-gate * heavy error load situation, violating the basic design principle of 6257c478bd9Sstevel@tonic-gate * fmd(1M) that we don't want to make a bad situation even worse. 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate if (lp->log_minfree != 0 && fstatvfs64(lp->log_fd, &stv) == 0 && 6307c478bd9Sstevel@tonic-gate stv.f_bavail * stv.f_frsize < lp->log_minfree + easize) { 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "append %s crosses minfree", lp->log_tag)); 6337c478bd9Sstevel@tonic-gate err = EFMD_LOG_MINFREE; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate } else if (fmd_log_write(lp, eabuf, easize) == easize) { 6367c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "append %s %p off=0x%llx", 6377c478bd9Sstevel@tonic-gate lp->log_tag, (void *)ep, (u_longlong_t)lp->log_off)); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_VOLATILE; 6407c478bd9Sstevel@tonic-gate ep->ev_log = lp; 6417c478bd9Sstevel@tonic-gate ep->ev_off = lp->log_off; 6427c478bd9Sstevel@tonic-gate ep->ev_len = easize; 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 6457c478bd9Sstevel@tonic-gate lp->log_pending++; 6467c478bd9Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate lp->log_refs++; 6507c478bd9Sstevel@tonic-gate ASSERT(lp->log_refs != 0); 6517c478bd9Sstevel@tonic-gate lp->log_off += easize; 6527c478bd9Sstevel@tonic-gate } else { 6537c478bd9Sstevel@tonic-gate err = errno; /* save errno for fmd_error() call below */ 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * If we can't write append the record, seek the file back to 6577c478bd9Sstevel@tonic-gate * the original location and truncate it there in order to make 6587c478bd9Sstevel@tonic-gate * sure the file is always in a sane state w.r.t. libexacct. 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate (void) lseek64(lp->log_fd, lp->log_off, SEEK_SET); 6617c478bd9Sstevel@tonic-gate (void) ftruncate64(lp->log_fd, lp->log_off); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 6657c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ep->ev_lock); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate fmd_free(eabuf, easize); 6687ee93e3bSdilpreet 6697ee93e3bSdilpreet exerrcp: 6707ee93e3bSdilpreet if (cp != NULL) { 6717ee93e3bSdilpreet if (fe != NULL) { 6727ee93e3bSdilpreet ea_object_t **fp = fe; 6737ee93e3bSdilpreet int i = 0; 6747ee93e3bSdilpreet 6757ee93e3bSdilpreet for (; *fp != NULL && i < cip->ci_nitems; i++) 6767ee93e3bSdilpreet (void) ea_free_item(*fp++, EUP_ALLOC); 6777ee93e3bSdilpreet fmd_free(fe, frsize); 6787ee93e3bSdilpreet } 6797ee93e3bSdilpreet 6807ee93e3bSdilpreet fmd_free(items, itsize); 6817ee93e3bSdilpreet } 6827ee93e3bSdilpreet 6837c478bd9Sstevel@tonic-gate exerr: 6847c478bd9Sstevel@tonic-gate fmd_free(nvbuf, nvsize); 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate (void) ea_free_item(&i0, EUP_ALLOC); 6877c478bd9Sstevel@tonic-gate (void) ea_free_item(&i1, EUP_ALLOC); 6887c478bd9Sstevel@tonic-gate (void) ea_free_item(&i2, EUP_ALLOC); 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Keep track of out-of-space errors using global statistics. As we're 6927c478bd9Sstevel@tonic-gate * out of disk space, it's unlikely the EFMD_LOG_APPEND will be logged. 6937c478bd9Sstevel@tonic-gate */ 6947c478bd9Sstevel@tonic-gate if (err == ENOSPC || err == EFMD_LOG_MINFREE) { 6957c478bd9Sstevel@tonic-gate fmd_stat_t *sp; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if (lp == fmd.d_errlog) 6987c478bd9Sstevel@tonic-gate sp = &fmd.d_stats->ds_err_enospc; 6997c478bd9Sstevel@tonic-gate else if (lp == fmd.d_fltlog) 7007c478bd9Sstevel@tonic-gate sp = &fmd.d_stats->ds_flt_enospc; 7017c478bd9Sstevel@tonic-gate else 7027c478bd9Sstevel@tonic-gate sp = &fmd.d_stats->ds_oth_enospc; 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fmd.d_stats_lock); 7057c478bd9Sstevel@tonic-gate sp->fmds_value.ui64++; 7067c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fmd.d_stats_lock); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (err != 0) { 7107c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_APPEND, "failed to log_append %s %p: %s\n", 7117c478bd9Sstevel@tonic-gate lp->log_tag, (void *)ep, fmd_strerror(err)); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * Commit an event to the log permanently, indicating that it should not be 7177c478bd9Sstevel@tonic-gate * replayed on restart. This is done by overwriting the event group's catalog 7187c478bd9Sstevel@tonic-gate * code with EXD_GROUP_FMA (from EXD_GROUP_RFMA used in fmd_log_append()). We 7197c478bd9Sstevel@tonic-gate * use pwrite64() to update the existing word directly, using somewhat guilty 7207c478bd9Sstevel@tonic-gate * knowledge that exacct stores the 32-bit catalog word first for each object. 7217c478bd9Sstevel@tonic-gate * Since we are overwriting an existing log location using pwrite64() and hold 7227c478bd9Sstevel@tonic-gate * the event lock, we do not need to hold the log_lock during the i/o. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate void 7257c478bd9Sstevel@tonic-gate fmd_log_commit(fmd_log_t *lp, fmd_event_t *e) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 7287c478bd9Sstevel@tonic-gate ea_catalog_t c; 7297c478bd9Sstevel@tonic-gate int err = 0; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 7327c478bd9Sstevel@tonic-gate return; /* log does not require replay tagging */ 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ep->ev_lock)); 7357c478bd9Sstevel@tonic-gate ASSERT(ep->ev_log == lp && ep->ev_off != 0); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate c = CAT_FMA_GROUP; 7387c478bd9Sstevel@tonic-gate exacct_order32(&c); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (pwrite64(lp->log_fd, &c, sizeof (c), ep->ev_off) == sizeof (c)) { 7417c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "commit %s %p", lp->log_tag, (void *)ep)); 7427c478bd9Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_REPLAY; 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate /* 7457c478bd9Sstevel@tonic-gate * If we have committed the event, check to see if the TOC skip 7467c478bd9Sstevel@tonic-gate * offset needs to be updated, and decrement the pending count. 7477c478bd9Sstevel@tonic-gate */ 7487c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (lp->log_skip == ep->ev_off) { 7517c478bd9Sstevel@tonic-gate lp->log_flags |= FMD_LF_DIRTY; 7527c478bd9Sstevel@tonic-gate lp->log_skip += ep->ev_len; 7537c478bd9Sstevel@tonic-gate } 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 7567c478bd9Sstevel@tonic-gate lp->log_pending--; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 759d9638e54Smws (void) pthread_mutex_unlock(&lp->log_lock); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate } else { 7627c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_COMMIT, "failed to log_commit %s %p: %s\n", 7637c478bd9Sstevel@tonic-gate lp->log_tag, (void *)ep, fmd_strerror(err)); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * If we need to destroy an event and it wasn't able to be committed, we permit 7697c478bd9Sstevel@tonic-gate * the owner to decommit from ever trying again. This operation decrements the 7707c478bd9Sstevel@tonic-gate * pending count on the log and broadcasts to anyone waiting on log_cv. 7717c478bd9Sstevel@tonic-gate */ 7727c478bd9Sstevel@tonic-gate void 7737c478bd9Sstevel@tonic-gate fmd_log_decommit(fmd_log_t *lp, fmd_event_t *e) 7747c478bd9Sstevel@tonic-gate { 7757c478bd9Sstevel@tonic-gate fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 7787c478bd9Sstevel@tonic-gate return; /* log does not require replay tagging */ 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ep->ev_lock)); 7817c478bd9Sstevel@tonic-gate ASSERT(ep->ev_log == lp); 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "decommit %s %p", lp->log_tag, (void *)ep)); 7867c478bd9Sstevel@tonic-gate ep->ev_flags &= ~FMD_EVF_REPLAY; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate ASSERT(lp->log_pending != 0); 7897c478bd9Sstevel@tonic-gate lp->log_pending--; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 792d9638e54Smws (void) pthread_mutex_unlock(&lp->log_lock); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate static fmd_event_t * 7967c478bd9Sstevel@tonic-gate fmd_log_unpack(fmd_log_t *lp, ea_object_t *grp, off64_t off) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate fmd_timeval_t ftv = { -1ULL, -1ULL }; 7997c478bd9Sstevel@tonic-gate nvlist_t *nvl = NULL; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate ea_object_t *obj; 8027c478bd9Sstevel@tonic-gate char *class; 8037c478bd9Sstevel@tonic-gate int err; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate for (obj = grp->eo_group.eg_objs; obj != NULL; obj = obj->eo_next) { 8067c478bd9Sstevel@tonic-gate switch (obj->eo_catalog) { 8077c478bd9Sstevel@tonic-gate case CAT_FMA_NVLIST: 8087c478bd9Sstevel@tonic-gate if ((err = nvlist_xunpack(obj->eo_item.ei_raw, 8097c478bd9Sstevel@tonic-gate obj->eo_item.ei_size, &nvl, &fmd.d_nva)) != 0) { 8107c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack " 8117c478bd9Sstevel@tonic-gate "log nvpair: %s\n", fmd_strerror(err)); 8127c478bd9Sstevel@tonic-gate return (NULL); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate break; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate case CAT_FMA_TODSEC: 8177c478bd9Sstevel@tonic-gate ftv.ftv_sec = obj->eo_item.ei_uint64; 8187c478bd9Sstevel@tonic-gate break; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate case CAT_FMA_TODNSEC: 8217c478bd9Sstevel@tonic-gate ftv.ftv_nsec = obj->eo_item.ei_uint64; 8227c478bd9Sstevel@tonic-gate break; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate if (nvl == NULL || ftv.ftv_sec == -1ULL || ftv.ftv_nsec == -1ULL) { 8277c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack log event: " 8287c478bd9Sstevel@tonic-gate "required object(s) missing from record group\n"); 8297c478bd9Sstevel@tonic-gate nvlist_free(nvl); 8307c478bd9Sstevel@tonic-gate return (NULL); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) { 8347c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_UNPACK, "failed to unpack log event: " 8357c478bd9Sstevel@tonic-gate "record is missing required '%s' nvpair\n", FM_CLASS); 8367c478bd9Sstevel@tonic-gate nvlist_free(nvl); 8377c478bd9Sstevel@tonic-gate return (NULL); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate return (fmd_event_recreate(FMD_EVT_PROTOCOL, 8417c478bd9Sstevel@tonic-gate &ftv, nvl, class, lp, off, ea_pack_object(grp, NULL, 0))); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * Replay event(s) from the specified log by invoking the specified callback 8467c478bd9Sstevel@tonic-gate * function 'func' for each event. If the log has the FMD_LF_REPLAY flag set, 8477c478bd9Sstevel@tonic-gate * we replay all events after log_skip that have the FMA_RGROUP group tag. 8487c478bd9Sstevel@tonic-gate * This mode is used for the error telemetry log. If the log does not have 8497c478bd9Sstevel@tonic-gate * this flag set (used for ASRU logs), only the most recent event is replayed. 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate void 8527c478bd9Sstevel@tonic-gate fmd_log_replay(fmd_log_t *lp, fmd_log_f *func, void *data) 8537c478bd9Sstevel@tonic-gate { 8547c478bd9Sstevel@tonic-gate ea_object_t obj, *grp; 8557c478bd9Sstevel@tonic-gate ea_object_type_t type; 8567c478bd9Sstevel@tonic-gate ea_catalog_t c; 8577c478bd9Sstevel@tonic-gate fmd_event_t *ep; 8587c478bd9Sstevel@tonic-gate off64_t off, skp; 8597c478bd9Sstevel@tonic-gate uint_t n = 0; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate if (lp->log_stat.st_size == 0 && (lp->log_flags & FMD_LF_REPLAY)) { 8647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 8657c478bd9Sstevel@tonic-gate return; /* we just created this log: never replay events */ 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate while (lp->log_flags & FMD_LF_BUSY) 8697c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&lp->log_cv, &lp->log_lock); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (lp->log_off == lp->log_beg) { 8727c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 8737c478bd9Sstevel@tonic-gate return; /* no records appended yet */ 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate lp->log_flags |= FMD_LF_BUSY; 8777c478bd9Sstevel@tonic-gate skp = lp->log_skip; 8787c478bd9Sstevel@tonic-gate ea_clear(&lp->log_ea); /* resync exacct file */ 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate /* 8817c478bd9Sstevel@tonic-gate * If FMD_LF_REPLAY is set, begin our replay at either log_skip (if it 8827c478bd9Sstevel@tonic-gate * is non-zero) or at log_beg. Otherwise replay from the end (log_off) 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_REPLAY) { 8857c478bd9Sstevel@tonic-gate off = MAX(lp->log_beg, lp->log_skip); 8867c478bd9Sstevel@tonic-gate c = CAT_FMA_RGROUP; 8877c478bd9Sstevel@tonic-gate } else { 8887c478bd9Sstevel@tonic-gate off = lp->log_off; 8897c478bd9Sstevel@tonic-gate c = CAT_FMA_GROUP; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate if (lseek64(lp->log_fd, off, SEEK_SET) != off) { 8937c478bd9Sstevel@tonic-gate fmd_panic("failed to seek %s to 0x%llx\n", 8947c478bd9Sstevel@tonic-gate lp->log_name, (u_longlong_t)off); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * If FMD_LF_REPLAY is not set, back up to the start of the previous 8997c478bd9Sstevel@tonic-gate * object and make sure this object is an EO_GROUP; otherwise return. 9007c478bd9Sstevel@tonic-gate */ 9017c478bd9Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY) && 9027c478bd9Sstevel@tonic-gate (type = ea_previous_object(&lp->log_ea, &obj)) != EO_GROUP) { 9037c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_REPLAY, "last log object is of unexpected " 9047c478bd9Sstevel@tonic-gate "type %d (log may be truncated or corrupt)\n", type); 9057c478bd9Sstevel@tonic-gate goto out; 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate while ((grp = ea_get_object_tree(&lp->log_ea, 1)) != NULL) { 9097c478bd9Sstevel@tonic-gate if (!(lp->log_flags & FMD_LF_REPLAY)) 9107c478bd9Sstevel@tonic-gate off -= ea_pack_object(grp, NULL, 0); 9117c478bd9Sstevel@tonic-gate else if (n == 0 && grp->eo_catalog == CAT_FMA_GROUP) 9127c478bd9Sstevel@tonic-gate skp = off; /* update skip */ 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * We temporarily drop log_lock around the call to unpack the 9167c478bd9Sstevel@tonic-gate * event, hold it, and perform the callback, because these 9177c478bd9Sstevel@tonic-gate * operations may try to acquire log_lock to bump log_refs. 9187c478bd9Sstevel@tonic-gate * We cannot lose control because the FMD_LF_BUSY flag is set. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate if (grp->eo_catalog == c && 9237c478bd9Sstevel@tonic-gate (ep = fmd_log_unpack(lp, grp, off)) != NULL) { 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "replay %s %p off %llx", 9267c478bd9Sstevel@tonic-gate lp->log_tag, (void *)ep, (u_longlong_t)off)); 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate fmd_event_hold(ep); 9297c478bd9Sstevel@tonic-gate func(lp, ep, data); 9307c478bd9Sstevel@tonic-gate fmd_event_rele(ep); 9317c478bd9Sstevel@tonic-gate n++; 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 9357c478bd9Sstevel@tonic-gate off += ea_pack_object(grp, NULL, 0); 9367c478bd9Sstevel@tonic-gate ea_free_object(grp, EUP_ALLOC); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate if (ea_error() != EXR_EOF) { 9407c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_REPLAY, "failed to replay %s event at " 9417c478bd9Sstevel@tonic-gate "offset 0x%llx: %s\n", lp->log_name, (u_longlong_t)off, 9427c478bd9Sstevel@tonic-gate fmd_ea_strerror(ea_error())); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (n == 0) 9467c478bd9Sstevel@tonic-gate skp = off; /* if no replays, move skip to where we ended up */ 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate out: 9497c478bd9Sstevel@tonic-gate if (lseek64(lp->log_fd, lp->log_off, SEEK_SET) != lp->log_off) { 9507c478bd9Sstevel@tonic-gate fmd_panic("failed to seek %s to 0x%llx\n", 9517c478bd9Sstevel@tonic-gate lp->log_name, (u_longlong_t)lp->log_off); 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate if (skp != lp->log_skip) { 9557c478bd9Sstevel@tonic-gate lp->log_flags |= FMD_LF_DIRTY; 9567c478bd9Sstevel@tonic-gate lp->log_skip = skp; 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_BUSY; 9607c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&lp->log_cv); 961d9638e54Smws (void) pthread_mutex_unlock(&lp->log_lock); 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate void 9657c478bd9Sstevel@tonic-gate fmd_log_update(fmd_log_t *lp) 9667c478bd9Sstevel@tonic-gate { 9677c478bd9Sstevel@tonic-gate ea_object_t toc, item; 9687c478bd9Sstevel@tonic-gate off64_t skip = 0; 9697c478bd9Sstevel@tonic-gate size_t size; 9707c478bd9Sstevel@tonic-gate void *buf; 9717c478bd9Sstevel@tonic-gate 9727c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_DIRTY) { 9757c478bd9Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_DIRTY; 9767c478bd9Sstevel@tonic-gate skip = lp->log_skip; 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * If the skip needs to be updated, construct a TOC record group 9837c478bd9Sstevel@tonic-gate * containing the skip offset and overwrite the TOC in-place. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate if (skip != 0 && ea_set_group(&toc, CAT_FMA_GROUP) == 0 && 9867c478bd9Sstevel@tonic-gate ea_set_item(&item, CAT_FMA_OFFSET, &skip, 0) == 0) { 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&toc, &item); 9897c478bd9Sstevel@tonic-gate size = ea_pack_object(&toc, NULL, 0); 9907c478bd9Sstevel@tonic-gate buf = fmd_alloc(size, FMD_SLEEP); 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate (void) ea_pack_object(&toc, buf, size); 9937c478bd9Sstevel@tonic-gate ASSERT(lp->log_toc + size == lp->log_beg); 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate if (pwrite64(lp->log_fd, buf, size, lp->log_toc) == size) { 9967c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_LOG, "updated skip to %llx", skip)); 9977c478bd9Sstevel@tonic-gate } else { 9987c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_UPDATE, 9997c478bd9Sstevel@tonic-gate "failed to log_update %s", lp->log_tag); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate fmd_free(buf, size); 10037c478bd9Sstevel@tonic-gate (void) ea_free_item(&item, EUP_ALLOC); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Rotate the specified log by renaming its underlying file to a staging file 10097c478bd9Sstevel@tonic-gate * that can be handed off to logadm(1M) or an administrator script. If the 10107c478bd9Sstevel@tonic-gate * rename succeeds, open a new log file using the old path and return it. 10117c478bd9Sstevel@tonic-gate * Note that we are relying our caller to use some higher-level mechanism to 10127c478bd9Sstevel@tonic-gate * ensure that fmd_log_rotate() cannot be called while other threads are 10137c478bd9Sstevel@tonic-gate * attempting fmd_log_append() using the same log (fmd's d_log_lock is used 10147c478bd9Sstevel@tonic-gate * for the global errlog and fltlog). 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate fmd_log_t * 10177c478bd9Sstevel@tonic-gate fmd_log_rotate(fmd_log_t *lp) 10187c478bd9Sstevel@tonic-gate { 10197c478bd9Sstevel@tonic-gate char npath[PATH_MAX]; 10207c478bd9Sstevel@tonic-gate fmd_log_t *nlp; 10217c478bd9Sstevel@tonic-gate 1022*9dd0f810Scindi (void) snprintf(npath, sizeof (npath), "%s+", lp->log_name); 1023*9dd0f810Scindi 1024*9dd0f810Scindi /* 1025*9dd0f810Scindi * Open new log file. 1026*9dd0f810Scindi */ 1027*9dd0f810Scindi if ((nlp = fmd_log_open("", npath, lp->log_tag)) == NULL) { 1028*9dd0f810Scindi fmd_error(EFMD_LOG_ROTATE, "failed to open %s", npath); 1029*9dd0f810Scindi (void) fmd_set_errno(EFMD_LOG_ROTATE); 1030*9dd0f810Scindi return (NULL); 1031*9dd0f810Scindi } 1032*9dd0f810Scindi 10337c478bd9Sstevel@tonic-gate (void) snprintf(npath, sizeof (npath), "%s.0-", lp->log_name); 10347c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&lp->log_lock); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * Check for any pending commits to drain before proceeding. We can't 10387c478bd9Sstevel@tonic-gate * rotate the log out if commits are pending because if we die after 10397c478bd9Sstevel@tonic-gate * the log is moved aside, we won't be able to replay them on restart. 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate if (lp->log_pending != 0) { 10427c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 1043*9dd0f810Scindi (void) unlink(nlp->log_name); 1044*9dd0f810Scindi fmd_log_rele(nlp); 10457c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTBUSY); 10467c478bd9Sstevel@tonic-gate return (NULL); 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate if (rename(lp->log_name, npath) != 0) { 10507c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10517c478bd9Sstevel@tonic-gate fmd_error(EFMD_LOG_ROTATE, "failed to rename %s", lp->log_name); 1052*9dd0f810Scindi (void) unlink(nlp->log_name); 1053*9dd0f810Scindi fmd_log_rele(nlp); 10547c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTATE); 10557c478bd9Sstevel@tonic-gate return (NULL); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 1058*9dd0f810Scindi if (rename(nlp->log_name, lp->log_name) != 0) { 10597c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 1060*9dd0f810Scindi fmd_error(EFMD_LOG_ROTATE, "failed to rename %s", 1061*9dd0f810Scindi nlp->log_name); 1062*9dd0f810Scindi (void) unlink(nlp->log_name); 1063*9dd0f810Scindi fmd_log_rele(nlp); 10647c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_LOG_ROTATE); 10657c478bd9Sstevel@tonic-gate return (NULL); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* 1069*9dd0f810Scindi * Change name of new log file 1070*9dd0f810Scindi */ 1071*9dd0f810Scindi fmd_strfree(nlp->log_name); 1072*9dd0f810Scindi nlp->log_name = fmd_strdup(lp->log_name, FMD_SLEEP); 1073*9dd0f810Scindi 1074*9dd0f810Scindi /* 10757c478bd9Sstevel@tonic-gate * If we've rotated the log, no pending events exist so we don't have 10767c478bd9Sstevel@tonic-gate * any more commits coming, and our caller should have arranged for 10777c478bd9Sstevel@tonic-gate * no more calls to append. As such, we can close log_fd for good. 10787c478bd9Sstevel@tonic-gate */ 10797c478bd9Sstevel@tonic-gate if (lp->log_flags & FMD_LF_EAOPEN) { 10807c478bd9Sstevel@tonic-gate (void) ea_close(&lp->log_ea); 10817c478bd9Sstevel@tonic-gate lp->log_flags &= ~FMD_LF_EAOPEN; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate (void) close(lp->log_fd); 10857c478bd9Sstevel@tonic-gate lp->log_fd = -1; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&lp->log_lock); 10887c478bd9Sstevel@tonic-gate return (nlp); 10897c478bd9Sstevel@tonic-gate } 1090