1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/nvpair.h> 31 #include <sys/fs/zfs.h> 32 #include <math.h> 33 34 #include <libzutil.h> 35 36 static void 37 dump_ddt_stat(const ddt_stat_t *dds, int h) 38 { 39 char refcnt[6]; 40 char blocks[6], lsize[6], psize[6], dsize[6]; 41 char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6]; 42 43 if (dds == NULL || dds->dds_blocks == 0) 44 return; 45 46 if (h == -1) 47 (void) strcpy(refcnt, "Total"); 48 else 49 zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt)); 50 51 zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks)); 52 zfs_nicebytes(dds->dds_lsize, lsize, sizeof (lsize)); 53 zfs_nicebytes(dds->dds_psize, psize, sizeof (psize)); 54 zfs_nicebytes(dds->dds_dsize, dsize, sizeof (dsize)); 55 zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks)); 56 zfs_nicebytes(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize)); 57 zfs_nicebytes(dds->dds_ref_psize, ref_psize, sizeof (ref_psize)); 58 zfs_nicebytes(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize)); 59 60 (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n", 61 refcnt, 62 blocks, lsize, psize, dsize, 63 ref_blocks, ref_lsize, ref_psize, ref_dsize); 64 } 65 66 /* 67 * Print the DDT histogram and the column totals. 68 */ 69 void 70 zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh) 71 { 72 int h; 73 74 (void) printf("\n"); 75 76 (void) printf("bucket " 77 " allocated " 78 " referenced \n"); 79 (void) printf("______ " 80 "______________________________ " 81 "______________________________\n"); 82 83 (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n", 84 "refcnt", 85 "blocks", "LSIZE", "PSIZE", "DSIZE", 86 "blocks", "LSIZE", "PSIZE", "DSIZE"); 87 88 (void) printf("%6s %6s %5s %5s %5s %6s %5s %5s %5s\n", 89 "------", 90 "------", "-----", "-----", "-----", 91 "------", "-----", "-----", "-----"); 92 93 for (h = 0; h < 64; h++) 94 dump_ddt_stat(&ddh->ddh_stat[h], h); 95 96 dump_ddt_stat(dds_total, -1); 97 98 (void) printf("\n"); 99 } 100 101 /* 102 * Process the buffer of nvlists, unpacking and storing each nvlist record 103 * into 'records'. 'leftover' is set to the number of bytes that weren't 104 * processed as there wasn't a complete record. 105 */ 106 int 107 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover, 108 nvlist_t ***records, uint_t *numrecords) 109 { 110 uint64_t reclen; 111 nvlist_t *nv; 112 int i; 113 void *tmp; 114 115 while (bytes_read > sizeof (reclen)) { 116 117 /* get length of packed record (stored as little endian) */ 118 for (i = 0, reclen = 0; i < sizeof (reclen); i++) 119 reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i); 120 121 if (bytes_read < sizeof (reclen) + reclen) 122 break; 123 124 /* unpack record */ 125 int err = nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0); 126 if (err != 0) 127 return (err); 128 bytes_read -= sizeof (reclen) + reclen; 129 buf += sizeof (reclen) + reclen; 130 131 /* add record to nvlist array */ 132 (*numrecords)++; 133 if (ISP2(*numrecords + 1)) { 134 tmp = realloc(*records, 135 *numrecords * 2 * sizeof (nvlist_t *)); 136 if (tmp == NULL) { 137 nvlist_free(nv); 138 (*numrecords)--; 139 return (ENOMEM); 140 } 141 *records = tmp; 142 } 143 (*records)[*numrecords - 1] = nv; 144 } 145 146 *leftover = bytes_read; 147 return (0); 148 } 149 150 /* 151 * Floating point sleep(). Allows you to pass in a floating point value for 152 * seconds. 153 */ 154 void 155 fsleep(float sec) 156 { 157 struct timespec req; 158 req.tv_sec = floor(sec); 159 req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC; 160 nanosleep(&req, NULL); 161 } 162 163 /* 164 * Get environment variable 'env' and return it as an integer. 165 * If 'env' is not set, then return 'default_val' instead. 166 */ 167 int 168 zpool_getenv_int(const char *env, int default_val) 169 { 170 char *str; 171 int val; 172 str = getenv(env); 173 if ((str == NULL) || sscanf(str, "%d", &val) != 1 || 174 val < 0) { 175 val = default_val; 176 } 177 return (val); 178 } 179