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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
36 #include <sys/nsctl/rdc.h>
37 #include <sys/nsctl/rdc_io.h>
38 #include <sys/nsctl/rdc_bitmap.h>
40 #include "sdbc_stats.h"
41 #include "sndr_stats.h"
47 static sndrstat_t
*sndr_top
;
49 void sndr_add_stat(sndrstat_t
*);
50 sndrstat_t
*sndr_del_stat(sndrstat_t
*);
52 int sndr_value_check(sndrstat_t
*);
53 int sndr_validate(kstat_t
*);
54 int sndr_strcmp(char *, char *);
55 int sndr_vol_selected(kstat_t
*);
57 void getType(kstat_t
*, char *);
58 void getStat(kstat_t
*, char *);
59 void getQueue(kstat_t
*, char *);
60 void printQueueStats(int, kstat_t
*);
61 float getSyncNeeded(kstat_t
*);
63 static void update_sighandler(int);
64 static void discover_sighandler(int);
66 static sigjmp_buf update_env
, discover_env
;
67 static sig_atomic_t sig_raised
= 0;
69 * sndr_discover() - looks for new statistics to be monitored.
70 * Verifies that any statistics found are now already being
75 sndr_discover(kstat_ctl_t
*kc
)
77 static int validated
= 0;
78 struct sigaction segv_act
;
83 (void) signal(SIGSEGV
, discover_sighandler
);
84 (void) sigaction(SIGSEGV
, NULL
, &segv_act
);
86 /* Loop on all kstats */
87 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
89 char kname
[KSTAT_STRLEN
+ 1];
91 sndrstat_t
*sndrstat
= NULL
;
95 /* Serach for SNDR set */
96 if (strcmp(ksp
->ks_module
, RDC_KSTAT_MODULE
) != 0 ||
97 strcmp(ksp
->ks_name
, RDC_KSTAT_INFO
) != 0) {
101 if (kstat_read(kc
, ksp
, NULL
) == -1)
105 * Validate kstat structure
108 if (sndr_validate(ksp
))
117 for (cur
= sndr_top
; cur
!= NULL
; cur
= cur
->next
) {
118 char *cur_vname
, *tst_vname
;
119 uint32_t cur_inst
, tst_inst
;
121 cur_vname
= kstat_value(cur
->pre_set
, RDC_IKSTAT_FILE
);
122 cur_inst
= cur
->pre_set
->ks_instance
;
124 tst_vname
= kstat_value(ksp
, RDC_IKSTAT_FILE
);
125 tst_inst
= ksp
->ks_instance
;
127 if (strcmp(cur_vname
, tst_vname
) == 0 &&
128 cur_inst
== tst_inst
)
133 * Initialize new record
135 sndrstat
= (sndrstat_t
*)calloc(1, sizeof (sndrstat_t
));
136 kinst
= ksp
->ks_instance
;
141 sndrstat
->pre_set
= kstat_retrieve(kc
, ksp
);
143 if (sndrstat
->pre_set
== NULL
)
146 sndrstat
->collected
|= GOT_SET_KSTAT
;
151 (void) sprintf(kname
, "%s%d", RDC_KSTAT_BMPNAME
, kinst
);
153 bmp_ksp
= kstat_lookup(kc
, RDC_KSTAT_BMPNAME
, kinst
, kname
);
154 sndrstat
->pre_bmp
= kstat_retrieve(kc
, bmp_ksp
);
156 if (sndrstat
->pre_bmp
== NULL
)
159 sndrstat
->collected
|= GOT_BMP_KSTAT
;
164 (void) sprintf(kname
, "%s%d", RDC_KSTAT_RDCNAME
, kinst
);
166 sec_ksp
= kstat_lookup(kc
, RDC_KSTAT_MODULE
, kinst
, kname
);
167 sndrstat
->pre_sec
= kstat_retrieve(kc
, sec_ksp
);
169 if (sndrstat
->pre_sec
== NULL
)
172 sndrstat
->collected
|= GOT_SEC_KSTAT
;
176 * Check if we got a complete set of stats
178 if (sndrstat
== NULL
)
181 if (SNDR_COMPLETE(sndrstat
->collected
)) {
182 (void) sndr_del_stat(sndrstat
);
189 sndr_add_stat(sndrstat
);
192 (void) sigsetjmp(discover_env
, 0);
197 (void) sigaction(SIGSEGV
, &segv_act
, NULL
);
203 discover_sighandler(int sig
)
208 siglongjmp(discover_env
, sig
);
215 update_sighandler(int sig
)
220 siglongjmp(update_env
, sig
);
227 * sndr_update() - updates all of the statistics currently being monitored.
231 sndr_update(kstat_ctl_t
*kc
)
234 struct sigaction segv_act
;
237 (void) signal(SIGSEGV
, update_sighandler
);
238 (void) sigaction(SIGSEGV
, NULL
, &segv_act
);
240 for (cur
= sndr_top
; cur
!= NULL
; cur
= cur
->next
) {
242 char kname
[KSTAT_STRLEN
+ 1];
244 char *cur_vname
, *tst_vname
;
251 if (cur
->cur_set
!= NULL
) {
252 kstat_free(cur
->pre_set
);
253 kstat_free(cur
->pre_bmp
);
254 kstat_free(cur
->pre_sec
);
256 cur
->pre_set
= cur
->cur_set
;
257 cur
->pre_bmp
= cur
->cur_bmp
;
258 cur
->pre_sec
= cur
->cur_sec
;
264 (void) strncpy(kname
, cur
->pre_set
->ks_name
, KSTAT_STRLEN
);
265 kname
[KSTAT_STRLEN
] = '\0';
267 kinst
= cur
->pre_set
->ks_instance
;
269 ksp
= kstat_lookup(kc
, RDC_KSTAT_MODULE
, kinst
, kname
);
271 if ((cur
->cur_set
= kstat_retrieve(kc
, ksp
)) == NULL
)
274 cur
->collected
|= GOT_SET_KSTAT
;
279 cur_vname
= kstat_value(cur
->pre_set
, RDC_IKSTAT_FILE
);
280 tst_vname
= kstat_value(cur
->cur_set
, RDC_IKSTAT_FILE
);
282 if (strcmp(cur_vname
, tst_vname
) != 0)
288 (void) sprintf(kname
, "%s%d", RDC_KSTAT_BMPNAME
, kinst
);
290 ksp
= kstat_lookup(kc
, RDC_KSTAT_BMPNAME
, kinst
, kname
);
292 if ((cur
->cur_bmp
= kstat_retrieve(kc
, ksp
)) == NULL
)
295 cur
->collected
|= GOT_BMP_KSTAT
;
300 (void) sprintf(kname
, "%s%d", RDC_KSTAT_RDCNAME
, kinst
);
302 ksp
= kstat_lookup(kc
, RDC_KSTAT_MODULE
, kinst
, kname
);
304 if ((cur
->cur_sec
= kstat_retrieve(kc
, ksp
)) == NULL
)
307 cur
->collected
|= GOT_SEC_KSTAT
;
311 (void) sigsetjmp(update_env
, 0);
316 (void) sigaction(SIGSEGV
, &segv_act
, NULL
);
322 * sndr_report() - outputs statistics for the statistics currently being
323 * monitored. Deletes statistics for volumes that have been disabled.
331 sndrstat_t
*cur
, *pre
= NULL
;
333 if (sndr_top
== NULL
)
336 /* Create padding string for secondary report lines */
338 if (dflags
& FLAGS
) {
339 padsz
+= STAT_HDR_SIZE
;
340 padsz
+= STAT_HDR_SIZE
;
343 if (dflags
& ASYNC_QUEUE
)
344 padsz
+= STAT_HDR_SIZE
;
347 padsz
+= PCT_HDR_SIZE
;
351 (void) sprintf(fmt
, "%%%ds", padsz
);
352 (void) sprintf(pad
, fmt
, " ");
355 for (cur
= sndr_top
; cur
!= NULL
; ) { /*CSTYLED */
359 /* Check to see if this is this a complete */
360 if (SNDR_COMPLETE(cur
->collected
)) {
362 char vn
[NSC_MAXPATH
+ 1];
365 /* notify user of set being disabled */
366 c
= kstat_value(cur
->pre_set
, RDC_IKSTAT_SECFILE
);
367 (void) strncpy(vn
, c
, NSC_MAXPATH
);
368 vn
[NSC_MAXPATH
] = '\0';
370 (void) printf(DATA_C16
, vn
);
371 (void) printf(" %s\n", RDC_DISABLED
);
373 next
= sndr_del_stat(cur
);
375 /* free memory and remove stat from list */
377 cur
= sndr_top
= next
;
379 cur
= pre
->next
= next
;
384 /* Check to see if the user specified this volume */
385 if (! sndr_vol_selected(cur
->pre_set
))
388 /* Check to see if zflag applies */
389 if (zflag
&& sndr_value_check(cur
) == 0)
392 /* Calculate flags */
393 if (dflags
& FLAGS
) {
394 char c
[STAT_HDR_SIZE
];
395 char vtype
[STAT_HDR_SIZE
];
396 char vstat
[STAT_HDR_SIZE
];
398 getType(cur
->cur_set
, &c
[0]);
399 (void) sprintf(vtype
, DATA_C2
, c
);
400 (void) strcat(data
, vtype
);
402 getStat(cur
->cur_set
, &c
[0]);
403 (void) sprintf(vstat
, DATA_C2
, c
);
404 (void) strcat(data
, vstat
);
407 /* Async. queue statistics */
408 if (dflags
& ASYNC_QUEUE
) {
409 char c
[STAT_HDR_SIZE
];
410 char qtype
[STAT_HDR_SIZE
];
412 getQueue(cur
->cur_set
, &c
[0]);
413 (void) sprintf(qtype
, DATA_C2
, c
);
414 (void) strcat(data
, qtype
);
417 /* Calculate sync needed percentages */
421 (void) sprintf(snpct
, DATA_F62
,
422 getSyncNeeded(cur
->cur_set
));
423 (void) strcat(data
, snpct
);
427 if (rflags
& SNDR_NET
) {
429 char type
[STAT_HDR_SIZE
];
430 char vn
[NAMED_LEN
+ 1];
432 getType(cur
->cur_set
, &type
[0]);
434 if (type
[0] == 'S') {
435 c
= kstat_value(cur
->pre_set
,
438 c
= kstat_value(cur
->pre_set
,
442 /* Only print last 15 characters */
443 if (strlen(c
) >= NAMED_LEN
) {
444 c
+= strlen(c
) - NAMED_LEN
;
446 (void) strncpy(vn
, c
, NAMED_LEN
);
447 vn
[NAMED_LEN
] = '\0';
450 (void) printf(DATA_C16
, vn
);
451 (void) printf("%s", data
);
452 (void) printf(ROLE_INF_FMT
, RDC_SECONDARY
);
454 /* Async. queue statistics */
455 if (dflags
& ASYNC_QUEUE
)
456 printQueueStats(first
, cur
->cur_set
);
458 io_report(cur
->cur_sec
, cur
->pre_sec
,
463 (void) strcpy(data
, strlen(pad
) > 0 ? pad
: "");
468 if (rflags
& SNDR_BMP
) {
472 c
= kstat_value(cur
->pre_set
, RDC_IKSTAT_BITMAP
);
474 /* Only print last 15 characters */
475 if (strlen(c
) >= NAMED_LEN
) {
476 c
+= strlen(c
) - NAMED_LEN
;
478 (void) strncpy(vn
, c
, NAMED_LEN
);
479 vn
[NAMED_LEN
] = '\0';
482 (void) printf(DATA_C16
, vn
);
483 (void) printf("%s", data
);
484 (void) printf(ROLE_INF_FMT
, RDC_BITMAP
);
486 /* Async. queue statistics */
487 if (dflags
& ASYNC_QUEUE
)
488 printQueueStats(first
, cur
->cur_set
);
490 io_report(cur
->cur_bmp
, cur
->pre_bmp
,
495 (void) strcpy(data
, strlen(pad
) > 0 ? pad
: "");
508 * sndr_add_stat() - adds a fully populated sndrstat_t structure
509 * to the linked list of currently monitored kstats. The structure
510 * will be added in alphabetical order, using the volume name as the
514 * sndrstat_t *sndrstat - to be added to the list.
518 sndr_add_stat(sndrstat_t
*sndrstat
)
523 if (sndr_top
== NULL
) {
528 for (cur
= sndr_top
; cur
!= NULL
; cur
= cur
->next
) {
529 char *cur_vname
, *nxt_vname
, *tst_vname
;
531 cur_vname
= kstat_value(cur
->pre_set
, RDC_IKSTAT_FILE
);
532 tst_vname
= kstat_value(sndrstat
->pre_set
, RDC_IKSTAT_FILE
);
534 if (strcmp(cur_vname
, tst_vname
) <= 0) {
536 * If we get to the last item in the list, then just
537 * add this one to the end
539 if (cur
->next
== NULL
) {
540 cur
->next
= sndrstat
;
544 nxt_vname
= kstat_value(cur
->next
->pre_set
,
547 if (strcmp(nxt_vname
, tst_vname
) > 0) {
548 sndrstat
->next
= cur
->next
;
549 cur
->next
= sndrstat
;
556 sndrstat
->next
= cur
;
564 * sndr_del_stat() - deallocate memory for the structure being
568 * sndrstat_t *sndrstat - structure to be deallocated
571 * sndrstat_t * - pointer to the "next" structures in the
572 * linked list. May be NULL if we are removing the last
573 * structure in the linked list.
577 sndr_del_stat(sndrstat_t
*sndrstat
)
580 sndrstat_t
*next
= sndrstat
->next
;
582 kstat_free(sndrstat
->pre_set
);
583 kstat_free(sndrstat
->pre_bmp
);
584 kstat_free(sndrstat
->pre_sec
);
585 kstat_free(sndrstat
->cur_set
);
586 kstat_free(sndrstat
->cur_bmp
);
587 kstat_free(sndrstat
->cur_sec
);
595 * sndr_value_check() - check to determine if any activity was registered
596 * on this volume by checking the previous stats vs. the current stats.
599 * sndrstat_t *sndrstat - structure to be checked
606 sndr_value_check(sndrstat_t
*sndrstat
)
608 if (SNDR_COMPLETE(sndrstat
->collected
))
611 if (io_value_check(sndrstat
->pre_bmp
->ks_data
,
612 sndrstat
->cur_bmp
->ks_data
)) {
616 if (io_value_check(sndrstat
->pre_sec
->ks_data
,
617 sndrstat
->cur_sec
->ks_data
)) {
625 * sndr_validate() - validates the fields required by dsstat exist in
626 * the kstat_t structure passed in. This check keeps dsstat from
627 * core dumping if the kstat_named_t structures change in any of the
628 * services that dsstat monitors.
631 * kstat_t *ksp - kstat_t structure to check. The ks_data field
632 * should have been populated with a call to kstat_read()
635 * 0 - all fields are contained in the kstat
636 * 1 - a field required by dsstat is not in the kstat
639 sndr_validate(kstat_t
*ksp
)
641 if (! kstat_value(ksp
, RDC_IKSTAT_FILE
) ||
642 ! kstat_value(ksp
, RDC_IKSTAT_FLAGS
) ||
643 ! kstat_value(ksp
, RDC_IKSTAT_SYNCFLAGS
) ||
644 ! kstat_value(ksp
, RDC_IKSTAT_BMPFLAGS
) ||
645 ! kstat_value(ksp
, RDC_IKSTAT_VOLSIZE
) ||
646 ! kstat_value(ksp
, RDC_IKSTAT_BITSSET
) ||
647 ! kstat_value(ksp
, RDC_IKSTAT_QUEUE_TYPE
) ||
648 ! kstat_value(ksp
, RDC_IKSTAT_ASYNC_ITEMS
) ||
649 ! kstat_value(ksp
, RDC_IKSTAT_ASYNC_BLOCKS
) ||
650 ! kstat_value(ksp
, RDC_IKSTAT_ASYNC_ITEM_HWM
) ||
651 ! kstat_value(ksp
, RDC_IKSTAT_ASYNC_BLOCK_HWM
))
658 getType(kstat_t
*ksp
, char *vtype
)
662 set_flags
= kstat_value(ksp
, RDC_IKSTAT_FLAGS
);
664 if (*set_flags
& RDC_PRIMARY
)
665 (void) strcpy(vtype
, "P");
667 (void) strcpy(vtype
, "S");
671 getStat(kstat_t
*ksp
, char *vstat
)
677 set_flags
= kstat_value(ksp
, RDC_IKSTAT_FLAGS
);
678 syn_flags
= kstat_value(ksp
, RDC_IKSTAT_SYNCFLAGS
);
679 bmp_flags
= kstat_value(ksp
, RDC_IKSTAT_BMPFLAGS
);
681 (void) strcpy(vstat
, "R");
683 if (*set_flags
& RDC_SYNCING
) {
684 if (*set_flags
& RDC_SLAVE
)
685 if (*set_flags
& RDC_PRIMARY
)
686 (void) strcpy(vstat
, "RS");
688 (void) strcpy(vstat
, "SY");
690 if (*set_flags
& RDC_PRIMARY
)
691 (void) strcpy(vstat
, "SY");
693 (void) strcpy(vstat
, "RS");
696 if (*set_flags
& RDC_LOGGING
) {
697 (void) strcpy(vstat
, "L");
699 if (*set_flags
& RDC_QUEUING
)
700 (void) strcpy(vstat
, "Q");
702 if (*set_flags
& RDC_DISKQ_FAILED
)
703 (void) strcpy(vstat
, "QF");
705 if (*syn_flags
& RDC_SYNC_NEEDED
)
706 (void) strcpy(vstat
, "SN");
708 if (*syn_flags
& RDC_RSYNC_NEEDED
)
709 (void) strcpy(vstat
, "RN");
712 if (*syn_flags
& RDC_FCAL_FAILED
)
713 (void) strcpy(vstat
, "FF");
715 if (*bmp_flags
& RDC_BMP_FAILED
)
716 (void) strcpy(vstat
, "BF");
718 if (*syn_flags
& RDC_VOL_FAILED
)
719 (void) strcpy(vstat
, "VF");
723 getQueue(kstat_t
*ksp
, char *vqueue
)
727 (void) strcpy(vqueue
, "-");
729 qtype
= kstat_value(ksp
, RDC_IKSTAT_QUEUE_TYPE
);
731 if (strcmp(qtype
, "memory") == 0)
732 (void) strcpy(vqueue
, "M");
734 if (strcmp(qtype
, "disk") == 0)
735 (void) strcpy(vqueue
, "D");
739 getSyncNeeded(kstat_t
*ksp
)
741 uint32_t *volsize
, *bitsset
;
745 volsize
= kstat_value(ksp
, RDC_IKSTAT_VOLSIZE
);
746 bitsset
= kstat_value(ksp
, RDC_IKSTAT_BITSSET
);
748 segs
= FBA_TO_LOG_LEN(*volsize
);
749 bits
= *bitsset
> 0 ? *bitsset
: 0;
751 pct
= segs
? ((float)bits
/(float)segs
) : 0.0;
758 * Special handling for compatibility.
759 * "dsstat -s <set>" allows set name to be the last 15 chars,
760 * due to 15 characters limit of old kstat information.
763 * 1) full and partial are same
764 * 2) partial is the last 15 chars of full
767 sndr_strcmp(char *full
, char *partial
)
772 rc
= strcmp(full
, partial
);
775 (strlen(partial
) == NAMED_LEN
) &&
776 (strlen(full
) > NAMED_LEN
)) {
777 f
+= strlen(full
) - NAMED_LEN
;
778 rc
= strncmp(f
, partial
, NAMED_LEN
);
785 sndr_vol_selected(kstat_t
*ksp
)
787 vslist_t
*vslist
= vs_top
;
789 for (vslist
= vs_top
; vslist
!= NULL
; vslist
= vslist
->next
) {
793 /* If no host specified, check local only */
794 if (vslist
->volhost
== NULL
) {
795 vn
= kstat_value(ksp
, RDC_IKSTAT_FILE
);
797 if (sndr_strcmp(vn
, vslist
->volname
))
804 vn
= kstat_value(ksp
, RDC_IKSTAT_FILE
);
805 vh
= kstat_value(ksp
, RDC_IKSTAT_PRIMARY_HOST
);
807 if (sndr_strcmp(vn
, vslist
->volname
) == 0 &&
808 sndr_strcmp(vh
, vslist
->volhost
) == 0)
811 /* Check secondary */
812 vn
= kstat_value(ksp
, RDC_IKSTAT_SECFILE
);
813 vh
= kstat_value(ksp
, RDC_IKSTAT_SECONDARY_HOST
);
815 if (sndr_strcmp(vn
, vslist
->volname
) == 0 &&
816 sndr_strcmp(vh
, vslist
->volhost
) == 0)
820 if (vs_top
!= NULL
&& vslist
== NULL
)
827 printQueueStats(int first
, kstat_t
*cur_set
)
832 /* Filler for async. queue fields */
833 (void) printf(TPS_HDR_FMT
, NO_INFO
);
834 (void) printf(KPS_HDR_FMT
, NO_INFO
);
835 (void) printf(TPS_HDR_FMT
, NO_INFO
);
836 (void) printf(KPS_HDR_FMT
, NO_INFO
);
841 val
= (uint32_t *)kstat_value(cur_set
, RDC_IKSTAT_ASYNC_ITEMS
);
842 (void) printf(TPS_INF_FMT
, *val
);
844 val
= (uint32_t *)kstat_value(cur_set
, RDC_IKSTAT_ASYNC_BLOCKS
);
845 (void) printf(KPS_INF_FMT
, (float)(*val
/ 2));
847 val
= (uint32_t *)kstat_value(cur_set
, RDC_IKSTAT_ASYNC_ITEM_HWM
);
848 (void) printf(TPS_INF_FMT
, *val
);
850 val
= (uint32_t *)kstat_value(cur_set
, RDC_IKSTAT_ASYNC_BLOCK_HWM
);
851 (void) printf(KPS_INF_FMT
, (float)(*val
/ 2));