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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <mdb/mdb_modapi.h> 27 #include <sys/types.h> 28 #include <sys/sysmacros.h> 29 #include <sys/time.h> 30 #include <sys/vnode.h> 31 #include <sys/fs/snode.h> 32 33 typedef struct snode_walk_data { 34 int sw_stablesz; 35 uintptr_t sw_stable; 36 } snode_walk_data_t; 37 38 int 39 snode_walk_init(mdb_walk_state_t *wsp) 40 { 41 int stablesz; 42 GElf_Sym sym; 43 uintptr_t stable; 44 uintptr_t sp; 45 snode_walk_data_t *sw; 46 47 if (mdb_readvar(&stablesz, "stablesz") == -1) { 48 mdb_warn("failed to read 'stablesz'"); 49 return (WALK_ERR); 50 } 51 52 if (stablesz == 0) 53 return (WALK_DONE); 54 55 if (mdb_lookup_by_name("stable", &sym) == -1) { 56 mdb_warn("failed to read 'stable'"); 57 return (WALK_ERR); 58 } 59 60 stable = (uintptr_t)sym.st_value; 61 62 if (mdb_vread(&sp, sizeof (sp), stable) == -1) { 63 mdb_warn("failed to read stable entry at %p", stable); 64 return (WALK_DONE); 65 } 66 67 sw = mdb_alloc(sizeof (snode_walk_data_t), UM_SLEEP); 68 sw->sw_stablesz = stablesz; 69 sw->sw_stable = stable; 70 71 wsp->walk_addr = sp; 72 wsp->walk_data = sw; 73 74 return (WALK_NEXT); 75 } 76 77 int 78 snode_walk_step(mdb_walk_state_t *wsp) 79 { 80 uintptr_t addr = wsp->walk_addr; 81 snode_walk_data_t *sw = wsp->walk_data; 82 struct snode *sp; 83 struct snode snode; 84 85 while (addr == 0) { 86 if (--sw->sw_stablesz == 0) 87 return (WALK_DONE); 88 89 sw->sw_stable += sizeof (struct snode *); 90 91 if (mdb_vread(&sp, sizeof (sp), sw->sw_stable) == -1) { 92 mdb_warn("failed to read stable entry at %p", 93 sw->sw_stable); 94 return (WALK_DONE); 95 } 96 addr = (uintptr_t)sp; 97 } 98 99 if (mdb_vread(&snode, sizeof (snode), addr) == -1) { 100 mdb_warn("failed to read snode at %p", addr); 101 return (WALK_DONE); 102 } 103 104 wsp->walk_addr = (uintptr_t)snode.s_next; 105 106 return (wsp->walk_callback(addr, &snode, wsp->walk_cbdata)); 107 } 108 109 void 110 snode_walk_fini(mdb_walk_state_t *wsp) 111 { 112 mdb_free(wsp->walk_data, sizeof (snode_walk_data_t)); 113 } 114 115 typedef struct snode_cbdata { 116 int sd_major; 117 int sd_minor; 118 int sd_verbose; 119 } snode_cbdata_t; 120 121 static int 122 snode_cb(uintptr_t addr, const struct snode *snode, snode_cbdata_t *sd) 123 { 124 static const mdb_bitmask_t s_flag_masks[] = { 125 { "UPD", SUPD, SUPD }, 126 { "ACC", SACC, SACC }, 127 { "CHG", SCHG, SCHG }, 128 { "PRIV", SPRIV, SPRIV }, 129 { "LOFFSET", SLOFFSET, SLOFFSET }, 130 { "LOCKED", SLOCKED, SLOCKED }, 131 { "WANT", SWANT, SWANT }, 132 { "CLONE", SCLONE, SCLONE }, 133 { "NEEDCLOSE", SNEEDCLOSE, SNEEDCLOSE }, 134 { "DIPSET", SDIPSET, SDIPSET }, 135 { "SIZEVALID", SSIZEVALID, SSIZEVALID }, 136 { "MUXED", SMUXED, SMUXED }, 137 { "SELFCLONE", SSELFCLONE, SSELFCLONE }, 138 { "NOFLUSH", SNOFLUSH, SNOFLUSH }, 139 { "CLOSING", SCLOSING, SCLOSING }, 140 { NULL, 0, 0 } 141 }; 142 143 int major = getmajor(snode->s_dev); 144 int minor = getminor(snode->s_dev); 145 146 if (sd->sd_major != -1 && sd->sd_major != major) 147 return (WALK_NEXT); 148 149 if (sd->sd_minor != -1 && sd->sd_minor != minor) 150 return (WALK_NEXT); 151 152 if (sd->sd_verbose) { 153 mdb_printf("%0?p %?p %6d %16lx <%b>\n", 154 addr, snode->s_vnode, snode->s_count, snode->s_dev, 155 snode->s_flag, s_flag_masks); 156 } else { 157 mdb_printf("%p\n", addr); 158 } 159 160 return (WALK_NEXT); 161 } 162 163 /*ARGSUSED*/ 164 int 165 snode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 166 { 167 snode_cbdata_t sd; 168 struct snode snode; 169 uintptr_t major = 0, dev = 0; 170 171 sd.sd_major = -1; 172 sd.sd_minor = -1; 173 sd.sd_verbose = !(flags & DCMD_PIPE_OUT); 174 175 if (mdb_getopts(argc, argv, 176 'm', MDB_OPT_UINTPTR, &major, 177 'd', MDB_OPT_UINTPTR, &dev, NULL) != argc) 178 return (DCMD_USAGE); 179 180 if (dev != 0) { 181 sd.sd_major = getmajor(dev); 182 sd.sd_minor = getminor(dev); 183 } 184 185 if (major != 0) 186 sd.sd_major = major; 187 188 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 189 mdb_printf("%<u>%?s %?s %6s %16s %-15s%</u>\n", 190 "ADDR", "VNODE", "COUNT", "DEV", "FLAG"); 191 } 192 193 if (!(flags & DCMD_ADDRSPEC)) { 194 if (mdb_walk("snode", (mdb_walk_cb_t)snode_cb, &sd) == -1) { 195 mdb_warn("can't walk snodes"); 196 return (DCMD_ERR); 197 } 198 return (DCMD_OK); 199 } 200 201 if (mdb_vread(&snode, sizeof (snode), addr) == -1) { 202 mdb_warn("failed to read snode structure at %p", addr); 203 return (DCMD_ERR); 204 } 205 206 snode_cb(addr, &snode, &sd); 207 208 return (DCMD_OK); 209 } 210 211 /*ARGSUSED3*/ 212 int 213 major2snode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 214 { 215 snode_cbdata_t sd; 216 217 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 218 return (DCMD_USAGE); 219 220 sd.sd_major = addr; 221 sd.sd_minor = -1; 222 sd.sd_verbose = 0; 223 224 if (mdb_pwalk("snode", (mdb_walk_cb_t)snode_cb, &sd, 0) != 0) 225 return (DCMD_ERR); 226 227 return (DCMD_OK); 228 } 229 230 /*ARGSUSED3*/ 231 int 232 dev2snode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 233 { 234 snode_cbdata_t sd; 235 236 if (!(flags & DCMD_ADDRSPEC) || argc != 0) 237 return (DCMD_USAGE); 238 239 sd.sd_major = getmajor(addr); 240 sd.sd_minor = getminor(addr); 241 sd.sd_verbose = 0; 242 243 if (mdb_pwalk("snode", (mdb_walk_cb_t)snode_cb, &sd, 0) != 0) 244 return (DCMD_ERR); 245 246 return (DCMD_OK); 247 } 248 249 void 250 snode_help(void) 251 { 252 mdb_printf("Options:\n" 253 " -d device filter snodes of the specified dev_t\n" 254 " -m major filter snodes of the specified major number\n"); 255 } 256 257 /* 258 * MDB module linkage 259 */ 260 static const mdb_dcmd_t dcmds[] = { 261 { "dev2snode", ":", "given a dev_t, return the snode", dev2snode }, 262 { "major2snode", ":", "given a major number, return the snode(s)", 263 major2snode }, 264 { "snode", "?[-d device] [-m major]", 265 "filter and display snode structures", snode, snode_help }, 266 { NULL } 267 }; 268 269 static const mdb_walker_t walkers[] = { 270 { "snode", "walk global snode lists", 271 snode_walk_init, snode_walk_step, snode_walk_fini }, 272 { NULL } 273 }; 274 275 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 276 277 const mdb_modinfo_t * 278 _mdb_init(void) 279 { 280 return (&modinfo); 281 } 282