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 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 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 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 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 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 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 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 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 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 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 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 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 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