17a7741afSMartin Matuska /* 27a7741afSMartin Matuska * CDDL HEADER START 37a7741afSMartin Matuska * 47a7741afSMartin Matuska * The contents of this file are subject to the terms of the 57a7741afSMartin Matuska * Common Development and Distribution License (the "License"). 67a7741afSMartin Matuska * You may not use this file except in compliance with the License. 77a7741afSMartin Matuska * 87a7741afSMartin Matuska * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97a7741afSMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 107a7741afSMartin Matuska * See the License for the specific language governing permissions 117a7741afSMartin Matuska * and limitations under the License. 127a7741afSMartin Matuska * 137a7741afSMartin Matuska * When distributing Covered Code, include this CDDL HEADER in each 147a7741afSMartin Matuska * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157a7741afSMartin Matuska * If applicable, add the following below this CDDL HEADER, with the 167a7741afSMartin Matuska * fields enclosed by brackets "[]" replaced with your own identifying 177a7741afSMartin Matuska * information: Portions Copyright [yyyy] [name of copyright owner] 187a7741afSMartin Matuska * 197a7741afSMartin Matuska * CDDL HEADER END 207a7741afSMartin Matuska */ 217a7741afSMartin Matuska /* 227a7741afSMartin Matuska * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 237a7741afSMartin Matuska * Copyright (c) 2012, 2014 by Delphix. All rights reserved. 247a7741afSMartin Matuska * Copyright (c) 2024, Rob Norris <robn@despairlabs.com> 257a7741afSMartin Matuska */ 267a7741afSMartin Matuska 277a7741afSMartin Matuska #include <sys/zfs_context.h> 287a7741afSMartin Matuska 297a7741afSMartin Matuska typedef struct zfs_dbgmsg { 307a7741afSMartin Matuska list_node_t zdm_node; 317a7741afSMartin Matuska uint64_t zdm_timestamp; 327a7741afSMartin Matuska uint_t zdm_size; 337a7741afSMartin Matuska char zdm_msg[]; /* variable length allocation */ 347a7741afSMartin Matuska } zfs_dbgmsg_t; 357a7741afSMartin Matuska 367a7741afSMartin Matuska static list_t zfs_dbgmsgs; 377a7741afSMartin Matuska static kmutex_t zfs_dbgmsgs_lock; 38*87bf66d4SMartin Matuska static uint_t zfs_dbgmsg_size = 0; 39*87bf66d4SMartin Matuska static uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */ 407a7741afSMartin Matuska 417a7741afSMartin Matuska int zfs_dbgmsg_enable = B_TRUE; 427a7741afSMartin Matuska 43*87bf66d4SMartin Matuska static void 44*87bf66d4SMartin Matuska zfs_dbgmsg_purge(uint_t max_size) 45*87bf66d4SMartin Matuska { 46*87bf66d4SMartin Matuska while (zfs_dbgmsg_size > max_size) { 47*87bf66d4SMartin Matuska zfs_dbgmsg_t *zdm = list_remove_head(&zfs_dbgmsgs); 48*87bf66d4SMartin Matuska if (zdm == NULL) 49*87bf66d4SMartin Matuska return; 50*87bf66d4SMartin Matuska 51*87bf66d4SMartin Matuska uint_t size = zdm->zdm_size; 52*87bf66d4SMartin Matuska kmem_free(zdm, size); 53*87bf66d4SMartin Matuska zfs_dbgmsg_size -= size; 54*87bf66d4SMartin Matuska } 55*87bf66d4SMartin Matuska } 56*87bf66d4SMartin Matuska 577a7741afSMartin Matuska void 587a7741afSMartin Matuska zfs_dbgmsg_init(void) 597a7741afSMartin Matuska { 607a7741afSMartin Matuska list_create(&zfs_dbgmsgs, sizeof (zfs_dbgmsg_t), 617a7741afSMartin Matuska offsetof(zfs_dbgmsg_t, zdm_node)); 627a7741afSMartin Matuska mutex_init(&zfs_dbgmsgs_lock, NULL, MUTEX_DEFAULT, NULL); 637a7741afSMartin Matuska } 647a7741afSMartin Matuska 657a7741afSMartin Matuska void 667a7741afSMartin Matuska zfs_dbgmsg_fini(void) 677a7741afSMartin Matuska { 687a7741afSMartin Matuska zfs_dbgmsg_t *zdm; 697a7741afSMartin Matuska while ((zdm = list_remove_head(&zfs_dbgmsgs))) 707a7741afSMartin Matuska umem_free(zdm, zdm->zdm_size); 717a7741afSMartin Matuska mutex_destroy(&zfs_dbgmsgs_lock); 727a7741afSMartin Matuska } 737a7741afSMartin Matuska 747a7741afSMartin Matuska void 757a7741afSMartin Matuska __set_error(const char *file, const char *func, int line, int err) 767a7741afSMartin Matuska { 777a7741afSMartin Matuska if (zfs_flags & ZFS_DEBUG_SET_ERROR) 787a7741afSMartin Matuska __dprintf(B_FALSE, file, func, line, "error %lu", 797a7741afSMartin Matuska (ulong_t)err); 807a7741afSMartin Matuska } 817a7741afSMartin Matuska 827a7741afSMartin Matuska void 837a7741afSMartin Matuska __zfs_dbgmsg(char *buf) 847a7741afSMartin Matuska { 857a7741afSMartin Matuska uint_t size = sizeof (zfs_dbgmsg_t) + strlen(buf) + 1; 867a7741afSMartin Matuska zfs_dbgmsg_t *zdm = umem_zalloc(size, KM_SLEEP); 877a7741afSMartin Matuska zdm->zdm_size = size; 887a7741afSMartin Matuska zdm->zdm_timestamp = gethrestime_sec(); 897a7741afSMartin Matuska strcpy(zdm->zdm_msg, buf); 907a7741afSMartin Matuska 917a7741afSMartin Matuska mutex_enter(&zfs_dbgmsgs_lock); 927a7741afSMartin Matuska list_insert_tail(&zfs_dbgmsgs, zdm); 93*87bf66d4SMartin Matuska zfs_dbgmsg_size += size; 94*87bf66d4SMartin Matuska zfs_dbgmsg_purge(zfs_dbgmsg_maxsize); 957a7741afSMartin Matuska mutex_exit(&zfs_dbgmsgs_lock); 967a7741afSMartin Matuska } 977a7741afSMartin Matuska 987a7741afSMartin Matuska void 997a7741afSMartin Matuska zfs_dbgmsg_print(int fd, const char *tag) 1007a7741afSMartin Matuska { 1017a7741afSMartin Matuska ssize_t ret __attribute__((unused)); 1027a7741afSMartin Matuska 1037a7741afSMartin Matuska mutex_enter(&zfs_dbgmsgs_lock); 1047a7741afSMartin Matuska 1057a7741afSMartin Matuska /* 1067a7741afSMartin Matuska * We use write() in this function instead of printf() 1077a7741afSMartin Matuska * so it is safe to call from a signal handler. 1087a7741afSMartin Matuska */ 1097a7741afSMartin Matuska ret = write(fd, "ZFS_DBGMSG(", 11); 1107a7741afSMartin Matuska ret = write(fd, tag, strlen(tag)); 1117a7741afSMartin Matuska ret = write(fd, ") START:\n", 9); 1127a7741afSMartin Matuska 1137a7741afSMartin Matuska for (zfs_dbgmsg_t *zdm = list_head(&zfs_dbgmsgs); zdm != NULL; 1147a7741afSMartin Matuska zdm = list_next(&zfs_dbgmsgs, zdm)) { 1157a7741afSMartin Matuska ret = write(fd, zdm->zdm_msg, strlen(zdm->zdm_msg)); 1167a7741afSMartin Matuska ret = write(fd, "\n", 1); 1177a7741afSMartin Matuska } 1187a7741afSMartin Matuska 1197a7741afSMartin Matuska ret = write(fd, "ZFS_DBGMSG(", 11); 1207a7741afSMartin Matuska ret = write(fd, tag, strlen(tag)); 1217a7741afSMartin Matuska ret = write(fd, ") END\n", 6); 1227a7741afSMartin Matuska 1237a7741afSMartin Matuska mutex_exit(&zfs_dbgmsgs_lock); 1247a7741afSMartin Matuska } 125