xref: /illumos-gate/usr/src/cmd/mdb/common/modules/nfs/common.c (revision 55fea89dcaa64928bed4327112404dcb3e07b79f)
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