1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <mdb/mdb_modapi.h> 29 30 #include <sys/types.h> 31 #include <sys/uio.h> 32 #include <sys/vnode.h> 33 #include <sys/fs/ufs_log.h> 34 #include "ufs_cmds.h" 35 36 37 typedef struct ufslogmap_walk_data { 38 mapentry_t me; 39 mapentry_t *start_addr; 40 mapentry_t *prev_addr; 41 } ufslogmap_walk_data_t; 42 43 /* 44 * Ensure we are started with a user specified address. 45 * We also allocate a ufslogmap_walk_data_t for storage, 46 * and save this using the walk_data pointer. 47 */ 48 int 49 ufslogmap_walk_init(mdb_walk_state_t *wsp) 50 { 51 ufslogmap_walk_data_t *uw; 52 53 if (wsp->walk_addr == NULL) { 54 mdb_warn("must specify an address\n"); 55 return (WALK_ERR); 56 } 57 58 uw = mdb_zalloc(sizeof (ufslogmap_walk_data_t), UM_SLEEP | UM_GC); 59 60 uw->start_addr = (mapentry_t *)wsp->walk_addr; 61 wsp->walk_data = uw; 62 return (WALK_NEXT); 63 } 64 65 /* 66 * Routine to step through one element of the list. 67 */ 68 int 69 ufslogmap_walk_step(mdb_walk_state_t *wsp) 70 { 71 ufslogmap_walk_data_t *uw = wsp->walk_data; 72 uintptr_t walk_addr = wsp->walk_addr; 73 74 /* 75 * Read the mapentry at the current walk address 76 */ 77 if (mdb_vread(&uw->me, sizeof (mapentry_t), walk_addr) == -1) { 78 mdb_warn("failed to read mapentry_t at %p", walk_addr); 79 return (WALK_DONE); 80 } 81 82 /* 83 * Check for empty list. 84 */ 85 if (uw->me.me_next == uw->me.me_prev) { 86 return (WALK_DONE); 87 } 88 89 /* 90 * Check for end of list. 91 */ 92 if (uw->me.me_next == uw->start_addr) { 93 return (WALK_DONE); 94 } 95 96 /* 97 * Check for proper linkage 98 */ 99 if (uw->prev_addr && (uw->me.me_prev != uw->prev_addr)) { 100 mdb_warn("invalid linkage mapentry_t at %p", walk_addr); 101 return (WALK_DONE); 102 } 103 uw->prev_addr = (mapentry_t *)walk_addr; 104 105 /* 106 * Save next address and call callback with current address 107 */ 108 wsp->walk_addr = (uintptr_t)uw->me.me_next; 109 return (wsp->walk_callback(walk_addr, wsp->walk_data, 110 wsp->walk_cbdata)); 111 } 112 113 static const char * 114 delta2str(delta_t delta_type) 115 { 116 switch (delta_type) { 117 case DT_NONE: return ("none"); 118 case DT_SB: return ("sb"); 119 case DT_CG: return ("cg"); 120 case DT_SI: return ("si"); 121 case DT_AB: return ("ab"); 122 case DT_ABZERO: return ("abzero"); 123 case DT_DIR: return ("dir"); 124 case DT_INODE: return ("inode"); 125 case DT_FBI: return ("fbi"); 126 case DT_QR: return ("quota"); 127 case DT_COMMIT: return ("commit"); 128 case DT_CANCEL: return ("cancel"); 129 case DT_BOT: return ("trans"); 130 case DT_EOT: return ("etrans"); 131 case DT_UD: return ("udata"); 132 case DT_SUD: return ("sudata"); 133 case DT_SHAD: return ("shadow"); 134 default: return ("???"); 135 } 136 } 137 138 /* ARGSUSED */ 139 int 140 mapentry_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 141 { 142 mapentry_t me; 143 144 if (!(flags & DCMD_ADDRSPEC)) 145 return (DCMD_USAGE); 146 147 if (DCMD_HDRSPEC(flags)) { 148 mdb_printf("%<u>%?s %6s %8s %8s %s%</u>\n", 149 "ADDR", "TYPE", "SIZE", "TRANS", "HANDLER"); 150 } 151 152 if (mdb_vread(&me, sizeof (me), addr) == -1) { 153 mdb_warn("couldn't read ufslog mapentry at %p", addr); 154 return (DCMD_ABORT); 155 } 156 157 /* 158 * Validate mapentry 159 */ 160 if (me.me_delta.d_typ >= DT_MAX) { 161 mdb_warn("Invalid delta type for mapentry at %p", addr); 162 return (DCMD_ABORT); 163 } 164 165 mdb_printf("%0?p %6s %8x %8x %a\n", 166 addr, 167 delta2str(me.me_delta.d_typ), 168 me.me_delta.d_nb, 169 me.me_tid, 170 me.me_func); 171 172 return (DCMD_OK); 173 } 174 175 typedef struct { 176 uint64_t nentries; /* number of mapentries */ 177 uint64_t totalsize; /* total number of bytes */ 178 uint32_t transid; /* first transaction id */ 179 int transdiff; /* transaction different */ 180 uint32_t delta_cnt[DT_MAX]; /* count of each delta */ 181 uint64_t delta_sum[DT_MAX]; /* total number of bytes for delta */ 182 } mapstats_t; 183 184 /* ARGSUSED */ 185 int 186 mapadd(uintptr_t *addr, ufslogmap_walk_data_t *uw, mapstats_t *msp) 187 { 188 if (msp->nentries == 0) { 189 msp->transid = uw->me.me_tid; 190 } else { 191 if (msp->transid != uw->me.me_tid) { 192 msp->transdiff = TRUE; 193 } 194 } 195 msp->nentries++; 196 msp->totalsize += uw->me.me_nb; 197 if (uw->me.me_dt >= DT_MAX) { 198 mdb_warn("Invalid delta type for mapentry at %p", addr); 199 } else { 200 msp->delta_cnt[uw->me.me_dt]++; 201 msp->delta_sum[uw->me.me_dt] += uw->me.me_nb; 202 } 203 return (WALK_NEXT); 204 } 205 206 /*ARGSUSED*/ 207 int 208 mapstats_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 209 { 210 mapstats_t *msp; 211 int i; 212 213 if (!(flags & DCMD_ADDRSPEC)) 214 return (DCMD_USAGE); 215 216 msp = mdb_zalloc(sizeof (mapstats_t), UM_SLEEP | UM_GC); 217 msp->transdiff = FALSE; 218 219 if (mdb_pwalk("ufslogmap", (mdb_walk_cb_t)mapadd, msp, addr) == -1) { 220 mdb_warn("can't walk ufslogmap for stats"); 221 return (DCMD_ERR); 222 } 223 224 mdb_printf("Number of entries 0x%llx\n", msp->nentries); 225 mdb_printf("Total map size 0x%llx\n", msp->totalsize); 226 if (msp->transdiff) { 227 mdb_printf("Multiple transactions\n"); 228 } else { 229 mdb_printf("All the same transaction id = %d\n", msp->transid); 230 } 231 if (msp->nentries) { 232 mdb_printf("%<u>delta count(hex) avsize(hex)%</u>\n"); 233 for (i = 0; i < DT_MAX; i++) { 234 if (msp->delta_cnt[i]) { 235 mdb_printf("%6s %10X %10X\n", 236 delta2str(i), msp->delta_cnt[i], 237 msp->delta_sum[i] / msp->delta_cnt[i]); 238 } 239 } 240 } 241 return (DCMD_OK); 242 } 243