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