summaryrefslogtreecommitdiff
path: root/src/pmdas/nfsclient
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/nfsclient
downloadpcp-debian.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/nfsclient')
-rw-r--r--src/pmdas/nfsclient/GNUmakefile49
-rwxr-xr-xsrc/pmdas/nfsclient/Install29
-rwxr-xr-xsrc/pmdas/nfsclient/Remove24
-rw-r--r--src/pmdas/nfsclient/pmdanfsclient.pl1181
4 files changed, 1283 insertions, 0 deletions
diff --git a/src/pmdas/nfsclient/GNUmakefile b/src/pmdas/nfsclient/GNUmakefile
new file mode 100644
index 0000000..cb149f9
--- /dev/null
+++ b/src/pmdas/nfsclient/GNUmakefile
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2011 SGI.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+IAM = nfsclient
+
+PMDADIR = $(PCP_PMDAS_DIR)/$(IAM)
+LSRCFILES = Install Remove pmda$(IAM).pl
+LDIRT = $(MAN_PAGES)
+
+ifneq ($(POD2MAN),)
+MAN_SECTION = 1
+MAN_PAGES = pmda$(IAM).$(MAN_SECTION)
+MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION)
+endif
+
+default: check_domain $(MAN_PAGES)
+
+pmda$(IAM).1: pmda$(IAM).pl
+ $(POD_MAKERULE)
+
+include $(BUILDRULES)
+
+install: default
+ $(INSTALL) -m 755 -d $(PMDADIR)
+ $(INSTALL) -m 755 Install Remove $(PMDADIR)
+ $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl
+ @$(INSTALL_MAN)
+
+default_pcp : default
+
+install_pcp : install
+
+check_domain : ../../pmns/stdpmid
+ $(DOMAIN_PERLRULE)
diff --git a/src/pmdas/nfsclient/Install b/src/pmdas/nfsclient/Install
new file mode 100755
index 0000000..3e3677d
--- /dev/null
+++ b/src/pmdas/nfsclient/Install
@@ -0,0 +1,29 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 SGI.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=nfsclient
+pmda_interface=2
+dso_opt=false
+daemon_opt=false
+perl_opt=true
+socket_opt=false
+
+pmdaSetup
+pmdaInstall
+exit 0
diff --git a/src/pmdas/nfsclient/Remove b/src/pmdas/nfsclient/Remove
new file mode 100755
index 0000000..4a26c90
--- /dev/null
+++ b/src/pmdas/nfsclient/Remove
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Copyright (c) 2011 SGI.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=nfsclient
+
+pmdaSetup
+pmdaRemove
+exit 0
diff --git a/src/pmdas/nfsclient/pmdanfsclient.pl b/src/pmdas/nfsclient/pmdanfsclient.pl
new file mode 100644
index 0000000..380b1cd
--- /dev/null
+++ b/src/pmdas/nfsclient/pmdanfsclient.pl
@@ -0,0 +1,1181 @@
+#
+# Copyright (c) 2011 SGI.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+use strict;
+use warnings;
+use PCP::PMDA;
+
+use vars qw( $pmda @all_ops @common_ops @v3only_ops @v4_ops @v41_ops);
+
+# The instance domain is 0 for all nfs client stats
+our $nfsclient_indom = 0;
+
+# mountstats or other file to use
+our $MOUNTSTATS_PATH = "/proc/self/mountstats";
+
+# Configuration files for overriding the location of mountstats, mostly for testing purposes
+for my $file (pmda_config('PCP_PMDAS_DIR') . '/nfsclient/nfsclient.conf', 'nfsclient.conf') {
+ eval `cat $file` unless ! -f $file;
+}
+
+# Check env variable for mountstats file to use
+if ( defined $ENV{"NFSCLIENT_MOUNTSTATS_PATH"} ) {
+ $MOUNTSTATS_PATH = $ENV{"NFSCLIENT_MOUNTSTATS_PATH"}
+}
+
+our $noval = PM_ERR_APPVERSION;
+
+# The stats hash is keyed on the 'mount' string (the mountpoint string), e.g.
+# '/home'. The value is a hash ref, and that hash contains all of
+# the stats data keyed on pmid_name
+our %h = ();
+
+#
+# Parse /proc/self/mountstats and store the stats, taking one pass through
+# the file.
+#
+sub nfsclient_parse_proc_mountstats {
+ # mountstats output has a section for each mounted filesystems on the
+ # system. Each section starts with a line like: 'device X mounted on
+ # Y with fstype Z'. Some filesystems (like nfs) print additional
+ # output that we need to capture.
+ open STATS, '<', $MOUNTSTATS_PATH ||
+ ( $pmda->err("pmdanfsclient failed to open $MOUNTSTATS_PATH: $!") &&
+ die "Can't open $MOUNTSTATS_PATH: $!\n") ;
+
+ my $export;
+ my $nfsinst;
+ while (<STATS>) {
+ my $line = $_;
+
+ # does this line represent a mount?
+ if ($line =~ /^device (\S*) mounted on (\S*) with fstype.*/) {
+ $export = $1;
+ my $mtpt = $2;
+ $nfsinst = $mtpt;
+
+ # is it an nfs mount?
+ if ($line =~ /.*nfs(4)? statvers=.*/) {
+ $h{$nfsinst} = {}; # {} is an anonymous hash ref
+ $h{$nfsinst}->{'nfsclient.export'} = $export;
+ $h{$nfsinst}->{'nfsclient.mountpoint'} = $mtpt;
+ } else {
+ # the following lines aren't nfs so undef
+ # $nfsinst so that they are ignored below
+ undef $nfsinst;
+ next;
+ }
+ }
+
+ # skip lines that do not belong to nfs mounts
+ if (not defined $nfsinst) {
+ next;
+ }
+
+ # opts
+ if ($line =~ /^\topts:\t(.*)$/) {
+
+ # Need to differentiate between options that are not available based on nfs vers, vs options that are not set and therefore default values ?
+ # Prepopulate based on this constraint
+ # Try to stay away from the "no" names
+ # Guess reasonable defaults based on mapping below
+ #
+ $h{$nfsinst}->{'nfsclient.options.readmode'} = "rw";
+ $h{$nfsinst}->{'nfsclient.options.sync'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.atime'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.diratime'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.vers'} = "3";
+ $h{$nfsinst}->{'nfsclient.options.rsize'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.wsize'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.bsize'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.namlen'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.acregmin'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.acregmax'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.acdirmin'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.acdirmax'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.recovery'} = "hard";
+ $h{$nfsinst}->{'nfsclient.options.posix'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.cto'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.ac'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.lock'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.acl'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.rdirplus'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.sharecache'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.resvport'} = 1;
+ $h{$nfsinst}->{'nfsclient.options.proto'} = "tcp";
+ $h{$nfsinst}->{'nfsclient.options.port'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.timeo'} = 600;
+ $h{$nfsinst}->{'nfsclient.options.retrans'} = 3;
+ $h{$nfsinst}->{'nfsclient.options.sec'} = "sys";
+
+ # NFS 3 only options but can be NULL also
+ $h{$nfsinst}->{'nfsclient.options.mountaddr'} = "unspecified";
+ $h{$nfsinst}->{'nfsclient.options.mountvers'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.mountport'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.mountproto'} = "";
+
+ # NFS 4 only
+ $h{$nfsinst}->{'nfsclient.options.clientaddr'} = "";
+
+ # All
+ $h{$nfsinst}->{'nfsclient.options.fsc'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.migration'} = 0;
+ $h{$nfsinst}->{'nfsclient.options.lookupcache'} = "";
+ $h{$nfsinst}->{'nfsclient.options.local_lock'} = "none";
+
+ $h{$nfsinst}->{'nfsclient.options.string'} = $1; # Keep this???
+
+ my @mountopts = split(',', $1);
+
+ foreach my $mountopt (@mountopts) {
+ chomp $mountopt;
+ # Is there a better way to do this ??
+ # Started with a regex for the full line but got ugly
+ #
+ if( $mountopt =~ /^(ro|rw)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.readmode'} = "$1";
+ } elsif ( $mountopt =~ /^(sync)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.sync'} = 1;
+ } elsif ( $mountopt =~ /^(noatime)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.atime'} = 0;
+ } elsif ( $mountopt =~ /^(nodirtime)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.diratime'} = 0;
+ } elsif ( $mountopt =~ /^vers=([2-4](\.[0-9])?)/ ){
+ $h{$nfsinst}->{'nfsclient.options.vers'} = "$1";
+ } elsif ( $mountopt =~ /^rsize=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.rsize'} = $1;
+ } elsif ( $mountopt =~ /^wsize=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.wsize'} = $1;
+ } elsif ( $mountopt =~ /^bsize=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.bsize'} = $1;
+ } elsif ( $mountopt =~ /^namlen=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.namlen'} = $1;
+ } elsif ( $mountopt =~ /^acregmin=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.acregmin'} = $1;
+ } elsif ( $mountopt =~ /^acregmax=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.acregmax'} = $1;
+ } elsif ( $mountopt =~ /^acdirmin=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.acdirmin'} = $1;
+ } elsif ( $mountopt =~ /^acdirmax=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.acdirmax'} = $1;
+ } elsif ( $mountopt =~ /^(soft|hard)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.recovery'} = "$1";
+ } elsif ( $mountopt =~ /^(posix)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.posix'} = 1;
+ } elsif ( $mountopt =~ /^(nocto)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.cto'} = 0;
+ } elsif ( $mountopt =~ /^(noac)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.ac'} = 0;
+ } elsif ( $mountopt =~ /^(nolock)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.lock'} = 0;
+ } elsif ( $mountopt =~ /^(noacl)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.acl'} = 0;
+ } elsif ( $mountopt =~ /^(nordirplus)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.rdirplus'} = 0;
+ } elsif ( $mountopt =~ /^(nosharecache)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.sharecache'} = 0;
+ } elsif ( $mountopt =~ /^(noresvport)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.resvport'} = 0;
+ } elsif ( $mountopt =~ /^proto=(tcp|udp|rdma)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.proto'} = "$1";
+ } elsif ( $mountopt =~ /^port=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.port'} = $1;
+ } elsif ( $mountopt =~ /^timeo=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.timeo'} = $1;
+ } elsif ( $mountopt =~ /^retrans=(\d+)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.retrans'} = $1;
+ } elsif ( $mountopt =~ /^sec=(null|sys|krb5|krb5i|krb5p|lkey|lkeyi|lkeyp|spkm|spkmi|spkmp|unknown)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.sec'} = "$1";
+ } elsif ( $mountopt =~ /^mountaddr=(.*)$/ ){ # NFS3 only
+ $h{$nfsinst}->{'nfsclient.options.mountaddr'} = "$1";
+ } elsif ( $mountopt =~ /^mountvers=(\d+)$/ ){ # NFS3 only
+ $h{$nfsinst}->{'nfsclient.options.mountvers'} = $1;
+ } elsif ( $mountopt =~ /^mountport=(\d+)$/ ){ # NFS3 only
+ $h{$nfsinst}->{'nfsclient.options.mountport'} = $1;
+ } elsif ( $mountopt =~ /^mountproto=(udp|tcp|auto|udp6|tcp6)$/ ){ # NFS3 only
+ $h{$nfsinst}->{'nfsclient.options.mountproto'} = "$1"
+ } elsif ( $mountopt =~ /^clientaddr=(.*)$/ ){ # NFS4 only
+ $h{$nfsinst}->{'nfsclient.options.clientaddr'} = "$1";
+ } elsif ( $mountopt =~ /^(fsc)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.fsc'} = 1;
+ } elsif ( $mountopt =~ /^(migration)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.migration'} = 1;
+ } elsif ( $mountopt =~ /^lookupcache=(none|pos)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.lookupcache'} = "$1";
+ } elsif ( $mountopt =~ /^local_lock=(none|all|flock|posix)$/ ){
+ $h{$nfsinst}->{'nfsclient.options.local_lock'} = "$1";
+ }
+ }
+ }
+ #age
+ if ($line =~ /^\tage:\t(.*)$/) {
+ $h{$nfsinst}->{'nfsclient.age'} = $1;
+ }
+ #caps
+ if ($line =~ /^\tcaps:\t(.*)$/) {
+ $h{$nfsinst}->{'nfsclient.capabilities'} = $1;
+ }
+ #sec
+ if ($line =~ /^\tsec:\t(.*)$/) {
+ $h{$nfsinst}->{'nfsclient.security'} = $1;
+ }
+ # events
+ if ($line =~ /^\tevents:\t(.*)$/) {
+ ($h{$nfsinst}->{'nfsclient.events.inoderevalidate'},
+ $h{$nfsinst}->{'nfsclient.events.dentryrevalidate'},
+ $h{$nfsinst}->{'nfsclient.events.datainvalidate'},
+ $h{$nfsinst}->{'nfsclient.events.attrinvalidate'},
+ $h{$nfsinst}->{'nfsclient.events.vfsopen'},
+ $h{$nfsinst}->{'nfsclient.events.vfslookup'},
+ $h{$nfsinst}->{'nfsclient.events.vfsaccess'},
+ $h{$nfsinst}->{'nfsclient.events.vfsupdatepage'},
+ $h{$nfsinst}->{'nfsclient.events.vfsreadpage'},
+ $h{$nfsinst}->{'nfsclient.events.vfsreadpages'},
+ $h{$nfsinst}->{'nfsclient.events.vfswritepage'},
+ $h{$nfsinst}->{'nfsclient.events.vfswritepages'},
+ $h{$nfsinst}->{'nfsclient.events.vfsgetdents'},
+ $h{$nfsinst}->{'nfsclient.events.vfssetattr'},
+ $h{$nfsinst}->{'nfsclient.events.vfsflush'},
+ $h{$nfsinst}->{'nfsclient.events.vfsfsync'},
+ $h{$nfsinst}->{'nfsclient.events.vfslock'},
+ $h{$nfsinst}->{'nfsclient.events.vfsrelease'},
+ $h{$nfsinst}->{'nfsclient.events.congestionwait'},
+ $h{$nfsinst}->{'nfsclient.events.setattrtrunc'},
+ $h{$nfsinst}->{'nfsclient.events.extendwrite'},
+ $h{$nfsinst}->{'nfsclient.events.sillyrename'},
+ $h{$nfsinst}->{'nfsclient.events.shortread'},
+ $h{$nfsinst}->{'nfsclient.events.shortwrite'},
+ $h{$nfsinst}->{'nfsclient.events.delay'}) =
+ split(/ /, $1);
+ }
+
+ # bytes
+ if ($line =~ /\tbytes:\t(.*)$/) {
+ ($h{$nfsinst}->{'nfsclient.bytes.read.normal'},
+ $h{$nfsinst}->{'nfsclient.bytes.write.normal'},
+ $h{$nfsinst}->{'nfsclient.bytes.read.direct'},
+ $h{$nfsinst}->{'nfsclient.bytes.write.direct'},
+ $h{$nfsinst}->{'nfsclient.bytes.read.server'},
+ $h{$nfsinst}->{'nfsclient.bytes.write.server'},
+ $h{$nfsinst}->{'nfsclient.pages.read'},
+ $h{$nfsinst}->{'nfsclient.pages.write'}) =
+ split(/ /, $1);
+ }
+
+ # xprt
+ if ($line =~ /\txprt:\t(.*)$/) {
+ my @stats = split(/ /, $1);
+ my $xprt_prot = shift(@stats);
+
+ if( $xprt_prot eq "tcp"){
+
+ ($h{$nfsinst}->{'nfsclient.xprt.srcport'},
+ $h{$nfsinst}->{'nfsclient.xprt.bind_count'},
+ $h{$nfsinst}->{'nfsclient.xprt.connect_count'},
+ $h{$nfsinst}->{'nfsclient.xprt.connect_time'},
+ $h{$nfsinst}->{'nfsclient.xprt.idle_time'},
+ $h{$nfsinst}->{'nfsclient.xprt.sends'},
+ $h{$nfsinst}->{'nfsclient.xprt.recvs'},
+ $h{$nfsinst}->{'nfsclient.xprt.bad_xids'},
+ $h{$nfsinst}->{'nfsclient.xprt.req_u'},
+ $h{$nfsinst}->{'nfsclient.xprt.bklog_u'}) =
+ @stats;
+
+ # Unused RDMA Elements
+ $h{$nfsinst}->{'nfsclient.xprt.read_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.write_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.reply_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_req'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_rep'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.pullup'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.fixup'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.hardway'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.failed_marshal'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.bad_reply'} = 0;
+
+ } elsif ( $xprt_prot eq "udp"){
+ ($h{$nfsinst}->{'nfsclient.xprt.srcport'},
+ $h{$nfsinst}->{'nfsclient.xprt.bind_count'},
+ $h{$nfsinst}->{'nfsclient.xprt.sends'},
+ $h{$nfsinst}->{'nfsclient.xprt.recvs'},
+ $h{$nfsinst}->{'nfsclient.xprt.bad_xids'},
+ $h{$nfsinst}->{'nfsclient.xprt.req_u'},
+ $h{$nfsinst}->{'nfsclient.xprt.bklog_u'}) =
+ @stats;
+
+ # Unused TCP elements
+ $h{$nfsinst}->{'nfsclient.xprt.connect_count'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.connect_time'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.idle_time'} = 0;
+
+ # Unused RDMA Elements
+ $h{$nfsinst}->{'nfsclient.xprt.read_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.write_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.reply_chunks'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_req'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_rep'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.pullup'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.fixup'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.hardway'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.failed_marshal'} = 0;
+ $h{$nfsinst}->{'nfsclient.xprt.bad_reply'} = 0;
+
+ } elsif ( $xprt_prot eq "rdma"){
+ ($h{$nfsinst}->{'nfsclient.xprt.srcport'},
+ $h{$nfsinst}->{'nfsclient.xprt.bind_count'},
+ $h{$nfsinst}->{'nfsclient.xprt.connect_count'},
+ $h{$nfsinst}->{'nfsclient.xprt.connect_time'},
+ $h{$nfsinst}->{'nfsclient.xprt.idle_time'},
+ $h{$nfsinst}->{'nfsclient.xprt.sends'},
+ $h{$nfsinst}->{'nfsclient.xprt.recvs'},
+ $h{$nfsinst}->{'nfsclient.xprt.bad_xids'},
+ $h{$nfsinst}->{'nfsclient.xprt.req_u'},
+ $h{$nfsinst}->{'nfsclient.xprt.bklog_u'},
+ $h{$nfsinst}->{'nfsclient.xprt.read_chunks'},
+ $h{$nfsinst}->{'nfsclient.xprt.write_chunks'},
+ $h{$nfsinst}->{'nfsclient.xprt.reply_chunks'},
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_req'},
+ $h{$nfsinst}->{'nfsclient.xprt.total_rdma_rep'},
+ $h{$nfsinst}->{'nfsclient.xprt.pullup'},
+ $h{$nfsinst}->{'nfsclient.xprt.fixup'},
+ $h{$nfsinst}->{'nfsclient.xprt.hardway'},
+ $h{$nfsinst}->{'nfsclient.xprt.failed_marshal'},
+ $h{$nfsinst}->{'nfsclient.xprt.bad_reply'}) =
+ @stats;
+
+ } else {
+ next;
+ }
+ }
+
+ # per-op statistics
+ # pre-populate all possible ops from v3, v4, v4.1 and set to noval
+ # ops defined below
+ for my $opname (@all_ops) {
+ $h{$nfsinst}->{"nfsclient.ops.$opname.ops"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.ntrans"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.timeouts"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.bytes_sent"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.bytes_recv"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.queue"} = $noval;
+ $h{$nfsinst}->{"nfsclient.ops.$opname.rtt"} = $noval;
+ $h{$nfsinst}->{"nfsclinet.ops.$opname.execute"} = $noval;
+ }
+
+ if ($line =~ /\tper-op statistics$/) {
+ # We'll do these a bit differently since they are not
+ # all on the same line. Just loop until we don't match
+ # anymore.
+ # v4 ops can have underscore
+ while (<STATS> =~
+ /^\s*([A-Z_]*): (\d*) (\d*) (\d*) (\d*) (\d*) (\d*) (\d*) (\d*)$/) {
+ my $op_name = "\L$1";
+ ($h{$nfsinst}->{"nfsclient.ops.$op_name.ops"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.ntrans"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.timeouts"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.bytes_sent"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.bytes_recv"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.queue"},
+ $h{$nfsinst}->{"nfsclient.ops.$op_name.rtt"},
+ $h{$nfsinst}->{"nfsclinet.ops.$op_name.execute"}) =
+ ($2, $3, $4, $5, $6, $7, $8, $9);
+ }
+ }
+ }
+
+ close STATS;
+}
+
+#
+# fetch is called once by pcp for each refresh and then the fetch callback is
+# called to query each statistic individually
+#
+sub nfsclient_fetch {
+ nfsclient_parse_proc_mountstats();
+
+ our $pmda->replace_indom($nfsclient_indom, \%h);
+}
+
+sub nfsclient_fetch_callback {
+ my ($cluster, $item, $inst) = @_;
+
+ my $lookup = pmda_inst_lookup($nfsclient_indom, $inst);
+ return (PM_ERR_INST, 0) unless defined($lookup);
+
+ my $pmid_name = pmda_pmid_name($cluster, $item)
+ or die "Unknown metric name: cluster $cluster item $item\n";
+
+ return ($lookup->{$pmid_name}, 1);
+
+}
+
+# the PCP::PMDA->new line is parsed by the check_domain rule of the PMDA build
+# process, so there are special requirements: no comments, the domain has to
+# be a bare number.
+#
+our $pmda = PCP::PMDA->new('nfsclient', 62);
+
+# metrics go here, with full descriptions
+
+# general - cluster 0
+$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.export',
+ 'Export',
+ '');
+$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.mountpoint',
+ 'Mount Point',
+ '');
+
+# opts - cluster 1
+#
+# Options in order:
+# NULL is not present
+# from super.c in nfs_show_mount_options
+#
+# ro | rw
+# sync | NULL
+# noatime | NULL
+# nodiratime | NULL
+# vers=([2-4](\.[0-9])?)
+# rsize=%u
+# wsize=%u
+# bsize=%u | NULL
+# namlen=%u
+# acregmin=%u | NULL
+# acregmax=%u | NULL
+# acdirmin=%u | NULL
+# acdirmax=%u | NULL
+# soft | hard
+# posix | NULL
+# nocto | NULL
+# noac | NULL
+# nolock | NULL
+# noacl | NULL
+# nordirplus | NULL
+# nosharecache | NULL
+# noresvport | NULL
+# proto=(tcp|udp|rdma)
+# port=%u | NULL
+# timeo=%lu
+# retrans=%u
+# sec=(null|sys|krb5|krb5i|krb5p|lkey|lkeyi|lkeyp|spkm|spkmi|spkmp|unknown) # null and unknown are those exact literal strings
+
+# NFS 3 only
+# Below block may not exist at all if NFS_MOUNT_LEGACY_INTERFACE
+# mountaddr="ip4addr|ip6addr|unspecified"
+# mountvers=%u | NULL
+# mountport=%u | NULL
+# mountproto=(udp|tcp|auto|udp6|tcp6|NULL) # NULL if showdefaults is false
+
+# NFS 4 Only
+# clientaddr=(ip4address|ip6address)
+
+# fsc | NULL
+# migration | NULL
+# lookupcache=(none|pos) | NULL
+# local_lock=(none|all|flock|posix)
+
+# TODO
+# deprecated after 2.6.25, do we care about these ?
+# intr|nointr
+
+$pmda->add_metric(pmda_pmid(1,1), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.string',
+ 'Full Options String',
+ '');
+$pmda->add_metric(pmda_pmid(1,2), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.readmode',
+ 'rw or ro mount mode',
+ '');
+$pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.sync',
+ 'boolean sync mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,4), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.atime',
+ 'boolean atime mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,5), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.diratime',
+ 'boolean diratime mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,6), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.vers',
+ 'nfs version',
+ '');
+$pmda->add_metric(pmda_pmid(1,7), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.rsize',
+ 'rsize mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,8), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.wsize',
+ 'wsize mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,9), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.bsize',
+ 'bsize mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,10), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.namlen',
+ 'namlen mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,11), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.acregmin',
+ 'acregmin mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,12), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.acregmax',
+ 'acregmax mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,13), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.acdirmin',
+ 'acdirmin mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,14), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.acdirmax',
+ 'acdirmax mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,15), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.recovery',
+ 'hard or soft recovery behavior',
+ '');
+$pmda->add_metric(pmda_pmid(1,16), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.posix',
+ 'boolean posix mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,17), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.cto',
+ 'boolean cto mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,18), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.ac',
+ 'boolean ac mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,19), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.lock',
+ 'boolean lock mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,20), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.acl',
+ 'boolean acl mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,21), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.rdirplus',
+ 'boolean rdirplus mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,22), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.sharecache',
+ 'boolean sharecache mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,23), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.resvport',
+ 'boolean resvport mount option used',
+ '');
+$pmda->add_metric(pmda_pmid(1,24), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.proto',
+ 'nfs protocol: udp|tcp|rdma',
+ '');
+$pmda->add_metric(pmda_pmid(1,25), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.port',
+ 'port mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,26), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.timeo',
+ 'timeo mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,27), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.retrans',
+ 'retrans mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,28), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.sec',
+ 'sec mount parameter',
+ '');
+# NFS3 only
+$pmda->add_metric(pmda_pmid(1,29), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.mountaddr',
+ 'mountaddr mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,30), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.mountvers',
+ 'mountvers mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,31), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.mountport',
+ 'mountport mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,32), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.mountproto',
+ 'mountproto mount parameter',
+ '');
+# NFS4 only
+$pmda->add_metric(pmda_pmid(1,33), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.clientaddr',
+ 'clientaddr mount parameter',
+ '');
+# All
+$pmda->add_metric(pmda_pmid(1,34), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.fsc',
+ 'fsc mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,35), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.migration',
+ 'migration mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,36), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.lookupcache',
+ 'lookupcache mount parameter',
+ '');
+$pmda->add_metric(pmda_pmid(1,37), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.options.local_lock',
+ 'local_lock mount parameter',
+ '');
+
+# age - cluster 2
+$pmda->add_metric(pmda_pmid(2,1), pmda_ulong, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0),
+ 'nfsclient.age',
+ 'Age in Seconds',
+ '');
+# caps - cluster 3 - Any use in parsing this ?
+$pmda->add_metric(pmda_pmid(3,1), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.capabilities',
+ 'Capabilities',
+ '');
+
+# sec - cluster 4 - Any use in parsing this ?
+$pmda->add_metric(pmda_pmid(4,1), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.security',
+ 'Security Flavor',
+ '');
+
+# events - cluster 5
+$pmda->add_metric(pmda_pmid(5,1), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.inoderevalidate',
+ 'NFSIOS_INODEREVALIDATE',
+'incremented in __nfs_revalidate_inode whenever an inode is revalidated');
+
+$pmda->add_metric(pmda_pmid(5,2), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.dentryrevalidate',
+ 'NFSIOS_DENTRYREVALIDATE',
+'incremented in nfs_lookup_revalidate whenever a dentry is revalidated');
+
+$pmda->add_metric(pmda_pmid(5,3), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.datainvalidate',
+ 'NFSIOS_DATAINVALIDATE',
+'incremented in nfs_invalidate_mapping_nolock when data cache for an inode ' .
+'is invalidated');
+
+$pmda->add_metric(pmda_pmid(5,4), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.attrinvalidate',
+ 'NFSIOS_ATTRINVALIDATE',
+'incremented in nfs_zap_caches_locked and nfs_update_inode when an the ' .
+'attribute cache for an inode has been invalidated');
+
+$pmda->add_metric(pmda_pmid(5,5), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsopen',
+ 'NFSIOS_VFSOPEN',
+'incremented in nfs_file_open and nfs_opendir whenever a file or directory ' .
+'is opened');
+
+$pmda->add_metric(pmda_pmid(5,6), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfslookup',
+ 'NFSIOS_VFSLOOKUP',
+'incremented in nfs_lookup on every lookup');
+
+$pmda->add_metric(pmda_pmid(5,7), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsaccess',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,8), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsupdatepage',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,9), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsreadpage',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,10), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsreadpages',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,11), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfswritepage',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,12), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfswritepages',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,13), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsgetdents',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,14), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfssetattr',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,15), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsflush',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,16), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsfsync',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,17), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfslock',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,18), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.vfsrelease',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,19), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.congestionwait',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,20), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.setattrtrunc',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,21), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.extendwrite',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,22), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.sillyrename',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,23), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.shortread',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,24), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.shortwrite',
+ '', '');
+
+$pmda->add_metric(pmda_pmid(5,25), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.events.delay',
+ '', '');
+
+# bytes - cluster 6
+$pmda->add_metric(pmda_pmid(6,1), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.read.normal',
+ 'NFSIOS_NORMALREADBYTES',
+'the number of bytes read by applications via the read system call interface');
+
+$pmda->add_metric(pmda_pmid(6,2), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.write.normal',
+ 'NFSIOS_NORMALWRITTENBYTES',
+'the number of bytes written by applications via the write system call ' .
+'interface');
+
+$pmda->add_metric(pmda_pmid(6,3), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.read.direct',
+ 'NFSIOS_DIRECTREADBYTES',
+'the number of bytes read by applications from files opened with the ' .
+'O_DIRECT flag');
+
+$pmda->add_metric(pmda_pmid(6,4), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.write.direct',
+ 'NFSIOS_DIRECTWRITTENBYTES',
+'the number of bytes written by applications to files opened with the ' .
+'O_DIRECT flag');
+
+$pmda->add_metric(pmda_pmid(6,5), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.read.server',
+ 'NFSIOS_SERVERREADBYTES',
+'the number of bytes read from the nfs server by the nfs client via nfs ' .
+'read requests');
+
+$pmda->add_metric(pmda_pmid(6,6), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'nfsclient.bytes.write.server',
+ 'NFSIOS_SERVERWRITTENBYTES',
+'the number of bytes written to the nfs server by the nfs client via nfs ' .
+'write requests');
+
+$pmda->add_metric(pmda_pmid(6,7), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.pages.read',
+ 'NFSIOS_READPAGES',
+'the number of pages read via nfs_readpage or nfs_readpages');
+
+$pmda->add_metric(pmda_pmid(6,8), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.pages.write',
+ 'NFSIOS_WRITEPAGES',
+'the number of pages written via nfs_writepage or nfs_writepages');
+
+# xprt - cluster 7
+#
+# We have three possible transports: udp, tcp, rdma.
+# Fill in 0 for ones that dont apply. Types for RDMA from net/sunrpc/xprtrdma/transport.c : xprt_rdma_print_stats
+#
+$pmda->add_metric(pmda_pmid(7,1), PM_TYPE_STRING, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'nfsclient.xprt.srcport',
+ 'tcp source port',
+'source port on the client');
+
+$pmda->add_metric(pmda_pmid(7,2), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.bind_count',
+ 'count of rpcbind get_port calls',
+'incremented in rpcb_getport_async: \"obtain the port for a given RPC ' .
+'service on a given host\"');
+
+$pmda->add_metric(pmda_pmid(7,3), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.connect_count',
+ 'count of tcp connects',
+'incremented in xs_tcp_finish_connecting and xprt_connect_status. This is ' .
+'a count of the number of tcp (re)connects (only of which is active at a ' .
+'time) for this mount.');
+
+$pmda->add_metric(pmda_pmid(7,4), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.connect_time',
+ 'jiffies waiting for connect',
+'Summed in xprt_connect_status, it is stored and printed in jiffies. This ' .
+'the sum of all connection attempts: how long was spent waiting to connect.');
+
+$pmda->add_metric(pmda_pmid(7,5), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0),
+ 'nfsclient.xprt.idle_time',
+ 'transport idle time',
+'How long has it been since the transport has been used. Stored and ' .
+'calculated in jiffies and printed in seconds.');
+
+$pmda->add_metric(pmda_pmid(7,6), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.sends',
+ 'count of tcp transmits',
+'Incremented in xprt_transmit upon transmit completion of each rpc.');
+
+$pmda->add_metric(pmda_pmid(7,7), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.recvs',
+ 'count of tcp receives',
+'Incremented in xprt_complete_rqst when reply processing is complete.');
+
+$pmda->add_metric(pmda_pmid(7,8), PM_TYPE_U32, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.bad_xids',
+ 'count of bad transaction identifiers',
+'When processing an rpc reply it is necessary to look up the original ' .
+'rpc_rqst using xprt_lookup_rqst. If the rpc_rqst that prompted the reply ' .
+'cannot be found on the transport bad_xids is incremented.');
+
+$pmda->add_metric(pmda_pmid(7,9), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.req_u',
+ 'average requests on the wire',
+'FIXME: The comment in struct stat says: \"average requests on the wire\", ' .
+'but the actual calculation in xprt_transmit is: ' .
+'xprt->stat.req_u += xprt->stat.sends - xprt->stat.recvs;\n' .
+'This stat may be broken.');
+
+$pmda->add_metric(pmda_pmid(7,10), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.backlog_u',
+ 'backlog queue utilization',
+'FIXME: here is the calculation in xprt_transmit: ' .
+'xprt->stat.bklog_u += xprt->backlog.qlen;\n ' .
+'qlen is incremented in __rpc_add_wait_queue and decremented in ' .
+'__rpc_remove_wait_queue.');
+
+$pmda->add_metric(pmda_pmid(7,11), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.read_chunks',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,12), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.write_chunks',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,13), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.reply_chunks',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,14), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.total_rdma_req',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,15), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.total_rdma_rep',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,16), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.pullup',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,17), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.fixup',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,18), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.hardway',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,19), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.failed_marshal',
+ '',
+ '');
+
+$pmda->add_metric(pmda_pmid(7,20), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'nfsclient.xprt.bad_reply',
+ '',
+ '');
+
+# ops - cluster 8
+#
+# Different versions have different ops. We just List them all and fill in
+# only what is appropriate for this version. Non matching ones will return noval
+# from above.
+
+# ops available in v3, v4 and v4.1
+#
+our @common_ops = ('null', 'getattr', 'setattr', 'lookup', 'access', 'readlink',
+ 'read', 'write', 'create', 'symlink', 'remove',
+ 'rename', 'link', 'readdir',
+ 'fsinfo', 'pathconf', 'commit');
+
+# ops only in v3
+#
+our @v3only_ops = ('fsstat', 'mkdir', 'mknod', 'readdirplus', 'rmdir');
+
+# ops ADDED in v4, some v3 ops are invalid : fsstat, mkdir, mknod, readdirplus, rmdir
+#
+our @v4_ops = ('close', 'create_session', 'delegreturn', 'destroy_session', 'exchange_id',
+ 'fs_locations', 'getacl', 'getdeviceinfo', 'get_lease_time', 'layoutcommit',
+ 'layoutget', 'layoutreturn', 'lock', 'lockt', 'locku', 'lookup_root',
+ 'open', 'open_confirm', 'open_downgrade', 'open_noattr', 'reclaim_complete',
+ 'release_lockowner', 'renew', 'secinfo', 'sequence', 'server_caps', 'setacl',
+ 'setclientid', 'setclientid_confirm', 'statfs');
+
+# ops ADDED in v4.1, same v3 ops removed as in v4, all v4 ops should exist
+#
+our @v41_ops = ('bind_conn_to_session', 'destroy_clientid', 'free_stateid', 'getdevicelist',
+ 'secinfo_no_name', 'test_stateid');
+
+our @all_ops = ( @common_ops, @v3only_ops, @v4_ops, @v41_ops );
+
+my $item = 1;
+for my $op_name (@all_ops) {
+ $pmda->add_metric(pmda_pmid(8, $item++), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ "nfsclient.ops.$op_name.ops",
+ 'count of operations',
+'rpc count for this op, only bumped in rpc_count_iostats');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ "nfsclient.ops.$op_name.ntrans",
+ 'count of transmissions',
+'there can be more than one transmission per rpc');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), pmda_ulong, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ "nfsclient.ops.$op_name.timeouts",
+ 'count of major timeouts',
+'XXX fill me in');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ "nfsclient.ops.$op_name.bytes_sent",
+ 'count of bytes out',
+'How many bytes are sent for this procedure type. This indicates how much ' .
+'load this procedure is putting on the network. It includes the RPC and ULP' .
+'headers, and the request payload');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ "nfsclient.ops.$op_name.bytes_recv",
+ 'count of bytes in',
+'How many bytes are received for this procedure type. This indicates how ' .
+'much load this procedure is putting on the network. It includes RPC and ' .
+'ULP headers, and the request payload');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0),
+ "nfsclient.ops.$op_name.queue",
+ 'milliseconds queued for transmit',
+'The length of time an RPC request waits in queue before transmission in ' .
+' milliseconds.');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0),
+ "nfsclient.ops.$op_name.rtt",
+ 'milliseconds for rpc round trip time',
+'The network + server latency of the request in milliseconds.');
+
+ $pmda->add_metric(pmda_pmid(8, $item++), PM_TYPE_U64, $nfsclient_indom,
+ PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0),
+ "nfsclient.ops.$op_name.execute",
+ 'milliseconds for rpc execution',
+'The total time the request spent from init to release in milliseconds.');
+}
+
+&nfsclient_parse_proc_mountstats;
+
+$nfsclient_indom = $pmda->add_indom($nfsclient_indom, {}, '', '');
+
+$pmda->set_fetch(\&nfsclient_fetch);
+$pmda->set_fetch_callback(\&nfsclient_fetch_callback);
+
+$pmda->run;
+
+=pod
+
+=head1 NAME
+
+pmdanfsclient - nfs client statistics performance metrics domain agent (PMDA)
+
+=head1 DESCRIPTION
+
+B<pmdanfsclient> is a Performance Metrics Domain Agent (PMDA) which exports
+metric values from the /proc/self/mountstats interface to provide information
+on nfs mounts.
+
+=head1 INSTALLATION
+
+If you want access to the names and values for the nfsclient performance
+metrics, do the following as root:
+
+ # cd $PCP_PMDAS_DIR/nfsclient
+ # ./Install
+
+If you want to undo the installation, do the following as root:
+
+ # cd $PCP_PMDAS_DIR/nfsclient
+ # ./Remove
+
+B<pmdanfsclient> is launched by pmcd(1) and should never be executed
+directly. The Install and Remove scripts notify pmcd(1) when
+the agent is installed or removed.
+
+=head1 FILES
+
+=over
+
+=item $PCP_PMDAS_DIR/nfsclient/Install
+
+installation script for the B<pmdanfsclient> agent
+
+=item $PCP_PMDAS_DIR/nfsclient/Remove
+
+undo installation script for the B<pmdanfsclient> agent
+
+=item $PCP_LOG_DIR/pmcd/nfsclient.log
+
+default log file for error messages from B<pmdanfsclient>
+
+=back
+
+=head1 SEE ALSO
+
+pmcd(1) and nfs(5) and mountstats(8).
+