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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #include <sys/types.h>
32 #include <sys/kstat.h>
33 #include <sys/zone.h>
34 #include <sys/kmem.h>
35 #include <sys/systm.h>
36
37 #include <nfs/nfs.h>
38 #include <nfs/nfs4_kprot.h>
39
40 /*
41 * Key to retrieve per-zone data corresponding to NFS kstats consumed by
42 * nfsstat(1m).
43 */
44 zone_key_t nfsstat_zone_key;
45
46 /*
47 * Convenience routine to create a named kstat associated with zoneid, named
48 * module:0:name:"misc", using the provided template to initialize the names
49 * and values of the stats.
50 */
51 static kstat_named_t *
52 nfsstat_zone_init_common(zoneid_t zoneid, const char *module, int vers,
53 const char *name, const kstat_named_t *template, size_t template_size)
54 {
55 kstat_t *ksp;
56 kstat_named_t *ks_data;
57
58 ks_data = kmem_alloc(template_size, KM_SLEEP);
59 bcopy(template, ks_data, template_size);
60 if ((ksp = kstat_create_zone(module, vers, name, "misc",
61 KSTAT_TYPE_NAMED, template_size / sizeof (kstat_named_t),
62 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, zoneid)) != NULL) {
63 ksp->ks_data = ks_data;
64 kstat_install(ksp);
65 }
66 return (ks_data);
67 }
68
69 /*
70 * Convenience routine to remove a kstat in specified zone with name
71 * module:0:name.
72 */
73 static void
74 nfsstat_zone_fini_common(zoneid_t zoneid, const char *module, int vers,
75 const char *name)
76 {
77 kstat_delete_byname_zone(module, vers, name, zoneid);
78 }
79
80 /*
81 * Server statistics. These are defined here, rather than in the server
82 * code, so that they can be referenced before the nfssrv kmod is loaded.
83 *
84 * The "calls" counter is a Contract Private interface covered by
85 * PSARC/2001/357. Please contact contract-2001-357-01@eng.sun.com before
86 * making any changes.
87 */
88
89 static const kstat_named_t svstat_tmpl[] = {
90 { "calls", KSTAT_DATA_UINT64 },
91 { "badcalls", KSTAT_DATA_UINT64 },
92 { "referrals", KSTAT_DATA_UINT64 },
93 { "referlinks", KSTAT_DATA_UINT64 },
94 };
95
96 /* Points to the global zone server kstat data for all nfs versions */
97 kstat_named_t *global_svstat_ptr[NFS_VERSMAX + 1];
98
99 static void
100 nfsstat_zone_init_server(zoneid_t zoneid, kstat_named_t *svstatp[])
101 {
102 int vers;
103
104 /*
105 * first two indexes of these arrays are not used, so initialize
106 * to NULL
107 */
108 svstatp[0] = NULL;
109 svstatp[1] = NULL;
110 global_svstat_ptr[0] = NULL;
111 global_svstat_ptr[0] = NULL;
112
113 for (vers = NFS_VERSION; vers <= NFS_V4; vers++) {
114 svstatp[vers] = nfsstat_zone_init_common(zoneid, "nfs", vers,
115 "nfs_server", svstat_tmpl, sizeof (svstat_tmpl));
116 if (zoneid == GLOBAL_ZONEID)
117 global_svstat_ptr[vers] = svstatp[vers];
118 }
119 }
120
121 static void
122 nfsstat_zone_fini_server(zoneid_t zoneid, kstat_named_t **svstatp)
123 {
124 int vers;
125 for (vers = NFS_VERSION; vers <= NFS_V4; vers++) {
126 if (zoneid == GLOBAL_ZONEID)
127 global_svstat_ptr[vers] = NULL;
128 nfsstat_zone_fini_common(zoneid, "nfs", vers, "nfs_server");
129 kmem_free(svstatp[vers], sizeof (svstat_tmpl));
130 }
131 }
132
133 /*
134 * Support functions for the kstat_io alloc/free
135 */
136 static kstat_t **
137 rfs_kstat_io_init(zoneid_t zoneid, const char *module, int instance,
138 const char *name, const char *class, const kstat_named_t *tmpl, int count,
139 kmutex_t *lock)
140 {
141 int i;
142 kstat_t **ret = kmem_alloc(count * sizeof (*ret), KM_SLEEP);
143
144 for (i = 0; i < count; i++) {
145 char namebuf[KSTAT_STRLEN];
146
147 (void) snprintf(namebuf, sizeof (namebuf), "%s_%s", name,
148 tmpl[i].name);
149 ret[i] = kstat_create_zone(module, instance, namebuf, class,
150 KSTAT_TYPE_IO, 1, 0, zoneid);
151 if (ret[i] != NULL) {
152 ret[i]->ks_lock = lock;
153 kstat_install(ret[i]);
154 }
155 }
156
157 return (ret);
158 }
159
160 static void
161 rfs_kstat_io_delete(kstat_t **ks, int count)
162 {
163 int i;
164
165 for (i = 0; i < count; i++) {
166 if (ks[i] != NULL) {
167 kstat_delete(ks[i]);
168 ks[i] = NULL;
169 }
170 }
171 }
172
173 static void
174 rfs_kstat_io_free(kstat_t **ks, int count)
175 {
176 rfs_kstat_io_delete(ks, count);
177 kmem_free(ks, count * sizeof (*ks));
178 }
179
180 /*
181 * NFSv2 client stats
182 */
183 static const kstat_named_t rfsreqcnt_v2_tmpl[] = {
184 { "null", KSTAT_DATA_UINT64 },
185 { "getattr", KSTAT_DATA_UINT64 },
186 { "setattr", KSTAT_DATA_UINT64 },
187 { "root", KSTAT_DATA_UINT64 },
188 { "lookup", KSTAT_DATA_UINT64 },
189 { "readlink", KSTAT_DATA_UINT64 },
190 { "read", KSTAT_DATA_UINT64 },
191 { "wrcache", KSTAT_DATA_UINT64 },
192 { "write", KSTAT_DATA_UINT64 },
193 { "create", KSTAT_DATA_UINT64 },
194 { "remove", KSTAT_DATA_UINT64 },
195 { "rename", KSTAT_DATA_UINT64 },
196 { "link", KSTAT_DATA_UINT64 },
197 { "symlink", KSTAT_DATA_UINT64 },
198 { "mkdir", KSTAT_DATA_UINT64 },
199 { "rmdir", KSTAT_DATA_UINT64 },
200 { "readdir", KSTAT_DATA_UINT64 },
201 { "statfs", KSTAT_DATA_UINT64 }
202 };
203
204 static void
205 nfsstat_zone_init_rfsreq_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
206 {
207 statsp->rfsreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
208 "rfsreqcnt_v2", rfsreqcnt_v2_tmpl, sizeof (rfsreqcnt_v2_tmpl));
209 }
210
211 static void
212 nfsstat_zone_fini_rfsreq_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
213 {
214 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsreqcnt_v2");
215 kmem_free(statsp->rfsreqcnt_ptr, sizeof (rfsreqcnt_v2_tmpl));
216 }
217
218 /*
219 * NFSv2 server stats
220 */
221 static const kstat_named_t rfsproccnt_v2_tmpl[] = {
222 { "null", KSTAT_DATA_UINT64 },
223 { "getattr", KSTAT_DATA_UINT64 },
224 { "setattr", KSTAT_DATA_UINT64 },
225 { "root", KSTAT_DATA_UINT64 },
226 { "lookup", KSTAT_DATA_UINT64 },
227 { "readlink", KSTAT_DATA_UINT64 },
228 { "read", KSTAT_DATA_UINT64 },
229 { "wrcache", KSTAT_DATA_UINT64 },
230 { "write", KSTAT_DATA_UINT64 },
231 { "create", KSTAT_DATA_UINT64 },
232 { "remove", KSTAT_DATA_UINT64 },
233 { "rename", KSTAT_DATA_UINT64 },
234 { "link", KSTAT_DATA_UINT64 },
235 { "symlink", KSTAT_DATA_UINT64 },
236 { "mkdir", KSTAT_DATA_UINT64 },
237 { "rmdir", KSTAT_DATA_UINT64 },
238 { "readdir", KSTAT_DATA_UINT64 },
239 { "statfs", KSTAT_DATA_UINT64 }
240 };
241
242 #define RFSPROCCNT_V2_COUNT \
243 (sizeof (rfsproccnt_v2_tmpl) / sizeof (rfsproccnt_v2_tmpl[0]))
244
245 kstat_named_t *rfsproccnt_v2_ptr;
246 kstat_t **rfsprocio_v2_ptr;
247
248 static void
249 nfsstat_zone_init_rfsproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
250 {
251 statsp->rfsproccnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
252 "rfsproccnt_v2", rfsproccnt_v2_tmpl, sizeof (rfsproccnt_v2_tmpl));
253
254 mutex_init(&statsp->rfsprocio_lock, NULL, MUTEX_DEFAULT, NULL);
255
256 statsp->rfsprocio_ptr = rfs_kstat_io_init(zoneid, "nfs", 0,
257 "rfsprocio_v2", "rfsprocio_v2", rfsproccnt_v2_tmpl,
258 RFSPROCCNT_V2_COUNT, &statsp->rfsprocio_lock);
259
260 if (zoneid == GLOBAL_ZONEID) {
261 rfsproccnt_v2_ptr = statsp->rfsproccnt_ptr;
262 rfsprocio_v2_ptr = statsp->rfsprocio_ptr;
263 }
264 }
265
266 static void
267 nfsstat_zone_fini_rfsproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
268 {
269 if (zoneid == GLOBAL_ZONEID) {
270 rfsproccnt_v2_ptr = NULL;
271 rfsprocio_v2_ptr = NULL;
272 }
273
274 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v2");
275 kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v2_tmpl));
276
277 rfs_kstat_io_free(statsp->rfsprocio_ptr, RFSPROCCNT_V2_COUNT);
278
279 mutex_destroy(&statsp->rfsprocio_lock);
280 }
281
282 /*
283 * NFSv2 client ACL stats
284 */
285 static const kstat_named_t aclreqcnt_v2_tmpl[] = {
286 { "null", KSTAT_DATA_UINT64 },
287 { "getacl", KSTAT_DATA_UINT64 },
288 { "setacl", KSTAT_DATA_UINT64 },
289 { "getattr", KSTAT_DATA_UINT64 },
290 { "access", KSTAT_DATA_UINT64 },
291 { "getxattrdir", KSTAT_DATA_UINT64 }
292 };
293
294 static void
295 nfsstat_zone_init_aclreq_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
296 {
297 statsp->aclreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
298 "aclreqcnt_v2", aclreqcnt_v2_tmpl, sizeof (aclreqcnt_v2_tmpl));
299 }
300
301 static void
302 nfsstat_zone_fini_aclreq_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
303 {
304 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclreqcnt_v2");
305 kmem_free(statsp->aclreqcnt_ptr, sizeof (aclreqcnt_v2_tmpl));
306 }
307
308 /*
309 * NFSv2 server ACL stats
310 */
311 static const kstat_named_t aclproccnt_v2_tmpl[] = {
312 { "null", KSTAT_DATA_UINT64 },
313 { "getacl", KSTAT_DATA_UINT64 },
314 { "setacl", KSTAT_DATA_UINT64 },
315 { "getattr", KSTAT_DATA_UINT64 },
316 { "access", KSTAT_DATA_UINT64 },
317 { "getxattrdir", KSTAT_DATA_UINT64 }
318 };
319
320 #define ACLPROCCNT_V2_COUNT \
321 (sizeof (aclproccnt_v2_tmpl) / sizeof (aclproccnt_v2_tmpl[0]))
322
323 kstat_named_t *aclproccnt_v2_ptr;
324 kstat_t **aclprocio_v2_ptr;
325
326 static void
327 nfsstat_zone_init_aclproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
328 {
329 statsp->aclproccnt_ptr = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
330 "aclproccnt_v2", aclproccnt_v2_tmpl, sizeof (aclproccnt_v2_tmpl));
331
332 mutex_init(&statsp->aclprocio_lock, NULL, MUTEX_DEFAULT, NULL);
333
334 statsp->aclprocio_ptr = rfs_kstat_io_init(zoneid, "nfs_acl", 0,
335 "aclprocio_v2", "aclprocio_v2", aclproccnt_v2_tmpl,
336 ACLPROCCNT_V2_COUNT, &statsp->aclprocio_lock);
337
338 if (zoneid == GLOBAL_ZONEID) {
339 aclproccnt_v2_ptr = statsp->aclproccnt_ptr;
340 aclprocio_v2_ptr = statsp->aclprocio_ptr;
341 }
342 }
343
344 static void
345 nfsstat_zone_fini_aclproc_v2(zoneid_t zoneid, struct nfs_version_stats *statsp)
346 {
347 if (zoneid == GLOBAL_ZONEID) {
348 aclproccnt_v2_ptr = NULL;
349 aclprocio_v2_ptr = NULL;
350 }
351
352 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v2");
353 kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v2_tmpl));
354
355 rfs_kstat_io_free(statsp->aclprocio_ptr, ACLPROCCNT_V2_COUNT);
356
357 mutex_destroy(&statsp->aclprocio_lock);
358 }
359
360 /*
361 * NFSv3 client stats
362 */
363 static const kstat_named_t rfsreqcnt_v3_tmpl[] = {
364 { "null", KSTAT_DATA_UINT64 },
365 { "getattr", KSTAT_DATA_UINT64 },
366 { "setattr", KSTAT_DATA_UINT64 },
367 { "lookup", KSTAT_DATA_UINT64 },
368 { "access", KSTAT_DATA_UINT64 },
369 { "readlink", KSTAT_DATA_UINT64 },
370 { "read", KSTAT_DATA_UINT64 },
371 { "write", KSTAT_DATA_UINT64 },
372 { "create", KSTAT_DATA_UINT64 },
373 { "mkdir", KSTAT_DATA_UINT64 },
374 { "symlink", KSTAT_DATA_UINT64 },
375 { "mknod", KSTAT_DATA_UINT64 },
376 { "remove", KSTAT_DATA_UINT64 },
377 { "rmdir", KSTAT_DATA_UINT64 },
378 { "rename", KSTAT_DATA_UINT64 },
379 { "link", KSTAT_DATA_UINT64 },
380 { "readdir", KSTAT_DATA_UINT64 },
381 { "readdirplus", KSTAT_DATA_UINT64 },
382 { "fsstat", KSTAT_DATA_UINT64 },
383 { "fsinfo", KSTAT_DATA_UINT64 },
384 { "pathconf", KSTAT_DATA_UINT64 },
385 { "commit", KSTAT_DATA_UINT64 }
386 };
387
388 static void
389 nfsstat_zone_init_rfsreq_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
390 {
391 statsp->rfsreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
392 "rfsreqcnt_v3", rfsreqcnt_v3_tmpl, sizeof (rfsreqcnt_v3_tmpl));
393 }
394
395 static void
396 nfsstat_zone_fini_rfsreq_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
397 {
398 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsreqcnt_v3");
399 kmem_free(statsp->rfsreqcnt_ptr, sizeof (rfsreqcnt_v3_tmpl));
400 }
401
402 /*
403 * NFSv3 server stats
404 */
405 static const kstat_named_t rfsproccnt_v3_tmpl[] = {
406 { "null", KSTAT_DATA_UINT64 },
407 { "getattr", KSTAT_DATA_UINT64 },
408 { "setattr", KSTAT_DATA_UINT64 },
409 { "lookup", KSTAT_DATA_UINT64 },
410 { "access", KSTAT_DATA_UINT64 },
411 { "readlink", KSTAT_DATA_UINT64 },
412 { "read", KSTAT_DATA_UINT64 },
413 { "write", KSTAT_DATA_UINT64 },
414 { "create", KSTAT_DATA_UINT64 },
415 { "mkdir", KSTAT_DATA_UINT64 },
416 { "symlink", KSTAT_DATA_UINT64 },
417 { "mknod", KSTAT_DATA_UINT64 },
418 { "remove", KSTAT_DATA_UINT64 },
419 { "rmdir", KSTAT_DATA_UINT64 },
420 { "rename", KSTAT_DATA_UINT64 },
421 { "link", KSTAT_DATA_UINT64 },
422 { "readdir", KSTAT_DATA_UINT64 },
423 { "readdirplus", KSTAT_DATA_UINT64 },
424 { "fsstat", KSTAT_DATA_UINT64 },
425 { "fsinfo", KSTAT_DATA_UINT64 },
426 { "pathconf", KSTAT_DATA_UINT64 },
427 { "commit", KSTAT_DATA_UINT64 }
428 };
429
430 #define RFSPROCCNT_V3_COUNT \
431 (sizeof (rfsproccnt_v3_tmpl) / sizeof (rfsproccnt_v3_tmpl[0]))
432
433 kstat_named_t *rfsproccnt_v3_ptr;
434 kstat_t **rfsprocio_v3_ptr;
435
436 static void
437 nfsstat_zone_init_rfsproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
438 {
439 statsp->rfsproccnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
440 "rfsproccnt_v3", rfsproccnt_v3_tmpl, sizeof (rfsproccnt_v3_tmpl));
441
442 mutex_init(&statsp->rfsprocio_lock, NULL, MUTEX_DEFAULT, NULL);
443
444 statsp->rfsprocio_ptr = rfs_kstat_io_init(zoneid, "nfs", 0,
445 "rfsprocio_v3", "rfsprocio_v3", rfsproccnt_v3_tmpl,
446 RFSPROCCNT_V3_COUNT, &statsp->rfsprocio_lock);
447
448 if (zoneid == GLOBAL_ZONEID) {
449 rfsproccnt_v3_ptr = statsp->rfsproccnt_ptr;
450 rfsprocio_v3_ptr = statsp->rfsprocio_ptr;
451 }
452 }
453
454 static void
455 nfsstat_zone_fini_rfsproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
456 {
457 if (zoneid == GLOBAL_ZONEID) {
458 rfsproccnt_v3_ptr = NULL;
459 rfsprocio_v3_ptr = NULL;
460 }
461
462 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v3");
463 kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v3_tmpl));
464
465 rfs_kstat_io_free(statsp->rfsprocio_ptr, RFSPROCCNT_V3_COUNT);
466
467 mutex_destroy(&statsp->rfsprocio_lock);
468 }
469
470 /*
471 * NFSv3 client ACL stats
472 */
473 static const kstat_named_t aclreqcnt_v3_tmpl[] = {
474 { "null", KSTAT_DATA_UINT64 },
475 { "getacl", KSTAT_DATA_UINT64 },
476 { "setacl", KSTAT_DATA_UINT64 },
477 { "getxattrdir", KSTAT_DATA_UINT64 }
478 };
479
480 static void
481 nfsstat_zone_init_aclreq_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
482 {
483 statsp->aclreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
484 "aclreqcnt_v3", aclreqcnt_v3_tmpl, sizeof (aclreqcnt_v3_tmpl));
485 }
486
487 static void
488 nfsstat_zone_fini_aclreq_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
489 {
490 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclreqcnt_v3");
491 kmem_free(statsp->aclreqcnt_ptr, sizeof (aclreqcnt_v3_tmpl));
492 }
493
494 /*
495 * NFSv3 server ACL stats
496 */
497 static const kstat_named_t aclproccnt_v3_tmpl[] = {
498 { "null", KSTAT_DATA_UINT64 },
499 { "getacl", KSTAT_DATA_UINT64 },
500 { "setacl", KSTAT_DATA_UINT64 },
501 { "getxattrdir", KSTAT_DATA_UINT64 }
502 };
503
504 #define ACLPROCCNT_V3_COUNT \
505 (sizeof (aclproccnt_v3_tmpl) / sizeof (aclproccnt_v3_tmpl[0]))
506
507 kstat_named_t *aclproccnt_v3_ptr;
508 kstat_t **aclprocio_v3_ptr;
509
510 static void
511 nfsstat_zone_init_aclproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
512 {
513 statsp->aclproccnt_ptr = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
514 "aclproccnt_v3", aclproccnt_v3_tmpl, sizeof (aclproccnt_v3_tmpl));
515
516 mutex_init(&statsp->aclprocio_lock, NULL, MUTEX_DEFAULT, NULL);
517
518 statsp->aclprocio_ptr = rfs_kstat_io_init(zoneid, "nfs_acl", 0,
519 "aclprocio_v3", "aclprocio_v3", aclproccnt_v3_tmpl,
520 ACLPROCCNT_V3_COUNT, &statsp->aclprocio_lock);
521
522 if (zoneid == GLOBAL_ZONEID) {
523 aclproccnt_v3_ptr = statsp->aclproccnt_ptr;
524 aclprocio_v3_ptr = statsp->aclprocio_ptr;
525 }
526 }
527
528 static void
529 nfsstat_zone_fini_aclproc_v3(zoneid_t zoneid, struct nfs_version_stats *statsp)
530 {
531 if (zoneid == GLOBAL_ZONEID) {
532 aclproccnt_v3_ptr = NULL;
533 aclprocio_v3_ptr = NULL;
534 }
535
536 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v3");
537 kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v3_tmpl));
538
539 rfs_kstat_io_free(statsp->aclprocio_ptr, ACLPROCCNT_V3_COUNT);
540
541 mutex_destroy(&statsp->aclprocio_lock);
542 }
543
544 /*
545 * NFSv4 client stats
546 */
547 static const kstat_named_t rfsreqcnt_v4_tmpl[] = {
548 { "null", KSTAT_DATA_UINT64 },
549 { "compound", KSTAT_DATA_UINT64 },
550 { "reserved", KSTAT_DATA_UINT64 },
551 { "access", KSTAT_DATA_UINT64 },
552 { "close", KSTAT_DATA_UINT64 },
553 { "commit", KSTAT_DATA_UINT64 },
554 { "create", KSTAT_DATA_UINT64 },
555 { "delegpurge", KSTAT_DATA_UINT64 },
556 { "delegreturn", KSTAT_DATA_UINT64 },
557 { "getattr", KSTAT_DATA_UINT64 },
558 { "getfh", KSTAT_DATA_UINT64 },
559 { "link", KSTAT_DATA_UINT64 },
560 { "lock", KSTAT_DATA_UINT64 },
561 { "lockt", KSTAT_DATA_UINT64 },
562 { "locku", KSTAT_DATA_UINT64 },
563 { "lookup", KSTAT_DATA_UINT64 },
564 { "lookupp", KSTAT_DATA_UINT64 },
565 { "nverify", KSTAT_DATA_UINT64 },
566 { "open", KSTAT_DATA_UINT64 },
567 { "openattr", KSTAT_DATA_UINT64 },
568 { "open_confirm", KSTAT_DATA_UINT64 },
569 { "open_downgrade", KSTAT_DATA_UINT64 },
570 { "putfh", KSTAT_DATA_UINT64 },
571 { "putpubfh", KSTAT_DATA_UINT64 },
572 { "putrootfh", KSTAT_DATA_UINT64 },
573 { "read", KSTAT_DATA_UINT64 },
574 { "readdir", KSTAT_DATA_UINT64 },
575 { "readlink", KSTAT_DATA_UINT64 },
576 { "remove", KSTAT_DATA_UINT64 },
577 { "rename", KSTAT_DATA_UINT64 },
578 { "renew", KSTAT_DATA_UINT64 },
579 { "restorefh", KSTAT_DATA_UINT64 },
580 { "savefh", KSTAT_DATA_UINT64 },
581 { "secinfo", KSTAT_DATA_UINT64 },
582 { "setattr", KSTAT_DATA_UINT64 },
583 { "setclientid", KSTAT_DATA_UINT64 },
584 { "setclientid_confirm", KSTAT_DATA_UINT64 },
585 { "verify", KSTAT_DATA_UINT64 },
586 { "write", KSTAT_DATA_UINT64 }
587 };
588
589 static void
590 nfsstat_zone_init_rfsreq_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
591 {
592 statsp->rfsreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
593 "rfsreqcnt_v4", rfsreqcnt_v4_tmpl, sizeof (rfsreqcnt_v4_tmpl));
594 }
595
596 static void
597 nfsstat_zone_fini_rfsreq_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
598 {
599 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsreqcnt_v4");
600 kmem_free(statsp->rfsreqcnt_ptr, sizeof (rfsreqcnt_v4_tmpl));
601 }
602
603 /*
604 * NFSv4 server stats
605 */
606 static const kstat_named_t rfsproccnt_v4_tmpl[] = {
607 { "null", KSTAT_DATA_UINT64 },
608 { "compound", KSTAT_DATA_UINT64 },
609 { "reserved", KSTAT_DATA_UINT64 },
610 { "access", KSTAT_DATA_UINT64 },
611 { "close", KSTAT_DATA_UINT64 },
612 { "commit", KSTAT_DATA_UINT64 },
613 { "create", KSTAT_DATA_UINT64 },
614 { "delegpurge", KSTAT_DATA_UINT64 },
615 { "delegreturn", KSTAT_DATA_UINT64 },
616 { "getattr", KSTAT_DATA_UINT64 },
617 { "getfh", KSTAT_DATA_UINT64 },
618 { "link", KSTAT_DATA_UINT64 },
619 { "lock", KSTAT_DATA_UINT64 },
620 { "lockt", KSTAT_DATA_UINT64 },
621 { "locku", KSTAT_DATA_UINT64 },
622 { "lookup", KSTAT_DATA_UINT64 },
623 { "lookupp", KSTAT_DATA_UINT64 },
624 { "nverify", KSTAT_DATA_UINT64 },
625 { "open", KSTAT_DATA_UINT64 },
626 { "openattr", KSTAT_DATA_UINT64 },
627 { "open_confirm", KSTAT_DATA_UINT64 },
628 { "open_downgrade", KSTAT_DATA_UINT64 },
629 { "putfh", KSTAT_DATA_UINT64 },
630 { "putpubfh", KSTAT_DATA_UINT64 },
631 { "putrootfh", KSTAT_DATA_UINT64 },
632 { "read", KSTAT_DATA_UINT64 },
633 { "readdir", KSTAT_DATA_UINT64 },
634 { "readlink", KSTAT_DATA_UINT64 },
635 { "remove", KSTAT_DATA_UINT64 },
636 { "rename", KSTAT_DATA_UINT64 },
637 { "renew", KSTAT_DATA_UINT64 },
638 { "restorefh", KSTAT_DATA_UINT64 },
639 { "savefh", KSTAT_DATA_UINT64 },
640 { "secinfo", KSTAT_DATA_UINT64 },
641 { "setattr", KSTAT_DATA_UINT64 },
642 { "setclientid", KSTAT_DATA_UINT64 },
643 { "setclientid_confirm", KSTAT_DATA_UINT64 },
644 { "verify", KSTAT_DATA_UINT64 },
645 { "write", KSTAT_DATA_UINT64 },
646 { "release_lockowner", KSTAT_DATA_UINT64 },
647 { "illegal", KSTAT_DATA_UINT64 },
648 };
649
650 #define RFSPROCCNT_V4_COUNT \
651 (sizeof (rfsproccnt_v4_tmpl) / sizeof (rfsproccnt_v4_tmpl[0]))
652
653 kstat_named_t *rfsproccnt_v4_ptr;
654 kstat_t **rfsprocio_v4_ptr;
655
656 static void
657 nfsstat_zone_init_rfsproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
658 {
659 statsp->rfsproccnt_ptr = nfsstat_zone_init_common(zoneid, "nfs", 0,
660 "rfsproccnt_v4", rfsproccnt_v4_tmpl, sizeof (rfsproccnt_v4_tmpl));
661
662 mutex_init(&statsp->rfsprocio_lock, NULL, MUTEX_DEFAULT, NULL);
663
664 statsp->rfsprocio_ptr = rfs_kstat_io_init(zoneid, "nfs", 0,
665 "rfsprocio_v4", "rfsprocio_v4", rfsproccnt_v4_tmpl,
666 RFSPROCCNT_V4_COUNT, &statsp->rfsprocio_lock);
667
668 if (zoneid == GLOBAL_ZONEID) {
669 rfsproccnt_v4_ptr = statsp->rfsproccnt_ptr;
670 rfsprocio_v4_ptr = statsp->rfsprocio_ptr;
671 }
672 }
673
674 static void
675 nfsstat_zone_fini_rfsproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
676 {
677 if (zoneid == GLOBAL_ZONEID) {
678 rfsproccnt_v4_ptr = NULL;
679 rfsprocio_v4_ptr = NULL;
680 }
681
682 nfsstat_zone_fini_common(zoneid, "nfs", 0, "rfsproccnt_v4");
683 kmem_free(statsp->rfsproccnt_ptr, sizeof (rfsproccnt_v4_tmpl));
684
685 rfs_kstat_io_free(statsp->rfsprocio_ptr, RFSPROCCNT_V4_COUNT);
686
687 mutex_destroy(&statsp->rfsprocio_lock);
688 }
689
690 /*
691 * NFSv4 client ACL stats
692 */
693 static const kstat_named_t aclreqcnt_v4_tmpl[] = {
694 { "null", KSTAT_DATA_UINT64 },
695 { "getacl", KSTAT_DATA_UINT64 },
696 { "setacl", KSTAT_DATA_UINT64 },
697 };
698
699 static void
700 nfsstat_zone_init_aclreq_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
701 {
702 statsp->aclreqcnt_ptr = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
703 "aclreqcnt_v4", aclreqcnt_v4_tmpl, sizeof (aclreqcnt_v4_tmpl));
704 }
705
706 static void
707 nfsstat_zone_fini_aclreq_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
708 {
709 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclreqcnt_v4");
710 kmem_free(statsp->aclreqcnt_ptr, sizeof (aclreqcnt_v4_tmpl));
711 }
712
713 /*
714 * NFSv4 server ACL stats
715 */
716 static const kstat_named_t aclproccnt_v4_tmpl[] = {
717 { "null", KSTAT_DATA_UINT64 },
718 { "getacl", KSTAT_DATA_UINT64 },
719 { "setacl", KSTAT_DATA_UINT64 }
720 };
721
722 kstat_named_t *aclproccnt_v4_ptr;
723
724 static void
725 nfsstat_zone_init_aclproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
726 {
727 kstat_named_t *ks_data;
728
729 ks_data = nfsstat_zone_init_common(zoneid, "nfs_acl", 0,
730 "aclproccnt_v4", aclproccnt_v4_tmpl,
731 sizeof (aclproccnt_v4_tmpl));
732 statsp->aclproccnt_ptr = ks_data;
733 if (zoneid == GLOBAL_ZONEID)
734 aclproccnt_v4_ptr = ks_data;
735 }
736
737 static void
738 nfsstat_zone_fini_aclproc_v4(zoneid_t zoneid, struct nfs_version_stats *statsp)
739 {
740 if (zoneid == GLOBAL_ZONEID)
741 aclproccnt_v4_ptr = NULL;
742 nfsstat_zone_fini_common(zoneid, "nfs_acl", 0, "aclproccnt_v4");
743 kmem_free(statsp->aclproccnt_ptr, sizeof (aclproccnt_v4_tmpl));
744 }
745
746
747 /*
748 * NFS server per share kstats (exp_kstats)
749 * kstats are collected per share for NFSv3 & NFSv4 read and write operations.
750 */
751 #define NFSSRV_SHR_READ 0
752 #define NFSSRV_SHR_WRITE 1
753
754 static const kstat_named_t rfsshr_tmpl[] = {
755 { "read", KSTAT_DATA_UINT64 }, /* NFSSRV_SHR_READ */
756 { "write", KSTAT_DATA_UINT64 } /* NFSSRV_SHR_WRITE */
757 };
758 #define RFSSHARE_COUNT \
759 (sizeof (rfsshr_tmpl) / sizeof (rfsshr_tmpl[0]))
760
761 /*
762 * Zone initializer callback to setup the kstats.
763 */
764 void *
765 nfsstat_zone_init(zoneid_t zoneid)
766 {
767 struct nfs_stats *nfs_stats_ptr;
768
769 nfs_stats_ptr = kmem_zalloc(sizeof (*nfs_stats_ptr), KM_SLEEP);
770
771 /*
772 * Initialize all versions of the nfs_server
773 */
774 nfsstat_zone_init_server(zoneid, nfs_stats_ptr->nfs_stats_svstat_ptr);
775
776 /*
777 * Initialize v2 stats
778 */
779 nfsstat_zone_init_rfsreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
780 nfsstat_zone_init_rfsproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
781 nfsstat_zone_init_aclreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
782 nfsstat_zone_init_aclproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
783 /*
784 * Initialize v3 stats
785 */
786 nfsstat_zone_init_rfsreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
787 nfsstat_zone_init_rfsproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
788 nfsstat_zone_init_aclreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
789 nfsstat_zone_init_aclproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
790 /*
791 * Initialize v4 stats
792 */
793 nfsstat_zone_init_rfsreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
794 nfsstat_zone_init_rfsproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
795 nfsstat_zone_init_aclreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
796 nfsstat_zone_init_aclproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
797
798 return (nfs_stats_ptr);
799 }
800
801 /*
802 * Zone destructor callback to tear down the various kstats.
803 */
804 void
805 nfsstat_zone_fini(zoneid_t zoneid, void *data)
806 {
807 struct nfs_stats *nfs_stats_ptr = data;
808
809 /*
810 * Free nfs:0:nfs_server stats
811 */
812 nfsstat_zone_fini_server(zoneid, nfs_stats_ptr->nfs_stats_svstat_ptr);
813
814 /*
815 * Free v2 stats
816 */
817 nfsstat_zone_fini_rfsreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
818 nfsstat_zone_fini_rfsproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
819 nfsstat_zone_fini_aclreq_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
820 nfsstat_zone_fini_aclproc_v2(zoneid, &nfs_stats_ptr->nfs_stats_v2);
821 /*
822 * Free v3 stats
823 */
824 nfsstat_zone_fini_rfsreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
825 nfsstat_zone_fini_rfsproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
826 nfsstat_zone_fini_aclreq_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
827 nfsstat_zone_fini_aclproc_v3(zoneid, &nfs_stats_ptr->nfs_stats_v3);
828 /*
829 * Free v4 stats
830 */
831 nfsstat_zone_fini_rfsreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
832 nfsstat_zone_fini_rfsproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
833 nfsstat_zone_fini_aclreq_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
834 nfsstat_zone_fini_aclproc_v4(zoneid, &nfs_stats_ptr->nfs_stats_v4);
835
836 kmem_free(nfs_stats_ptr, sizeof (*nfs_stats_ptr));
837 }
838
839 /*
840 * Support for exp_kstats initialization and tear down
841 */
842 struct exp_kstats *
843 exp_kstats_init(zoneid_t zoneid, int instance, const char *path, size_t len,
844 bool_t pseudo)
845 {
846 struct exp_kstats *exp_kstats;
847
848 exp_kstats = kmem_alloc(sizeof (*exp_kstats), KM_SLEEP);
849
850 mutex_init(&exp_kstats->procio_lock, NULL, MUTEX_DEFAULT, NULL);
851
852 /*
853 * Generic share kstat.
854 */
855 exp_kstats->share_kstat = kstat_create_zone("nfs", instance, "share",
856 "misc", KSTAT_TYPE_NAMED,
857 sizeof (exp_kstats->share_kstat_data) / sizeof (kstat_named_t),
858 KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE, zoneid);
859 if (exp_kstats->share_kstat != NULL) {
860 len = strnlen(path, len);
861 exp_kstats->share_path = kmem_alloc(len + 1, KM_SLEEP);
862 bcopy(path, exp_kstats->share_path, len);
863 exp_kstats->share_path[len] = '\0';
864
865 exp_kstats->share_kstat->ks_data =
866 &exp_kstats->share_kstat_data;
867
868 kstat_named_init(&exp_kstats->share_kstat_data.path, "path",
869 KSTAT_DATA_STRING);
870 kstat_named_setstr(&exp_kstats->share_kstat_data.path,
871 exp_kstats->share_path);
872
873 kstat_named_init(&exp_kstats->share_kstat_data.filesystem,
874 "filesystem", KSTAT_DATA_STRING);
875 kstat_named_setstr(&exp_kstats->share_kstat_data.filesystem,
876 pseudo ? "pseudo" : "real");
877
878 exp_kstats->share_kstat->ks_lock = &exp_kstats->procio_lock;
879 kstat_install(exp_kstats->share_kstat);
880 }
881
882 /* NFS version 3 */
883 exp_kstats->rfsshr_v3_ptr = rfs_kstat_io_init(zoneid, "nfs",
884 instance, "share_v3", "rfsprocio_v3", rfsshr_tmpl,
885 RFSSHARE_COUNT, &exp_kstats->procio_lock);
886
887 /* NFS version 4 */
888 exp_kstats->rfsshr_v4_ptr = rfs_kstat_io_init(zoneid, "nfs",
889 instance, "share_v4", "rfsprocio_v4", rfsshr_tmpl,
890 RFSSHARE_COUNT, &exp_kstats->procio_lock);
891
892 return (exp_kstats);
893 }
894
895 void
896 exp_kstats_delete(struct exp_kstats *exp_kstats)
897 {
898 if (exp_kstats == NULL)
899 return;
900
901 /* Generic share kstat */
902 if (exp_kstats->share_kstat != NULL) {
903 kstat_delete(exp_kstats->share_kstat);
904 exp_kstats->share_kstat = NULL;
905 strfree(exp_kstats->share_path);
906 }
907
908 rfs_kstat_io_delete(exp_kstats->rfsshr_v3_ptr, RFSSHARE_COUNT);
909 rfs_kstat_io_delete(exp_kstats->rfsshr_v4_ptr, RFSSHARE_COUNT);
910
911 }
912
913 void
914 exp_kstats_fini(struct exp_kstats *exp_kstats)
915 {
916 if (exp_kstats == NULL)
917 return;
918
919 /* Generic share kstat */
920 if (exp_kstats->share_kstat != NULL) {
921 kstat_delete(exp_kstats->share_kstat);
922 strfree(exp_kstats->share_path);
923 }
924
925 rfs_kstat_io_free(exp_kstats->rfsshr_v3_ptr, RFSSHARE_COUNT);
926 rfs_kstat_io_free(exp_kstats->rfsshr_v4_ptr, RFSSHARE_COUNT);
927
928 mutex_destroy(&exp_kstats->procio_lock);
929
930 kmem_free(exp_kstats, sizeof (*exp_kstats));
931 }
932
933 void
934 exp_kstats_reset(struct exp_kstats *exp_kstats, const char *path, size_t len,
935 bool_t pseudo)
936 {
937 char *old;
938 char *new;
939
940 if ((exp_kstats == NULL) || (exp_kstats->share_kstat == NULL))
941 return;
942
943 len = strnlen(path, len);
944 new = kmem_alloc(len + 1, KM_SLEEP);
945 bcopy(path, new, len);
946 new[len] = '\0';
947
948 mutex_enter(exp_kstats->share_kstat->ks_lock);
949 old = exp_kstats->share_path;
950 exp_kstats->share_path = new;
951 kstat_named_setstr(&exp_kstats->share_kstat_data.path,
952 exp_kstats->share_path);
953 kstat_named_setstr(&exp_kstats->share_kstat_data.filesystem,
954 pseudo ? "pseudo" : "real");
955 mutex_exit(exp_kstats->share_kstat->ks_lock);
956
957 strfree(old);
958 }
959
960 kstat_t *
961 /* LINTED E_FUNC_ARG_UNUSED */
962 exp_kstats_v2(struct exp_kstats *exp_kstats, uint_t op)
963 {
964 /* No NFS v2 per-share kstats */
965 return (NULL);
966 }
967
968 kstat_t *
969 exp_kstats_v3(struct exp_kstats *exp_kstats, uint_t op)
970 {
971 if (exp_kstats == NULL)
972 return (NULL);
973
974 /* per share kstats for selected operations (read, write) only */
975 switch (op) {
976 case NFSPROC3_READ:
977 return (exp_kstats->rfsshr_v3_ptr[NFSSRV_SHR_READ]);
978 case NFSPROC3_WRITE:
979 return (exp_kstats->rfsshr_v3_ptr[NFSSRV_SHR_WRITE]);
980 default:
981 return (NULL);
982 }
983 }
984
985 kstat_t *
986 exp_kstats_v4(struct exp_kstats *exp_kstats, uint_t op)
987 {
988 if (exp_kstats == NULL)
989 return (NULL);
990
991 /* per share kstats for selected operations (read, write) only */
992 switch (op) {
993 case OP_READ:
994 return (exp_kstats->rfsshr_v4_ptr[NFSSRV_SHR_READ]);
995 case OP_WRITE:
996 return (exp_kstats->rfsshr_v4_ptr[NFSSRV_SHR_WRITE]);
997 default:
998 return (NULL);
999 }
1000 }