1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 /* 12 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 13 */ 14 15 #include <sys/mdb_modapi.h> 16 #include <mdb/mdb_ctf.h> 17 #include <sys/types.h> 18 #include <sys/mutex_impl.h> 19 #include <sys/rwlock_impl.h> 20 #include <sys/zone.h> 21 #include <sys/socket.h> 22 23 #include "nfssrv.h" 24 #include "common.h" 25 26 struct common_zsd_cb_data { 27 zone_key_t key; /* Key of ZSD for which we're looking */ 28 uint_t found; /* Was the specific ZSD entry found? */ 29 uintptr_t zsd_data; /* Result */ 30 }; 31 32 int 33 zoned_find_zsd_cb(uintptr_t addr, const void *data, void *cb_data) 34 { 35 const struct zsd_entry *entry = data; 36 struct common_zsd_cb_data *cbd = cb_data; 37 38 if (cbd->key != entry->zsd_key) 39 return (WALK_NEXT); 40 41 /* Match */ 42 cbd->zsd_data = (uintptr_t)entry->zsd_data; 43 cbd->found = TRUE; 44 return (WALK_DONE); 45 } 46 47 int 48 zoned_get_nfs_globals(uintptr_t zonep, uintptr_t *result) 49 { 50 return (zoned_get_zsd(zonep, "nfssrv_zone_key", result)); 51 } 52 53 int 54 zoned_get_zsd(uintptr_t zonep, char *key_str, uintptr_t *result) 55 { 56 zone_key_t key; 57 struct common_zsd_cb_data cbd; 58 59 if (mdb_readsym(&key, sizeof (zone_key_t), key_str) == -1) { 60 mdb_warn("failed to get %s", key_str); 61 return (DCMD_ERR); 62 } 63 64 cbd.key = key; 65 cbd.found = FALSE; 66 67 if (mdb_pwalk("zsd", zoned_find_zsd_cb, &cbd, zonep) != 0) { 68 mdb_warn("failed to walk zsd"); 69 return (DCMD_ERR); 70 } 71 72 if (cbd.found == FALSE) { 73 mdb_warn("no ZSD entry found"); 74 return (DCMD_ERR); 75 } 76 77 *result = cbd.zsd_data; 78 return (DCMD_OK); 79 } 80 81 82 const char * 83 common_mutex(kmutex_t *mp) 84 { 85 char *s; 86 size_t sz; 87 mutex_impl_t *lp = (mutex_impl_t *)mp; 88 89 if (MUTEX_TYPE_SPIN(lp)) { 90 const char *fmt = "spin - lock(%x)/oldspl(%x)/minspl(%x)"; 91 92 sz = 1 + mdb_snprintf(NULL, 0, fmt, lp->m_spin.m_spinlock, 93 lp->m_spin.m_oldspl, lp->m_spin.m_minspl); 94 s = mdb_alloc(sz, UM_SLEEP | UM_GC); 95 (void) mdb_snprintf(s, sz, fmt, lp->m_spin.m_spinlock, 96 lp->m_spin.m_oldspl, lp->m_spin.m_minspl); 97 98 return (s); 99 } 100 101 if (MUTEX_TYPE_ADAPTIVE(lp)) { 102 const char *fmt = "adaptive - owner %p%s"; 103 104 if ((MUTEX_OWNER(lp) == NULL) && !MUTEX_HAS_WAITERS(lp)) 105 return ("mutex not held"); 106 107 sz = 1 + mdb_snprintf(NULL, 0, fmt, MUTEX_OWNER(lp), 108 MUTEX_HAS_WAITERS(lp) ? " has waiters" : ""); 109 s = mdb_alloc(sz, UM_SLEEP | UM_GC); 110 (void) mdb_snprintf(s, sz, fmt, MUTEX_OWNER(lp), 111 MUTEX_HAS_WAITERS(lp) ? " has waiters" : ""); 112 113 return (s); 114 } 115 116 return ("mutex dead"); 117 } 118 119 const char * 120 common_rwlock(krwlock_t *lp) 121 { 122 char *s; 123 size_t sz; 124 uintptr_t w = ((rwlock_impl_t *)lp)->rw_wwwh; 125 uintptr_t o = w & RW_OWNER; 126 const char *hw = (w & RW_HAS_WAITERS) ? " has_waiters" : ""; 127 const char *ww = (w & RW_WRITE_WANTED) ? " write_wanted" : ""; 128 const char *wl = (w & RW_WRITE_LOCKED) ? " write_locked" : ""; 129 130 sz = 1 + mdb_snprintf(NULL, 0, "owner %p%s%s%s", o, hw, ww, wl); 131 s = mdb_alloc(sz, UM_SLEEP | UM_GC); 132 (void) mdb_snprintf(s, sz, "owner %p%s%s%s", o, hw, ww, wl); 133 134 return (s); 135 } 136 137 const char * 138 common_netbuf_str(struct netbuf *nb) 139 { 140 struct sockaddr_in *in; 141 142 in = mdb_alloc(nb->len + 1, UM_SLEEP | UM_GC); 143 if (mdb_vread(in, nb->len, (uintptr_t)nb->buf) == -1) 144 return (""); 145 146 if (nb->len < sizeof (struct sockaddr_in)) { 147 ((char *)in)[nb->len] = '\0'; 148 return ((char *)in); 149 } 150 151 if (in->sin_family == AF_INET) { 152 char *s; 153 ssize_t sz; 154 155 mdb_nhconvert(&in->sin_port, &in->sin_port, 156 sizeof (in->sin_port)); 157 158 sz = 1 + mdb_snprintf(NULL, 0, "%I:%d", in->sin_addr.s_addr, 159 in->sin_port); 160 s = mdb_alloc(sz, UM_SLEEP | UM_GC); 161 (void) mdb_snprintf(s, sz, "%I:%d", in->sin_addr.s_addr, 162 in->sin_port); 163 164 return (s); 165 } else if ((in->sin_family == AF_INET6) && 166 (nb->len >= sizeof (struct sockaddr_in6))) { 167 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in; 168 char *s; 169 size_t sz; 170 171 mdb_nhconvert(&in6->sin6_port, &in6->sin6_port, 172 sizeof (in6->sin6_port)); 173 174 sz = 1 + mdb_snprintf(NULL, 0, "[%N]:%d", 175 in6->sin6_addr.s6_addr, in6->sin6_port); 176 s = mdb_alloc(sz, UM_SLEEP | UM_GC); 177 (void) mdb_snprintf(s, sz, "[%N]:%d", in6->sin6_addr.s6_addr, 178 in6->sin6_port); 179 180 return (s); 181 } else { 182 ((char *)in)[nb->len] = '\0'; 183 return ((char *)in); 184 } 185 } 186 187 /* 188 * Generic hash table walker 189 * 190 */ 191 192 typedef struct hash_table_walk_data { 193 uintptr_t table; /* current table pointer */ 194 int count; /* number of entries to process */ 195 void *member; /* copy of the current member structure */ 196 } hash_table_walk_data_t; 197 198 int 199 hash_table_walk_init(mdb_walk_state_t *wsp) 200 { 201 hash_table_walk_arg_t *arg = wsp->walk_arg; 202 hash_table_walk_data_t *wd = mdb_alloc(sizeof (*wd), UM_SLEEP); 203 204 wd->table = arg->array_addr; 205 wd->count = arg->array_len; 206 207 wd->member = mdb_alloc(arg->member_size, UM_SLEEP); 208 209 wsp->walk_addr = 0; 210 wsp->walk_data = wd; 211 212 return (WALK_NEXT); 213 } 214 215 int 216 hash_table_walk_step(mdb_walk_state_t *wsp) 217 { 218 hash_table_walk_arg_t *arg = wsp->walk_arg; 219 hash_table_walk_data_t *wd = wsp->walk_data; 220 uintptr_t addr = wsp->walk_addr; 221 222 if (wd->count == 0) 223 return (WALK_DONE); 224 225 if (addr == 0) { 226 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr), 227 wd->table + arg->first_offset) == -1) { 228 mdb_warn("can't read %s", arg->first_name); 229 return (WALK_ERR); 230 } 231 if (wsp->walk_addr == 0) 232 wsp->walk_addr = wd->table; 233 234 return (WALK_NEXT); 235 } 236 237 if (addr == wd->table) { 238 wd->count--; 239 wd->table += arg->head_size; 240 wsp->walk_addr = 0; 241 242 return (WALK_NEXT); 243 } 244 245 if (mdb_vread(wd->member, arg->member_size, addr) == -1) { 246 mdb_warn("unable to read %s", arg->member_type_name); 247 return (WALK_ERR); 248 } 249 250 wsp->walk_addr = *(uintptr_t *)((uintptr_t)wd->member 251 + arg->next_offset); 252 if (wsp->walk_addr == 0) 253 wsp->walk_addr = wd->table; 254 255 return (wsp->walk_callback(addr, wd->member, wsp->walk_cbdata)); 256 } 257 258 void 259 hash_table_walk_fini(mdb_walk_state_t *wsp) 260 { 261 hash_table_walk_arg_t *arg = wsp->walk_arg; 262 hash_table_walk_data_t *wd = wsp->walk_data; 263 264 mdb_free(wd->member, arg->member_size); 265 mdb_free(wd, sizeof (*wd)); 266 } 267