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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/vfs.h> 31 #include <sys/fs/lofs_node.h> 32 #include <sys/fs/lofs_info.h> 33 34 #include <mdb/mdb_modapi.h> 35 36 typedef struct lnode_walk { 37 struct lobucket *lw_table; /* Snapshot of hash table */ 38 uint_t lw_tabsz; /* Size of hash table */ 39 uint_t lw_tabi; /* Current table index */ 40 lnode_t *lw_lnode; /* Current buffer */ 41 } lnode_walk_t; 42 43 int 44 lnode_walk_init(mdb_walk_state_t *wsp) 45 { 46 lnode_walk_t *lwp; 47 48 int lofsfstype; 49 struct vfs vfs; 50 struct loinfo loinfo; 51 52 if (mdb_readvar(&lofsfstype, "lofsfstype") == -1) { 53 mdb_warn("failed to read 'lofsfstype' symbol\n"); 54 return (WALK_ERR); 55 } 56 57 if (wsp->walk_addr == NULL) { 58 uintptr_t rootvfsp, vfsp; 59 uint_t htsize; 60 61 lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP); 62 63 retry: 64 lwp->lw_tabsz = 0; 65 if (mdb_readvar(&rootvfsp, "rootvfs") == -1) { 66 mdb_warn("failed to read 'rootvfs' symbol\n"); 67 mdb_free(lwp, sizeof (lnode_walk_t)); 68 return (WALK_ERR); 69 } 70 71 vfsp = rootvfsp; 72 do { 73 (void) mdb_vread(&vfs, sizeof (vfs), vfsp); 74 if (lofsfstype != vfs.vfs_fstype) { 75 vfsp = (uintptr_t)vfs.vfs_next; 76 continue; 77 } 78 (void) mdb_vread(&loinfo, sizeof (struct loinfo), 79 (uintptr_t)vfs.vfs_data); 80 lwp->lw_tabsz += loinfo.li_htsize; 81 vfsp = (uintptr_t)vfs.vfs_next; 82 } while (vfsp != rootvfsp); 83 84 if (lwp->lw_tabsz == 0) { 85 /* 86 * No lofs filesystems mounted. 87 */ 88 mdb_free(lwp, sizeof (lnode_walk_t)); 89 return (WALK_DONE); 90 } 91 lwp->lw_table = mdb_alloc(lwp->lw_tabsz * 92 sizeof (struct lobucket), UM_SLEEP); 93 htsize = 0; 94 95 vfsp = rootvfsp; 96 do { 97 (void) mdb_vread(&vfs, sizeof (vfs), vfsp); 98 if (lofsfstype != vfs.vfs_fstype) { 99 vfsp = (uintptr_t)vfs.vfs_next; 100 continue; 101 } 102 (void) mdb_vread(&loinfo, sizeof (struct loinfo), 103 (uintptr_t)vfs.vfs_data); 104 if (htsize + loinfo.li_htsize > lwp->lw_tabsz) { 105 /* 106 * Something must have resized. 107 */ 108 mdb_free(lwp->lw_table, 109 lwp->lw_tabsz * sizeof (struct lobucket)); 110 goto retry; 111 } 112 (void) mdb_vread(lwp->lw_table + htsize, 113 loinfo.li_htsize * sizeof (struct lobucket), 114 (uintptr_t)loinfo.li_hashtable); 115 htsize += loinfo.li_htsize; 116 vfsp = (uintptr_t)vfs.vfs_next; 117 } while (vfsp != rootvfsp); 118 } else { 119 if (mdb_vread(&vfs, sizeof (vfs_t), wsp->walk_addr) == -1) { 120 mdb_warn("failed to read from '%p'\n", wsp->walk_addr); 121 return (WALK_ERR); 122 } 123 if (lofsfstype != vfs.vfs_fstype) { 124 mdb_warn("%p does not point to a lofs mount vfs\n", 125 wsp->walk_addr); 126 return (WALK_ERR); 127 } 128 if (mdb_vread(&loinfo, sizeof (loinfo), 129 (uintptr_t)vfs.vfs_data) == -1) { 130 mdb_warn("failed to read struct loinfo from '%p'\n", 131 vfs.vfs_data); 132 return (WALK_ERR); 133 } 134 135 lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP); 136 lwp->lw_tabsz = loinfo.li_htsize; 137 lwp->lw_table = mdb_alloc(lwp->lw_tabsz * 138 sizeof (struct lobucket), UM_SLEEP); 139 (void) mdb_vread(lwp->lw_table, 140 lwp->lw_tabsz * sizeof (struct lobucket), 141 (uintptr_t)loinfo.li_hashtable); 142 } 143 lwp->lw_tabi = 0; 144 lwp->lw_lnode = mdb_alloc(sizeof (lnode_t), UM_SLEEP); 145 146 wsp->walk_addr = (uintptr_t)lwp->lw_table[0].lh_chain; 147 wsp->walk_data = lwp; 148 149 return (WALK_NEXT); 150 } 151 152 int 153 lnode_walk_step(mdb_walk_state_t *wsp) 154 { 155 lnode_walk_t *lwp = wsp->walk_data; 156 uintptr_t addr; 157 158 /* 159 * If the next lnode_t address we want is NULL, advance to the next 160 * hash bucket. When we reach lw_tabsz, we're done. 161 */ 162 while (wsp->walk_addr == NULL) { 163 if (++lwp->lw_tabi < lwp->lw_tabsz) 164 wsp->walk_addr = 165 (uintptr_t)lwp->lw_table[lwp->lw_tabi].lh_chain; 166 else 167 return (WALK_DONE); 168 } 169 170 /* 171 * When we have an lnode_t address, read the lnode and invoke the 172 * walk callback. Keep the next lnode_t address in wsp->walk_addr. 173 */ 174 addr = wsp->walk_addr; 175 (void) mdb_vread(lwp->lw_lnode, sizeof (lnode_t), addr); 176 wsp->walk_addr = (uintptr_t)lwp->lw_lnode->lo_next; 177 178 return (wsp->walk_callback(addr, lwp->lw_lnode, wsp->walk_cbdata)); 179 } 180 181 void 182 lnode_walk_fini(mdb_walk_state_t *wsp) 183 { 184 lnode_walk_t *lwp = wsp->walk_data; 185 186 mdb_free(lwp->lw_table, lwp->lw_tabsz * sizeof (struct lobucket)); 187 mdb_free(lwp->lw_lnode, sizeof (lnode_t)); 188 mdb_free(lwp, sizeof (lnode_walk_t)); 189 } 190 191 /*ARGSUSED*/ 192 static int 193 lnode_format(uintptr_t addr, const void *data, void *private) 194 { 195 const lnode_t *lop = data; 196 197 mdb_printf("%?p %?p %?p\n", 198 addr, lop->lo_vnode, lop->lo_vp); 199 200 return (DCMD_OK); 201 } 202 203 /*ARGSUSED*/ 204 int 205 lnode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 206 { 207 if (argc != 0) 208 return (DCMD_USAGE); 209 210 if (DCMD_HDRSPEC(flags)) { 211 mdb_printf("%<u>%?s %?s %?s%</u>\n", 212 "LNODE", "VNODE", "REALVP"); 213 } 214 215 if (flags & DCMD_ADDRSPEC) { 216 lnode_t lo; 217 218 (void) mdb_vread(&lo, sizeof (lo), addr); 219 return (lnode_format(addr, &lo, NULL)); 220 } 221 222 if (mdb_walk("lnode", lnode_format, NULL) == -1) 223 return (DCMD_ERR); 224 225 return (DCMD_OK); 226 } 227 228 /*ARGSUSED*/ 229 int 230 lnode2dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 231 { 232 lnode_t lo; 233 vnode_t vno; 234 vfs_t vfs; 235 236 if (argc != 0) 237 return (DCMD_ERR); 238 239 (void) mdb_vread(&lo, sizeof (lo), addr); 240 (void) mdb_vread(&vno, sizeof (vno), (uintptr_t)lo.lo_vnode); 241 (void) mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vno.v_vfsp); 242 243 mdb_printf("lnode %p vfs_dev %0?lx\n", addr, vfs.vfs_dev); 244 return (DCMD_OK); 245 } 246 247 static const mdb_dcmd_t dcmds[] = { 248 { "lnode", NULL, "print lnode structure(s)", lnode }, 249 { "lnode2dev", ":", "print vfs_dev given lnode", lnode2dev }, 250 { NULL } 251 }; 252 253 static const mdb_walker_t walkers[] = { 254 { "lnode", "hash of lnode structures", 255 lnode_walk_init, lnode_walk_step, lnode_walk_fini }, 256 { NULL } 257 }; 258 259 static const mdb_modinfo_t modinfo = { 260 MDB_API_VERSION, dcmds, walkers 261 }; 262 263 const mdb_modinfo_t * 264 _mdb_init(void) 265 { 266 return (&modinfo); 267 } 268