Repository: prometheus/procfs
Pull request #165 (2019-05-28 16:51:07)

Fix overflow in mounstats
Don't use time.Duration for mountstats timing data. These values can be
large uint64 milliseconds values and easily overflow time.Duration
(in64 nanoseconds). Return the raw time in milliseconds.

Signed-off-by: Ben Kochie <superq@gmail.com>

SuperQ: Yes, the example data came from a RHEL 7.3 system, 3.10 kernel.

Patch:
diff --git a/fixtures.ttar b/fixtures.ttar
index 3ad2ce0..951d909 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -75,7 +75,7 @@ Max realtime timeout      unlimited            unlimited            us
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/proc/26231/mountstats
-Lines: 19
+Lines: 20
 device rootfs mounted on / with fstype rootfs
 device sysfs mounted on /sys with fstype sysfs
 device proc mounted on /proc with fstype proc
@@ -94,6 +94,7 @@ device 192.168.1.1:/srv/test mounted on /mnt/nfs/test with fstype nfs4 statvers=
 	        NULL: 0 0 0 0 0 0 0 0
 	        READ: 1298 1298 0 207680 1210292152 6 79386 79407
 	       WRITE: 0 0 0 0 0 0 0 0
+	      ACCESS: 2927395007 2927394995 0 526931094212 362996810236 18446743919241604546 1667369447 1953587717
 
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -120,6 +121,11 @@ SymlinkTo: net:[4026531993]
 Path: fixtures/proc/26231/root
 SymlinkTo: /
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/26231/stat
+Lines: 1
+26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/proc/26231/status
 Lines: 53
 
@@ -177,11 +183,6 @@ voluntary_ctxt_switches:	4742839
 nonvoluntary_ctxt_switches:	1727500
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Path: fixtures/proc/26231/stat
-Lines: 1
-26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0
-Mode: 644
-# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/26232
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/mountstats.go b/mountstats.go
index 7e8f044..35b2ef3 100644
--- a/mountstats.go
+++ b/mountstats.go
@@ -181,11 +181,11 @@ type NFSOperationStats struct {
 	// Number of bytes received for this operation, including RPC headers and payload.
 	BytesReceived uint64
 	// Duration all requests spent queued for transmission before they were sent.
-	CumulativeQueueTime time.Duration
+	CumulativeQueueMilliseconds uint64
 	// Duration it took to get a reply back after the request was transmitted.
-	CumulativeTotalResponseTime time.Duration
+	CumulativeTotalResponseMilliseconds uint64
 	// Duration from when a request was enqueued to when it was completely handled.
-	CumulativeTotalRequestTime time.Duration
+	CumulativeTotalRequestMilliseconds uint64
 }
 
 // A NFSTransportStats contains statistics for the NFS mount RPC requests and
@@ -204,7 +204,7 @@ type NFSTransportStats struct {
 	// spent waiting for connections to the server to be established.
 	ConnectIdleTime uint64
 	// Duration since the NFS mount last saw any RPC traffic.
-	IdleTime time.Duration
+	IdleTimeSeconds uint64
 	// Number of RPC requests for this mount sent to the NFS server.
 	Sends uint64
 	// Number of RPC responses for this mount received from the NFS server.
@@ -524,15 +524,15 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
 		}
 
 		ops = append(ops, NFSOperationStats{
-			Operation:                   strings.TrimSuffix(ss[0], ":"),
-			Requests:                    ns[0],
-			Transmissions:               ns[1],
-			MajorTimeouts:               ns[2],
-			BytesSent:                   ns[3],
-			BytesReceived:               ns[4],
-			CumulativeQueueTime:         time.Duration(ns[5]) * time.Millisecond,
-			CumulativeTotalResponseTime: time.Duration(ns[6]) * time.Millisecond,
-			CumulativeTotalRequestTime:  time.Duration(ns[7]) * time.Millisecond,
+			Operation:                           strings.TrimSuffix(ss[0], ":"),
+			Requests:                            ns[0],
+			Transmissions:                       ns[1],
+			MajorTimeouts:                       ns[2],
+			BytesSent:                           ns[3],
+			BytesReceived:                       ns[4],
+			CumulativeQueueMilliseconds:         ns[5],
+			CumulativeTotalResponseMilliseconds: ns[6],
+			CumulativeTotalRequestMilliseconds:  ns[7],
 		})
 	}
 
@@ -608,7 +608,7 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats
 		Bind:                     ns[1],
 		Connect:                  ns[2],
 		ConnectIdleTime:          ns[3],
-		IdleTime:                 time.Duration(ns[4]) * time.Second,
+		IdleTimeSeconds:          ns[4],
 		Sends:                    ns[5],
 		Receives:                 ns[6],
 		BadTransactionIDs:        ns[7],


Test patch:
diff --git a/mountstats_test.go b/mountstats_test.go
index b25ca8f..e41fcf3 100644
--- a/mountstats_test.go
+++ b/mountstats_test.go
@@ -122,7 +122,7 @@ func TestMountStats(t *testing.T) {
 						Bind:                     2,
 						Connect:                  3,
 						ConnectIdleTime:          4,
-						IdleTime:                 5 * time.Second,
+						IdleTimeSeconds:          5,
 						Sends:                    6,
 						Receives:                 7,
 						BadTransactionIDs:        8,
@@ -150,7 +150,7 @@ func TestMountStats(t *testing.T) {
 						Bind:                     2,
 						Connect:                  0,
 						ConnectIdleTime:          0,
-						IdleTime:                 0,
+						IdleTimeSeconds:          0,
 						Sends:                    3,
 						Receives:                 4,
 						BadTransactionIDs:        5,
@@ -178,7 +178,7 @@ func TestMountStats(t *testing.T) {
 						Bind:                     2,
 						Connect:                  3,
 						ConnectIdleTime:          4,
-						IdleTime:                 5 * time.Second,
+						IdleTimeSeconds:          5,
 						Sends:                    6,
 						Receives:                 7,
 						BadTransactionIDs:        8,
@@ -206,7 +206,7 @@ func TestMountStats(t *testing.T) {
 						Bind:                     2,
 						Connect:                  0, // these three are not
 						ConnectIdleTime:          0, // present for UDP
-						IdleTime:                 0, //
+						IdleTimeSeconds:          0, //
 						Sends:                    3,
 						Receives:                 4,
 						BadTransactionIDs:        5,
@@ -311,24 +311,34 @@ func TestMountStats(t *testing.T) {
 								Operation: "NULL",
 							},
 							{
-								Operation:                   "READ",
-								Requests:                    1298,
-								Transmissions:               1298,
-								BytesSent:                   207680,
-								BytesReceived:               1210292152,
-								CumulativeQueueTime:         6 * time.Millisecond,
-								CumulativeTotalResponseTime: 79386 * time.Millisecond,
-								CumulativeTotalRequestTime:  79407 * time.Millisecond,
+								Operation:                           "READ",
+								Requests:                            1298,
+								Transmissions:                       1298,
+								BytesSent:                           207680,
+								BytesReceived:                       1210292152,
+								CumulativeQueueMilliseconds:         6,
+								CumulativeTotalResponseMilliseconds: 79386,
+								CumulativeTotalRequestMilliseconds:  79407,
 							},
 							{
 								Operation: "WRITE",
 							},
+							{
+								Operation:                           "ACCESS",
+								Requests:                            2927395007,
+								Transmissions:                       2927394995,
+								BytesSent:                           526931094212,
+								BytesReceived:                       362996810236,
+								CumulativeQueueMilliseconds:         18446743919241604546,
+								CumulativeTotalResponseMilliseconds: 1667369447,
+								CumulativeTotalRequestMilliseconds:  1953587717,
+							},
 						},
 						Transport: NFSTransportStats{
 							Protocol:                 "tcp",
 							Port:                     832,
 							Connect:                  1,
-							IdleTime:                 11 * time.Second,
+							IdleTimeSeconds:          11,
 							Sends:                    6428,
 							Receives:                 6428,
 							CumulativeActiveRequests: 12154,