xref: /illumos-gate/usr/src/cmd/mdb/common/modules/nfs/nfs_stat.c (revision 86d949f9497332fe19be6b5d711d265eb957439f)
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/types.h>
16 #include <sys/kstat.h>
17 #include <sys/mdb_modapi.h>
18 #include <rpc/clnt.h>
19 #include <nfs/nfs_clnt.h>
20 #include <nfs/nfs4_clnt.h>
21 
22 #include "svc.h"
23 #include "rfs4.h"
24 #include "nfssrv.h"
25 #include "common.h"
26 
27 #define	NFS4_MINOR_VERS_COUNT 0
28 #define	NFS_STAT_NUM_STATS 79
29 
30 /*
31  * Structure used to group kstats we want to print.
32  */
33 typedef struct nfs_mdb_stats {
34 	struct nfs_stats nfsstats;
35 	struct rpcstat rpcstats;
36 	struct nfs_globals nfsglbls;
37 	uintptr_t clntstat;
38 	uintptr_t clntstat4; /* extend this for NFS4.X */
39 	uintptr_t callback_stats;
40 } nfs_mdb_stats_t;
41 
42 static int nfs_stat_clnt(nfs_mdb_stats_t *, int, int);
43 static int nfs_stat_srv(nfs_mdb_stats_t *, int, int);
44 static int nfs_srvstat(nfs_mdb_stats_t *, int);
45 static int nfs_srvstat_rpc(nfs_mdb_stats_t *);
46 static int nfs_srvstat_acl(nfs_mdb_stats_t *, int);
47 static int nfs_clntstat(nfs_mdb_stats_t *, int);
48 static int nfs_clntstat_rpc(nfs_mdb_stats_t *);
49 static int nfs_clntstat_acl(nfs_mdb_stats_t *, int);
50 static int nfs_srvstat_cb(nfs_mdb_stats_t *);
51 
52 #define	NFS_SRV_STAT	0x1
53 #define	NFS_CLNT_STAT	0x2
54 #define	NFS_CB_STAT	0x4
55 #define	NFS_NFS_STAT	0x1
56 #define	NFS_ACL_STAT	0x2
57 #define	NFS_RPC_STAT	0x4
58 #define	NFS_V2_STAT	0x1
59 #define	NFS_V3_STAT	0x2
60 #define	NFS_V4_STAT	0x4
61 
62 static int prt_nfs_stats(uintptr_t, char *);
63 static void kstat_prtout(char *, uint64_t *, int);
64 
65 void
nfs_stat_help(void)66 nfs_stat_help(void)
67 {
68 	mdb_printf("Switches similar to those of nfsstat command.\n",
69 	    "            ::nfs_stat -a	-> ACL    Statistics.\n"
70 	    "            ::nfs_stat -b  -> Callback Stats. (V4 only)\n"
71 	    "            ::nfs_stat -c  -> Client Statistics.\n"
72 	    "            ::nfs_stat -n	-> NFS    Statistics.\n"
73 	    "            ::nfs_stat -r	-> RPC    Statistics.\n"
74 	    "            ::nfs_stat -s	-> Server Statistics.\n"
75 	    "            ::nfs_stat -2	-> Version 2.\n"
76 	    "            ::nfs_stat -3	-> Version 3.\n"
77 	    "            ::nfs_stat -4	-> Version 4.\n");
78 }
79 
80 int
nfs_stat_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)81 nfs_stat_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
82 {
83 	int host_flag = 0; /* host or client flag */
84 	int type_flag = 0; /* type acl, rpc of nfs */
85 	int vers_flag = 0; /* NFS version flag */
86 	nfs_mdb_stats_t mdb_stats;
87 	uintptr_t glbls;
88 	uintptr_t cb_glbls;
89 	uintptr_t zonep;
90 
91 	if (argc == 1 && argv->a_type == MDB_TYPE_IMMEDIATE) {
92 		kstat_named_t ksts;
93 		int i;
94 		for (i = argv->a_un.a_val; i; i--) {
95 			if (mdb_vread(&ksts, sizeof (ksts), addr) < 0) {
96 				mdb_warn("failed to read kstat_name_t");
97 				return (DCMD_ERR);
98 			}
99 			mdb_printf(" %8s %30d\n", ksts.name, ksts.value.ui64);
100 			addr += sizeof (ksts);
101 		}
102 		return (DCMD_OK);
103 	}
104 
105 	if (mdb_getopts(argc, argv,
106 	    'a', MDB_OPT_SETBITS, NFS_ACL_STAT, &type_flag,
107 	    'b', MDB_OPT_SETBITS, NFS_CB_STAT, &host_flag,
108 	    'c', MDB_OPT_SETBITS, NFS_CLNT_STAT, &host_flag,
109 	    'n', MDB_OPT_SETBITS, NFS_NFS_STAT, &type_flag,
110 	    'r', MDB_OPT_SETBITS, NFS_RPC_STAT, &type_flag,
111 	    's', MDB_OPT_SETBITS, NFS_SRV_STAT, &host_flag,
112 	    '2', MDB_OPT_SETBITS, NFS_V2_STAT, &vers_flag,
113 	    '3', MDB_OPT_SETBITS, NFS_V3_STAT, &vers_flag,
114 	    '4', MDB_OPT_SETBITS, NFS_V4_STAT, &vers_flag,
115 	    NULL) != argc) {
116 		return (DCMD_USAGE);
117 	}
118 
119 
120 	if (flags & DCMD_ADDRSPEC) {
121 		zonep = addr;
122 	} else {
123 		if (mdb_readsym(&zonep, sizeof (uintptr_t),
124 		    "global_zone") == -1) {
125 			mdb_warn("Failed to find global_zone");
126 			return (DCMD_ERR);
127 		}
128 	}
129 
130 	if (zoned_get_zsd(zonep, "nfssrv_zone_key", &glbls)) {
131 		mdb_warn("Failed to find nfssrv_zone_key");
132 		return (DCMD_ERR);
133 	}
134 
135 	if (mdb_vread(&mdb_stats.nfsglbls, sizeof (struct nfs_globals),
136 	    glbls) == -1) {
137 		mdb_warn("Failed to read nfs_stats at %p", glbls);
138 		return (DCMD_ERR);
139 	}
140 
141 	if (zoned_get_zsd(zonep, "nfsstat_zone_key", &glbls)) {
142 		mdb_warn("Failed to find %s", "nfsstat_zone_key");
143 		return (DCMD_ERR);
144 	}
145 
146 	if (mdb_vread(&mdb_stats.nfsstats, sizeof (struct nfs_stats),
147 	    glbls) == -1) {
148 		mdb_warn("Failed to read nfs_stats at %p", glbls);
149 		return (DCMD_ERR);
150 	}
151 
152 	if (zoned_get_zsd(zonep, "rpcstat_zone_key", &glbls)) {
153 		mdb_warn("Failed to find %s", "rpcstat_zone_key");
154 		return (DCMD_ERR);
155 	}
156 
157 	if (mdb_vread(&mdb_stats.rpcstats, sizeof (struct rpcstat),
158 	    glbls) == -1) {
159 		mdb_warn("Failed to read nfs_stats at %p", glbls);
160 		return (DCMD_ERR);
161 	}
162 
163 	if (zoned_get_zsd(zonep, "nfsclnt_zone_key", &glbls)) {
164 		mdb_warn("Failed to find %s", "nfsclnt_zone_key");
165 		return (DCMD_ERR);
166 	}
167 	mdb_stats.clntstat = glbls + offsetof(struct nfs_clnt, nfscl_stat);
168 
169 	if (zoned_get_zsd(zonep, "nfs4clnt_zone_key", &glbls)) {
170 		mdb_warn("Failed to find %s", "nfs4clnt_zone_key");
171 		return (DCMD_ERR);
172 	}
173 	/*
174 	 * currently only have NFSv4.0 is availble. When NFSv4.1 and above are
175 	 * available stats support will need to be added.
176 	 */
177 	mdb_stats.clntstat4 = glbls + offsetof(struct nfs4_clnt, nfscl_stat);
178 
179 	if (zoned_get_zsd(zonep, "nfs4_callback_zone_key",
180 	    (uintptr_t *)&cb_glbls)) {
181 		mdb_warn("Failed to find %s", "nfs4_callback_zone_key");
182 		return (DCMD_ERR);
183 	}
184 
185 	mdb_stats.callback_stats =
186 	    (cb_glbls + offsetof(struct nfs4_callback_globals,
187 	    nfs4_callback_stats));
188 
189 	if (host_flag == 0)
190 		host_flag = NFS_SRV_STAT | NFS_CLNT_STAT | NFS_CB_STAT;
191 	if (vers_flag == 0)
192 		vers_flag = NFS_V2_STAT | NFS_V3_STAT | NFS_V4_STAT;
193 	if (type_flag == 0)
194 		type_flag = NFS_NFS_STAT | NFS_ACL_STAT | NFS_RPC_STAT;
195 
196 	if (host_flag & NFS_CB_STAT)
197 		if (nfs_srvstat_cb(&mdb_stats))
198 			return (DCMD_ERR);
199 	if (host_flag & NFS_SRV_STAT)
200 		if (nfs_stat_srv(&mdb_stats, type_flag, vers_flag))
201 			return (DCMD_ERR);
202 	if (host_flag & NFS_CLNT_STAT)
203 		if (nfs_stat_clnt(&mdb_stats, type_flag, vers_flag))
204 			return (DCMD_ERR);
205 	return (DCMD_OK);
206 }
207 
208 static int
nfs_srvstat_cb(nfs_mdb_stats_t * stptr)209 nfs_srvstat_cb(nfs_mdb_stats_t *stptr)
210 {
211 	int ret = 0;
212 	mdb_printf("CALLBACK STATISTICS:\n");
213 
214 	ret = prt_nfs_stats(stptr->callback_stats, "nfs4_callback_stats_tmpl");
215 
216 	return (ret);
217 }
218 
219 static int
nfs_stat_srv(nfs_mdb_stats_t * stptr,int type_flag,int vers_flag)220 nfs_stat_srv(nfs_mdb_stats_t *stptr, int type_flag, int vers_flag)
221 {
222 	mdb_printf("NFS SERVER STATS:\n");
223 	if (type_flag & NFS_SRV_STAT) {
224 		if (nfs_srvstat(stptr, vers_flag) != 0)
225 			return (1);
226 	}
227 	if (type_flag & NFS_RPC_STAT) {
228 		if (nfs_srvstat_rpc(stptr) != 0)
229 			return (1);
230 	}
231 	if (type_flag & NFS_ACL_STAT) {
232 		if (nfs_srvstat_acl(stptr, vers_flag) != 0)
233 			return (1);
234 	}
235 	return (0);
236 }
237 
238 static int
nfs_stat_clnt(nfs_mdb_stats_t * stptr,int type_flag,int vers_flag)239 nfs_stat_clnt(nfs_mdb_stats_t *stptr, int type_flag, int vers_flag)
240 {
241 	mdb_printf("CLIENT STATISTICS:\n");
242 	if (type_flag & NFS_CLNT_STAT) {
243 		if (nfs_clntstat(stptr, vers_flag))
244 			return (1);
245 	}
246 	if (type_flag & NFS_ACL_STAT) {
247 		if (nfs_clntstat_acl(stptr, vers_flag))
248 			return (1);
249 	}
250 	if (type_flag & NFS_RPC_STAT) {
251 		if (nfs_clntstat_rpc(stptr))
252 			return (1);
253 	}
254 	return (0);
255 }
256 
257 
258 static int
nfs_srvstat(nfs_mdb_stats_t * stptr,int flag)259 nfs_srvstat(nfs_mdb_stats_t *stptr, int flag)
260 {
261 	mdb_printf("NFS Statistics\n");
262 	if (flag & NFS_V2_STAT) {
263 		mdb_printf("NFSv2\n");
264 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.svstat[2],
265 		    "svstat_tmpl") ||
266 		    prt_nfs_stats((uintptr_t)stptr->nfsglbls.rfsproccnt[2],
267 		    "rfsproccnt_v2_tmpl"))
268 			return (-1);
269 	}
270 	if (flag & NFS_V3_STAT) {
271 		mdb_printf("NFSv3\n");
272 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.svstat[3],
273 		    "svstat_tmpl") ||
274 		    prt_nfs_stats((uintptr_t)stptr->nfsglbls.rfsproccnt[3],
275 		    "rfsproccnt_v3_tmpl"))
276 			return (-1);
277 	}
278 	if (flag & NFS_V4_STAT) {
279 		mdb_printf("NFSv4\n");
280 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.svstat[4],
281 		    "svstat_tmpl") ||
282 		    prt_nfs_stats((uintptr_t)stptr->nfsglbls.rfsproccnt[4],
283 		    "rfsproccnt_v4_tmpl"))
284 			return (-1);
285 	}
286 	return (0);
287 }
288 
289 
290 static int
nfs_srvstat_rpc(nfs_mdb_stats_t * stptr)291 nfs_srvstat_rpc(nfs_mdb_stats_t *stptr)
292 {
293 	mdb_printf("NFS RPC Statistics\n");
294 	mdb_printf("ConnectionLess\n");
295 	if (prt_nfs_stats((uintptr_t)stptr->rpcstats.rpc_clts_server,
296 	    "clts_rsstat_tmpl"))
297 		return (-1);
298 	mdb_printf("ConnectionOriented\n");
299 	if (prt_nfs_stats((uintptr_t)stptr->rpcstats.rpc_cots_server,
300 	    "cots_rsstat_tmpl"))
301 		return (-1);
302 	return (0);
303 }
304 
305 
306 static int
nfs_srvstat_acl(nfs_mdb_stats_t * stptr,int flags)307 nfs_srvstat_acl(nfs_mdb_stats_t *stptr, int flags)
308 {
309 	mdb_printf("NFS ACL Statistics\n");
310 	if (flags & NFS_V2_STAT) {
311 		mdb_printf("NFSv2\n");
312 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.aclproccnt[2],
313 		    "aclproccnt_v2_tmpl"))
314 			return (-1);
315 	}
316 	if (flags & NFS_V3_STAT) {
317 		mdb_printf("NFSv3\n");
318 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.aclproccnt[3],
319 		    "aclproccnt_v3_tmpl"))
320 			return (-1);
321 	}
322 	if (flags & NFS_V4_STAT) {
323 		mdb_printf("NFSv4\n");
324 		if (prt_nfs_stats((uintptr_t)stptr->nfsglbls.aclproccnt[4],
325 		    "aclreqcnt_v4_tmpl"))
326 			return (-1);
327 	}
328 	return (0);
329 }
330 
331 static int
nfs_clntstat(nfs_mdb_stats_t * stptr,int flags)332 nfs_clntstat(nfs_mdb_stats_t *stptr, int flags)
333 {
334 	mdb_printf("NFS Statistics\n");
335 	if (prt_nfs_stats((uintptr_t)stptr->clntstat, "clstat_tmpl"))
336 		return (-1);
337 	if (flags & NFS_V2_STAT) {
338 		mdb_printf("Version 2\n");
339 		if (prt_nfs_stats(
340 		    (uintptr_t)stptr->nfsstats.nfs_stats_v2.rfsreqcnt_ptr,
341 		    "rfsreqcnt_v2_tmpl"))
342 			return (-1);
343 	}
344 	if (flags & NFS_V3_STAT) {
345 		mdb_printf("Version 3\n");
346 		if (prt_nfs_stats(
347 		    (uintptr_t)stptr->nfsstats.nfs_stats_v3.rfsreqcnt_ptr,
348 		    "rfsreqcnt_v3_tmpl"))
349 			return (-1);
350 	}
351 	if (flags & NFS_V4_STAT) {
352 		mdb_printf("NFSv4 client\n");
353 		if (prt_nfs_stats((uintptr_t)stptr->clntstat, "clstat4_tmpl"))
354 			return (-1);
355 		mdb_printf("Version 4\n");
356 		if (prt_nfs_stats(
357 		    (uintptr_t)stptr->nfsstats.nfs_stats_v4.rfsreqcnt_ptr,
358 		    "rfsreqcnt_v4_tmpl"))
359 			return (-1);
360 	}
361 	return (0);
362 }
363 
364 static int
nfs_clntstat_rpc(nfs_mdb_stats_t * stptr)365 nfs_clntstat_rpc(nfs_mdb_stats_t *stptr)
366 {
367 	mdb_printf("NFS RPC Statistics\n");
368 	mdb_printf("ConnectionLess\n");
369 	if (prt_nfs_stats((uintptr_t)stptr->rpcstats.rpc_clts_client,
370 	    "clts_rcstat_tmpl"))
371 		return (-1);
372 	mdb_printf("ConnectionOriented\n");
373 	if (prt_nfs_stats((uintptr_t)stptr->rpcstats.rpc_cots_client,
374 	    "cots_rcstat_tmpl"))
375 		return (-1);
376 	return (0);
377 }
378 
379 static int
nfs_clntstat_acl(nfs_mdb_stats_t * stptr,int flags)380 nfs_clntstat_acl(nfs_mdb_stats_t *stptr, int flags)
381 {
382 	mdb_printf("ACL Statistics\n");
383 	if (flags & NFS_V2_STAT) {
384 		mdb_printf("Version 2\n");
385 		if (prt_nfs_stats(
386 		    (uintptr_t)stptr->nfsstats.nfs_stats_v2.aclreqcnt_ptr,
387 		    "aclreqcnt_v2_tmpl"))
388 			return (-1);
389 	}
390 	if (flags & NFS_V3_STAT) {
391 		mdb_printf("Version 3\n");
392 		if (prt_nfs_stats(
393 		    (uintptr_t)stptr->nfsstats.nfs_stats_v3.aclreqcnt_ptr,
394 		    "aclreqcnt_v3_tmpl"))
395 			return (-1);
396 	}
397 	if (flags & NFS_V4_STAT) {
398 		mdb_printf("Version 4\n");
399 		if (prt_nfs_stats(
400 		    (uintptr_t)stptr->nfsstats.nfs_stats_v4.aclreqcnt_ptr,
401 		    "aclreqcnt_v4_tmpl"))
402 			return (-1);
403 	}
404 	return (0);
405 }
406 
407 
408 /*
409  * helper functions for printing out the kstat data
410  */
411 
412 #define	NFS_STAT_NUM_CLMNS 16
413 
414 static int
prt_nfs_stats(uintptr_t addr,char * name)415 prt_nfs_stats(uintptr_t addr, char *name)
416 {
417 
418 	GElf_Sym sym;
419 	kstat_named_t kstats;
420 	char *kstat_line;
421 	uint64_t *value;
422 	uint_t count;
423 	int i = 0, status = 0;
424 
425 
426 	if (mdb_lookup_by_name(name, &sym) != 0) {
427 		mdb_warn("failed to find %s", name);
428 		return (1);
429 	}
430 
431 	count = sym.st_size / sizeof (kstat_named_t);
432 
433 	kstat_line = mdb_alloc(count * NFS_STAT_NUM_CLMNS, UM_SLEEP);
434 	value = mdb_alloc(count * sizeof (uint64_t), UM_SLEEP);
435 	for (i = 0; i < count; i++) {
436 		if (mdb_vread(&kstats, sizeof (kstat_named_t),
437 		    addr + (i * sizeof (kstat_named_t))) < 0) {
438 			status = 1;
439 			goto done;
440 		}
441 		mdb_snprintf(&kstat_line[NFS_STAT_NUM_CLMNS * i],
442 		    NFS_STAT_NUM_CLMNS, "%s", kstats.name);
443 		value[i] = kstats.value.ui64;
444 	}
445 	kstat_prtout(kstat_line, value, count);
446 done:
447 	mdb_free(kstat_line, count * NFS_STAT_NUM_CLMNS);
448 	mdb_free(value, count * sizeof (uint64_t));
449 	return (status);
450 }
451 
452 static void
kstat_prtout(char * ks_line,uint64_t * values,int count)453 kstat_prtout(char *ks_line, uint64_t *values, int count)
454 {
455 	char val_str[32];
456 	int i = 0, num = 0;
457 
458 	while (i < count) {
459 		mdb_printf("%-*s", NFS_STAT_NUM_CLMNS,
460 		    &ks_line[NFS_STAT_NUM_CLMNS * i]);
461 
462 		num++;
463 		if (num == NFS_STAT_NUM_STATS / NFS_STAT_NUM_CLMNS) {
464 			mdb_printf("\n");
465 			while (num > 0) {
466 				mdb_snprintf(val_str, 24, "%ld  ",
467 				    values[i+1-num]);
468 				mdb_printf("%-*s", NFS_STAT_NUM_CLMNS, val_str);
469 				--num;
470 			}
471 			mdb_printf("\n");
472 		}
473 		i++;
474 	}
475 	mdb_printf("\n");
476 }
477