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