Repository: prometheus/procfs
Pull request #262 (2020-02-06 16:35:17)

Add support for fscache
This PR tries to address https://github.com/prometheus/procfs/issues/259

This pull requests adds code to get and parse fscache data from /proc/fs/fscache/stats.

The parsing is based in the order of fields. I reviewed the Linux kernel code, and the output of /proc/fs/fscache/stat hasn't changed in the last 5 years..


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 212f50a..ffd28ca 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -34,7 +34,7 @@ jobs:
     steps:
     - checkout
     - run: sudo pip install codespell
-    - run: codespell --skip=".git,./vendor,ttar,go.mod,go.sum" -L uint,packages\'
+    - run: codespell --skip=".git,./vendor,ttar,go.mod,go.sum" -L uint,packages\',ded,alo,als
 
 workflows:
   version: 2
diff --git a/.golangci.yml b/.golangci.yml
index 0aa09ed..7c4ce1f 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -1,4 +1,4 @@
----
 linters:
   enable:
-  - golint
+  - staticcheck
+  - govet
diff --git a/Makefile.common b/Makefile.common
index b978dfc..066866e 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -69,15 +69,6 @@ else
 	GO_BUILD_PLATFORM ?= $(GOHOSTOS)-$(GOHOSTARCH)
 endif
 
-GOTEST := $(GO) test
-GOTEST_DIR :=
-ifneq ($(CIRCLE_JOB),)
-ifneq ($(shell which gotestsum),)
-	GOTEST_DIR := test-results
-	GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
-endif
-endif
-
 PROMU_VERSION ?= 0.5.0
 PROMU_URL     := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
 
@@ -151,17 +142,14 @@ else
 endif
 
 .PHONY: common-test-short
-common-test-short: $(GOTEST_DIR)
+common-test-short:
 	@echo ">> running short tests"
-	GO111MODULE=$(GO111MODULE) $(GOTEST) -short $(GOOPTS) $(pkgs)
+	GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs)
 
 .PHONY: common-test
-common-test: $(GOTEST_DIR)
+common-test:
 	@echo ">> running all tests"
-	GO111MODULE=$(GO111MODULE) $(GOTEST) $(test-flags) $(GOOPTS) $(pkgs)
-
-$(GOTEST_DIR):
-	@mkdir -p $@
+	GO111MODULE=$(GO111MODULE) $(GO) test $(test-flags) $(GOOPTS) $(pkgs)
 
 .PHONY: common-format
 common-format:
diff --git a/bcache/bcache.go b/bcache/bcache.go
index df724ed..1db178c 100644
--- a/bcache/bcache.go
+++ b/bcache/bcache.go
@@ -29,7 +29,7 @@ type Stats struct {
 }
 
 // BcacheStats contains statistics tied to a bcache ID.
-type BcacheStats struct { // nolint:golint
+type BcacheStats struct {
 	AverageKeySize        uint64
 	BtreeCacheSize        uint64
 	CacheAvailablePercent uint64
diff --git a/bcache/get.go b/bcache/get.go
index 67fcf8b..a8896bd 100644
--- a/bcache/get.go
+++ b/bcache/get.go
@@ -51,21 +51,8 @@ func NewFS(mountPoint string) (FS, error) {
 	return FS{&fs}, nil
 }
 
-// Stats is a wrapper around stats()
-// It returns full available statistics
+// Stats retrieves bcache runtime statistics for each bcache.
 func (fs FS) Stats() ([]*Stats, error) {
-	return fs.stats(true)
-}
-
-// StatsWithoutPriority is a wrapper around stats().
-// It ignores priority_stats file, because it is expensive to read.
-func (fs FS) StatsWithoutPriority() ([]*Stats, error) {
-	return fs.stats(false)
-}
-
-// stats() retrieves bcache runtime statistics for each bcache.
-// priorityStats flag controls if we need to read priority_stats.
-func (fs FS) stats(priorityStats bool) ([]*Stats, error) {
 	matches, err := filepath.Glob(fs.sys.Path("fs/bcache/*-*"))
 	if err != nil {
 		return nil, err
@@ -77,7 +64,7 @@ func (fs FS) stats(priorityStats bool) ([]*Stats, error) {
 		name := filepath.Base(uuidPath)
 
 		// stats
-		s, err := GetStats(uuidPath, priorityStats)
+		s, err := GetStats(uuidPath)
 		if err != nil {
 			return nil, err
 		}
@@ -264,7 +251,7 @@ func (p *parser) getPriorityStats() PriorityStats {
 }
 
 // GetStats collects from sysfs files data tied to one bcache ID.
-func GetStats(uuidPath string, priorityStats bool) (*Stats, error) {
+func GetStats(uuidPath string) (*Stats, error) {
 	var bs Stats
 
 	par := parser{uuidPath: uuidPath}
@@ -383,10 +370,8 @@ func GetStats(uuidPath string, priorityStats bool) (*Stats, error) {
 		cs.MetadataWritten = par.readValue("metadata_written")
 		cs.Written = par.readValue("written")
 
-		if priorityStats {
-			ps := par.getPriorityStats()
-			cs.Priority = ps
-		}
+		ps := par.getPriorityStats()
+		cs.Priority = ps
 	}
 
 	if par.err != nil {
diff --git a/fixtures.ttar b/fixtures.ttar
index 45a7321..79bd516 100644
--- a/fixtures.ttar
+++ b/fixtures.ttar
@@ -289,19 +289,6 @@ Max realtime priority     0                    0
 Max realtime timeout      unlimited            unlimited            us
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Path: fixtures/proc/26232/maps
-Lines: 9
-55680ae1e000-55680ae20000 r--p 00000000 fd:01 47316994                   /bin/cat
-55680ae29000-55680ae2a000 rwxs 0000a000 fd:01 47316994                   /bin/cat
-55680bed6000-55680bef7000 rw-p 00000000 00:00 0                          [heap]
-7fdf964fc000-7fdf973f2000 r--p 00000000 fd:01 17432624                   /usr/lib/locale/locale-archive
-7fdf973f2000-7fdf97417000 r--p 00000000 fd:01 60571062                   /lib/x86_64-linux-gnu/libc-2.29.so
-7ffe9215c000-7ffe9217f000 rw-p 00000000 00:00 0                          [stack]
-7ffe921da000-7ffe921dd000 r--p 00000000 00:00 0                          [vvar]
-7ffe921dd000-7ffe921de000 r-xp 00000000 00:00 0                          [vdso]
-ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
-Mode: 644
-# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/proc/26232/root
 SymlinkTo: /does/not/exist
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -330,17 +317,6 @@ Lines: 8
                 ||     ||
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Directory: fixtures/proc/26234
-Mode: 755
-# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Path: fixtures/proc/26234/maps
-Lines: 4
-08048000-08089000 r-xp 00000000 03:01 104219 /bin/tcsh
-08089000-0808c000 rw-p 00041000 03:01 104219 /bin/tcsh
-0808c000-08146000 rwxp 00000000 00:00 0
-40000000-40015000 r-xp 00000000 03:01 61874 /lib/ld-2.3.2.so
-Mode: 644
-# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/584
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1609,6 +1585,37 @@ Mode: 664
 Directory: fixtures/proc/fs
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Directory: fixtures/proc/fs/fscache
+Mode: 755
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Path: fixtures/proc/fs/fscache/stats
+Lines: 24
+FS-Cache statistics
+Cookies: idx=3 dat=67877 spc=0
+Objects: alc=67473 nal=0 avl=67473 ded=388
+ChkAux : non=12 ok=33 upd=44 obs=55
+Pages  : mrk=547164 unc=364577
+Acquire: n=67880 nul=98 noc=25 ok=67780 nbf=39 oom=26
+Lookups: n=67473 neg=67470 pos=58 crt=67473 tmo=85
+Invals : n=14 run=13
+Updates: n=7 nul=3 run=8
+Relinqs: n=394 nul=1 wcr=2 rtr=3
+AttrChg: n=6 ok=5 nbf=4 oom=3 run=2
+Allocs : n=20 ok=19 wt=18 nbf=17 int=16
+Allocs : ops=15 owt=14 abt=13
+Retrvls: n=151959 ok=82823 wt=23467 nod=69136 nbf=15 int=69 oom=43
+Retrvls: ops=151959 owt=42747 abt=44
+Stores : n=225565 ok=225565 agn=12 nbf=13 oom=14
+Stores : ops=69156 run=294721 pgs=225565 rxd=225565 olm=43
+VmScan : nos=364512 gon=2 bsy=43 can=12 wt=66
+Ops    : pend=42753 run=221129 enq=628798 can=11 rej=88
+Ops    : ini=377538 dfr=27 rel=377538 gc=37
+CacheOp: alo=1 luo=2 luc=3 gro=4
+CacheOp: inv=5 upo=6 dro=7 pto=8 atc=9 syn=10
+CacheOp: rap=11 ras=12 alp=13 als=14 wrp=15 ucp=16 dsp=17
+CacheEv: nsp=18 stl=19 rtr=20 cul=21EOF
+Mode: 644
+# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Directory: fixtures/proc/fs/xfs
 Mode: 755
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1851,14 +1858,8 @@ FRAG6: inuse 0 memory 0
 Mode: 444
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/proc/net/softnet_stat
-Lines: 2
-00015c73 00020e76 F0000769 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
-01663fb2 00000000 000109a4 00000000 00000000 00000000 00000000 00000000 00000000
-Mode: 644
-# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Path: fixtures/proc/net/softnet_stat.broken
 Lines: 1
-00015c73 00020e76 F0000769 00000000
+00015c73 00020e76 F0000769 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
 Mode: 644
 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Path: fixtures/proc/net/udp
diff --git a/fscache.go b/fscache.go
new file mode 100644
index 0000000..8783cf3
--- /dev/null
+++ b/fscache.go
@@ -0,0 +1,422 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+
+	"github.com/prometheus/procfs/internal/util"
+)
+
+// Fscacheinfo represents fscache statistics.
+type Fscacheinfo struct {
+	// Number of index cookies allocated
+	IndexCookiesAllocated uint64
+	// data storage cookies allocated
+	DataStorageCookiesAllocated uint64
+	// Number of special cookies allocated
+	SpecialCookiesAllocated uint64
+	// Number of objects allocated
+	ObjectsAllocated uint64
+	// Number of object allocation failures
+	ObjectAllocationsFailure uint64
+	// Number of objects that reached the available state
+	ObjectsAvailable uint64
+	// Number of objects that reached the dead state
+	ObjectsDead uint64
+	// Number of objects that didn't have a coherency check
+	ObjectsWithoutCoherencyCheck uint64
+	// Number of objects that passed a coherency check
+	ObjectsWithCoherencyCheck uint64
+	// Number of objects that needed a coherency data update
+	ObjectsNeedCoherencyCheckUpdate uint64
+	// Number of objects that were declared obsolete
+	ObjectsDeclaredObsolete uint64
+	// Number of pages marked as being cached
+	PagesMarkedAsBeingCached uint64
+	// Number of uncache page requests seen
+	UncachePagesRequestSeen uint64
+	// Number of acquire cookie requests seen
+	AcquireCookiesRequestSeen uint64
+	// Number of acq reqs given a NULL parent
+	AcquireRequestsWithNullParent uint64
+	// Number of acq reqs rejected due to no cache available
+	AcquireRequestsRejectedNoCacheAvailable uint64
+	// Number of acq reqs succeeded
+	AcquireRequestsSucceeded uint64
+	// Number of acq reqs rejected due to error
+	AcquireRequestsRejectedDueToError uint64
+	// Number of acq reqs failed on ENOMEM
+	AcquireRequestsFailedDueToEnomem uint64
+	// Number of lookup calls made on cache backends
+	LookupsNumber uint64
+	// Number of negative lookups made
+	LookupsNegative uint64
+	// Number of positive lookups made
+	LookupsPositive uint64
+	// Number of objects created by lookup
+	ObjectsCreatedByLookup uint64
+	// Number of lookups timed out and requeued
+	LookupsTimedOutAndRequed uint64
+	InvalidationsNumber      uint64
+	InvalidationsRunning     uint64
+	// Number of update cookie requests seen
+	UpdateCookieRequestSeen uint64
+	// Number of upd reqs given a NULL parent
+	UpdateRequestsWithNullParent uint64
+	// Number of upd reqs granted CPU time
+	UpdateRequestsRunning uint64
+	// Number of relinquish cookie requests seen
+	RelinquishCookiesRequestSeen uint64
+	// Number of rlq reqs given a NULL parent
+	RelinquishCookiesWithNullParent uint64
+	// Number of rlq reqs waited on completion of creation
+	RelinquishRequestsWaitingCompleteCreation uint64
+	// Relinqs rtr
+	RelinquishRetries uint64
+	// Number of attribute changed requests seen
+	AttributeChangedRequestsSeen uint64
+	// Number of attr changed requests queued
+	AttributeChangedRequestsQueued uint64
+	// Number of attr changed rejected -ENOBUFS
+	AttributeChangedRejectDueToEnobufs uint64
+	// Number of attr changed failed -ENOMEM
+	AttributeChangedFailedDueToEnomem uint64
+	// Number of attr changed ops given CPU time
+	AttributeChangedOps uint64
+	// Number of allocation requests seen
+	AllocationRequestsSeen uint64
+	// Number of successful alloc reqs
+	AllocationOkRequests uint64
+	// Number of alloc reqs that waited on lookup completion
+	AllocationWaitingOnLookup uint64
+	// Number of alloc reqs rejected -ENOBUFS
+	AllocationsRejectedDueToEnobufs uint64
+	// Number of alloc reqs aborted -ERESTARTSYS
+	AllocationsAbortedDueToErestartsys uint64
+	// Number of alloc reqs submitted
+	AllocationOperationsSubmitted uint64
+	// Number of alloc reqs waited for CPU time
+	AllocationsWaitedForCPU uint64
+	// Number of alloc reqs aborted due to object death
+	AllocationsAbortedDueToObjectDeath uint64
+	// Number of retrieval (read) requests seen
+	RetrievalsReadRequests uint64
+	// Number of successful retr reqs
+	RetrievalsOk uint64
+	// Number of retr reqs that waited on lookup completion
+	RetrievalsWaitingLookupCompletion uint64
+	// Number of retr reqs returned -ENODATA
+	RetrievalsReturnedEnodata uint64
+	// Number of retr reqs rejected -ENOBUFS
+	RetrievalsRejectedDueToEnobufs uint64
+	// Number of retr reqs aborted -ERESTARTSYS
+	RetrievalsAbortedDueToErestartsys uint64
+	// Number of retr reqs failed -ENOMEM
+	RetrievalsFailedDueToEnomem uint64
+	// Number of retr reqs submitted
+	RetrievalsRequests uint64
+	// Number of retr reqs waited for CPU time
+	RetrievalsWaitingCPU uint64
+	// Number of retr reqs aborted due to object death
+	RetrievalsAbortedDueToObjectDeath uint64
+	// Number of storage (write) requests seen
+	StoreWriteRequests uint64
+	// Number of successful store reqs
+	StoreSuccessfulRequests uint64
+	// Number of store reqs on a page already pending storage
+	StoreRequestsOnPendingStorage uint64
+	// Number of store reqs rejected -ENOBUFS
+	StoreRequestsRejectedDueToEnobufs uint64
+	// Number of store reqs failed -ENOMEM
+	StoreRequestsFailedDueToEnomem uint64
+	// Number of store reqs submitted
+	StoreRequestsSubmitted uint64
+	// Number of store reqs granted CPU time
+	StoreRequestsRunning uint64
+	// Number of pages given store req processing time
+	StorePagesWithRequestsProcessing uint64
+	// Number of store reqs deleted from tracking tree
+	StoreRequestsDeleted uint64
+	// Number of store reqs over store limit
+	StoreRequestsOverStoreLimit uint64
+	// Number of release reqs against pages with no pending store
+	ReleaseRequestsAgainstPagesWithNoPendingStorage uint64
+	// Number of release reqs against pages stored by time lock granted
+	ReleaseRequestsAgainstPagesStoredByTimeLockGranted uint64
+	// Number of release reqs ignored due to in-progress store
+	ReleaseRequestsIgnoredDueToInProgressStore uint64
+	// Number of page stores cancelled due to release req
+	PageStoresCancelledByReleaseRequests uint64
+	VmscanWaiting                        uint64
+	// Number of times async ops added to pending queues
+	OpsPending uint64
+	// Number of times async ops given CPU time
+	OpsRunning uint64
+	// Number of times async ops queued for processing
+	OpsEnqueued uint64
+	// Number of async ops cancelled
+	OpsCancelled uint64
+	// Number of async ops rejected due to object lookup/create failure
+	OpsRejected uint64
+	// Number of async ops initialised
+	OpsInitialised uint64
+	// Number of async ops queued for deferred release
+	OpsDeferred uint64
+	// Number of async ops released (should equal ini=N when idle)
+	OpsReleased uint64
+	// Number of deferred-release async ops garbage collected
+	OpsGarbageCollected uint64
+	// Number of in-progress alloc_object() cache ops
+	CacheopAllocationsinProgress uint64
+	// Number of in-progress lookup_object() cache ops
+	CacheopLookupObjectInProgress uint64
+	// Number of in-progress lookup_complete() cache ops
+	CacheopLookupCompleteInPorgress uint64
+	// Number of in-progress grab_object() cache ops
+	CacheopGrabObjectInProgress uint64
+	CacheopInvalidations        uint64
+	// Number of in-progress update_object() cache ops
+	CacheopUpdateObjectInProgress uint64
+	// Number of in-progress drop_object() cache ops
+	CacheopDropObjectInProgress uint64
+	// Number of in-progress put_object() cache ops
+	CacheopPutObjectInProgress uint64
+	// Number of in-progress attr_changed() cache ops
+	CacheopAttributeChangeInProgress uint64
+	// Number of in-progress sync_cache() cache ops
+	CacheopSyncCacheInProgress uint64
+	// Number of in-progress read_or_alloc_page() cache ops
+	CacheopReadOrAllocPageInProgress uint64
+	// Number of in-progress read_or_alloc_pages() cache ops
+	CacheopReadOrAllocPagesInProgress uint64
+	// Number of in-progress allocate_page() cache ops
+	CacheopAllocatePageInProgress uint64
+	// Number of in-progress allocate_pages() cache ops
+	CacheopAllocatePagesInProgress uint64
+	// Number of in-progress write_page() cache ops
+	CacheopWritePagesInProgress uint64
+	// Number of in-progress uncache_page() cache ops
+	CacheopUncachePagesInProgress uint64
+	// Number of in-progress dissociate_pages() cache ops
+	CacheopDissociatePagesInProgress uint64
+	// Number of object lookups/creations rejected due to lack of space
+	CacheevLookupsAndCreationsRejectedLackSpace uint64
+	// Number of stale objects deleted
+	CacheevStaleObjectsDeleted uint64
+	// Number of objects retired when relinquished
+	CacheevRetiredWhenReliquished uint64
+	// Number of objects culled
+	CacheevObjectsCulled uint64
+}
+
+// Fscacheinfo returns information about current fscache statistics.
+// See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt
+func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
+	b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats"))
+	if err != nil {
+		return Fscacheinfo{}, err
+	}
+
+	m, err := parseFscacheinfo(bytes.NewReader(b))
+	if err != nil {
+		return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %v", err)
+	}
+
+	return *m, nil
+}
+
+func setFSCacheFields(fields []string, setFields ...*uint64) error {
+	var err error
+	if len(fields) < len(setFields) {
+		return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields))
+	}
+
+	for i := range setFields {
+		*setFields[i], err = strconv.ParseUint(strings.Split(fields[i], "=")[1], 0, 64)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
+	var m Fscacheinfo
+	s := bufio.NewScanner(r)
+	for s.Scan() {
+		fields := strings.Fields(s.Text())
+		if len(fields) < 2 {
+			return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text())
+		}
+
+		switch fields[0] {
+		case "Cookies:":
+			err := setFSCacheFields(fields[1:], &m.IndexCookiesAllocated, &m.DataStorageCookiesAllocated,
+				&m.SpecialCookiesAllocated)
+			if err != nil {
+				return &m, err
+			}
+		case "Objects:":
+			err := setFSCacheFields(fields[1:], &m.ObjectsAllocated, &m.ObjectAllocationsFailure,
+				&m.ObjectsAvailable, &m.ObjectsDead)
+			if err != nil {
+				return &m, err
+			}
+		case "ChkAux":
+			err := setFSCacheFields(fields[2:], &m.ObjectsWithoutCoherencyCheck, &m.ObjectsWithCoherencyCheck,
+				&m.ObjectsNeedCoherencyCheckUpdate, &m.ObjectsDeclaredObsolete)
+			if err != nil {
+				return &m, err
+			}
+		case "Pages":
+			err := setFSCacheFields(fields[2:], &m.PagesMarkedAsBeingCached, &m.UncachePagesRequestSeen)
+			if err != nil {
+				return &m, err
+			}
+		case "Acquire:":
+			err := setFSCacheFields(fields[1:], &m.AcquireCookiesRequestSeen, &m.AcquireRequestsWithNullParent,
+				&m.AcquireRequestsRejectedNoCacheAvailable, &m.AcquireRequestsSucceeded, &m.AcquireRequestsRejectedDueToError,
+				&m.AcquireRequestsFailedDueToEnomem)
+			if err != nil {
+				return &m, err
+			}
+		case "Lookups:":
+			err := setFSCacheFields(fields[1:], &m.LookupsNumber, &m.LookupsNegative, &m.LookupsPositive,
+				&m.ObjectsCreatedByLookup, &m.LookupsTimedOutAndRequed)
+			if err != nil {
+				return &m, err
+			}
+		case "Invals":
+			err := setFSCacheFields(fields[2:], &m.InvalidationsNumber, &m.InvalidationsRunning)
+			if err != nil {
+				return &m, err
+			}
+		case "Updates:":
+			err := setFSCacheFields(fields[1:], &m.UpdateCookieRequestSeen, &m.UpdateRequestsWithNullParent,
+				&m.UpdateRequestsRunning)
+			if err != nil {
+				return &m, err
+			}
+		case "Relinqs:":
+			err := setFSCacheFields(fields[1:], &m.RelinquishCookiesRequestSeen, &m.RelinquishCookiesWithNullParent,
+				&m.RelinquishRequestsWaitingCompleteCreation, &m.RelinquishRetries)
+			if err != nil {
+				return &m, err
+			}
+		case "AttrChg:":
+			err := setFSCacheFields(fields[1:], &m.AttributeChangedRequestsSeen, &m.AttributeChangedRequestsQueued,
+				&m.AttributeChangedRejectDueToEnobufs, &m.AttributeChangedFailedDueToEnomem, &m.AttributeChangedOps)
+			if err != nil {
+				return &m, err
+			}
+		case "Allocs":
+			if strings.Split(fields[2], "=")[0] == "n" {
+				err := setFSCacheFields(fields[2:], &m.AllocationRequestsSeen, &m.AllocationOkRequests,
+					&m.AllocationWaitingOnLookup, &m.AllocationsRejectedDueToEnobufs, &m.AllocationsAbortedDueToErestartsys)
+				if err != nil {
+					return &m, err
+				}
+			} else {
+				err := setFSCacheFields(fields[2:], &m.AllocationOperationsSubmitted, &m.AllocationsWaitedForCPU,
+					&m.AllocationsAbortedDueToObjectDeath)
+				if err != nil {
+					return &m, err
+				}
+			}
+		case "Retrvls:":
+			if strings.Split(fields[1], "=")[0] == "n" {
+				err := setFSCacheFields(fields[1:], &m.RetrievalsReadRequests, &m.RetrievalsOk, &m.RetrievalsWaitingLookupCompletion,
+					&m.RetrievalsReturnedEnodata, &m.RetrievalsRejectedDueToEnobufs, &m.RetrievalsAbortedDueToErestartsys,
+					&m.RetrievalsFailedDueToEnomem)
+				if err != nil {
+					return &m, err
+				}
+			} else {
+				err := setFSCacheFields(fields[1:], &m.RetrievalsRequests, &m.RetrievalsWaitingCPU, &m.RetrievalsAbortedDueToObjectDeath)
+				if err != nil {
+					return &m, err
+				}
+			}
+		case "Stores":
+			if strings.Split(fields[2], "=")[0] == "n" {
+				err := setFSCacheFields(fields[2:], &m.StoreWriteRequests, &m.StoreSuccessfulRequests,
+					&m.StoreRequestsOnPendingStorage, &m.StoreRequestsRejectedDueToEnobufs, &m.StoreRequestsFailedDueToEnomem)
+				if err != nil {
+					return &m, err
+				}
+			} else {
+				err := setFSCacheFields(fields[2:], &m.StoreRequestsSubmitted, &m.StoreRequestsRunning,
+					&m.StorePagesWithRequestsProcessing, &m.StoreRequestsDeleted, &m.StoreRequestsOverStoreLimit)
+				if err != nil {
+					return &m, err
+				}
+			}
+		case "VmScan":
+			err := setFSCacheFields(fields[2:], &m.ReleaseRequestsAgainstPagesWithNoPendingStorage,
+				&m.ReleaseRequestsAgainstPagesStoredByTimeLockGranted, &m.ReleaseRequestsIgnoredDueToInProgressStore,
+				&m.PageStoresCancelledByReleaseRequests, &m.VmscanWaiting)
+			if err != nil {
+				return &m, err
+			}
+		case "Ops":
+			if strings.Split(fields[2], "=")[0] == "pend" {
+				err := setFSCacheFields(fields[2:], &m.OpsPending, &m.OpsRunning, &m.OpsEnqueued, &m.OpsCancelled, &m.OpsRejected)
+				if err != nil {
+					return &m, err
+				}
+			} else {
+				err := setFSCacheFields(fields[2:], &m.OpsInitialised, &m.OpsDeferred, &m.OpsReleased, &m.OpsGarbageCollected)
+				if err != nil {
+					return &m, err
+				}
+			}
+		case "CacheOp:":
+			if strings.Split(fields[1], "=")[0] == "alo" {
+				err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress,
+					&m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress)
+				if err != nil {
+					return &m, err
+				}
+			} else if strings.Split(fields[1], "=")[0] == "inv" {
+				err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress,
+					&m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress,
+					&m.CacheopSyncCacheInProgress)
+				if err != nil {
+					return &m, err
+				}
+			} else {
+				err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress,
+					&m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress,
+					&m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress)
+				if err != nil {
+					return &m, err
+				}
+			}
+		case "CacheEv:":
+			err := setFSCacheFields(fields[1:], &m.CacheevLookupsAndCreationsRejectedLackSpace, &m.CacheevStaleObjectsDeleted,
+				&m.CacheevRetiredWhenReliquished, &m.CacheevObjectsCulled)
+			if err != nil {
+				return &m, err
+			}
+		}
+	}
+
+	return &m, nil
+}
diff --git a/go.mod b/go.mod
index ded4825..0e04e5d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,5 +5,4 @@ go 1.12
 require (
 	github.com/google/go-cmp v0.3.1
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
-	golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e
 )
diff --git a/go.sum b/go.sum
index 54b5f33..33b824b 100644
--- a/go.sum
+++ b/go.sum
@@ -2,5 +2,3 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e h1:LwyF2AFISC9nVbS6MgzsaQNSUsRXI49GS+YQ5KX/QH0=
-golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/mountinfo.go b/mountinfo.go
index 9471136..bb01bb5 100644
--- a/mountinfo.go
+++ b/mountinfo.go
@@ -29,10 +29,10 @@ import (
 // is described in the following man page.
 // http://man7.org/linux/man-pages/man5/proc.5.html
 type MountInfo struct {
-	// Unique ID for the mount
-	MountID int
-	// The ID of the parent mount
-	ParentID int
+	// Unique Id for the mount
+	MountId int
+	// The Id of the parent mount
+	ParentId int
 	// The value of `st_dev` for the files on this FS
 	MajorMinorVer string
 	// The pathname of the directory in the FS that forms
@@ -96,11 +96,11 @@ func parseMountInfoString(mountString string) (*MountInfo, error) {
 		SuperOptions:   mountOptionsParser(mountInfo[mountInfoLength-1]),
 	}
 
-	mount.MountID, err = strconv.Atoi(mountInfo[0])
+	mount.MountId, err = strconv.Atoi(mountInfo[0])
 	if err != nil {
 		return nil, fmt.Errorf("failed to parse mount ID")
 	}
-	mount.ParentID, err = strconv.Atoi(mountInfo[1])
+	mount.ParentId, err = strconv.Atoi(mountInfo[1])
 	if err != nil {
 		return nil, fmt.Errorf("failed to parse parent ID")
 	}
diff --git a/net_softnet.go b/net_softnet.go
index db5debd..2a65cf1 100644
--- a/net_softnet.go
+++ b/net_softnet.go
@@ -25,9 +25,7 @@ import (
 )
 
 // For the proc file format details,
-// See:
-// * Linux 2.6.23 https://elixir.bootlin.com/linux/v2.6.23/source/net/core/dev.c#L2343
-// * Linux 4.17 https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162
+// see https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162
 // and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810.
 
 // SoftnetStat contains a single row of data from /proc/net/softnet_stat
@@ -40,11 +38,9 @@ type SoftnetStat struct {
 	TimeSqueezed uint32
 }
 
-var softNetProcFile = "net/softnet_stat"
-
 // NetSoftnetStat reads data from /proc/net/softnet_stat.
 func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
-	b, err := util.ReadFileNoStat(fs.proc.Path(softNetProcFile))
+	b, err := util.ReadFileNoStat(fs.proc.Path("net/softnet_stat"))
 	if err != nil {
 		return nil, err
 	}
@@ -58,7 +54,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
 }
 
 func parseSoftnet(r io.Reader) ([]SoftnetStat, error) {
-	const minColumns = 9
+	const expectedColumns = 11
 
 	s := bufio.NewScanner(r)
 
@@ -67,8 +63,8 @@ func parseSoftnet(r io.Reader) ([]SoftnetStat, error) {
 		columns := strings.Fields(s.Text())
 		width := len(columns)
 
-		if width < minColumns {
-			return nil, fmt.Errorf("%d columns were detected, but at least %d were expected", width, minColumns)
+		if width != 11 {
+			return nil, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns)
 		}
 
 		// We only parse the first three columns at the moment.
diff --git a/proc_cgroup.go b/proc_cgroup.go
deleted file mode 100644
index 4abd464..0000000
--- a/proc_cgroup.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package procfs
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/prometheus/procfs/internal/util"
-)
-
-// Cgroup models one line from /proc/[pid]/cgroup. Each Cgroup struct describes the the placement of a PID inside a
-// specific control hierarchy. The kernel has two cgroup APIs, v1 and v2. v1 has one hierarchy per available resource
-// controller, while v2 has one unified hierarchy shared by all controllers. Regardless of v1 or v2, all hierarchies
-// contain all running processes, so the question answerable with a Cgroup struct is 'where is this process in
-// this hierarchy' (where==what path on the specific cgroupfs). By prefixing this path with the mount point of
-// *this specific* hierarchy, you can locate the relevant pseudo-files needed to read/set the data for this PID
-// in this hierarchy
-//
-// Also see http://man7.org/linux/man-pages/man7/cgroups.7.html
-type Cgroup struct {
-	// HierarchyID that can be matched to a named hierarchy using /proc/cgroups. Cgroups V2 only has one
-	// hierarchy, so HierarchyID is always 0. For cgroups v1 this is a unique ID number
-	HierarchyID int
-	// Controllers using this hierarchy of processes. Controllers are also known as subsystems. For
-	// Cgroups V2 this may be empty, as all active controllers use the same hierarchy
-	Controllers []string
-	// Path of this control group, relative to the mount point of the cgroupfs representing this specific
-	// hierarchy
-	Path string
-}
-
-// parseCgroupString parses each line of the /proc/[pid]/cgroup file
-// Line format is hierarchyID:[controller1,controller2]:path
-func parseCgroupString(cgroupStr string) (*Cgroup, error) {
-	var err error
-
-	fields := strings.Split(cgroupStr, ":")
-	if len(fields) < 3 {
-		return nil, fmt.Errorf("at least 3 fields required, found %d fields in cgroup string: %s", len(fields), cgroupStr)
-	}
-
-	cgroup := &Cgroup{
-		Path:        fields[2],
-		Controllers: nil,
-	}
-	cgroup.HierarchyID, err = strconv.Atoi(fields[0])
-	if err != nil {
-		return nil, fmt.Errorf("failed to parse hierarchy ID")
-	}
-	if fields[1] != "" {
-		ssNames := strings.Split(fields[1], ",")
-		cgroup.Controllers = append(cgroup.Controllers, ssNames...)
-	}
-	return cgroup, nil
-}
-
-// parseCgroups reads each line of the /proc/[pid]/cgroup file
-func parseCgroups(data []byte) ([]Cgroup, error) {
-	var cgroups []Cgroup
-	scanner := bufio.NewScanner(bytes.NewReader(data))
-	for scanner.Scan() {
-		mountString := scanner.Text()
-		parsedMounts, err := parseCgroupString(mountString)
-		if err != nil {
-			return nil, err
-		}
-		cgroups = append(cgroups, *parsedMounts)
-	}
-
-	err := scanner.Err()
-	return cgroups, err
-}
-
-// Cgroups reads from /proc/<pid>/cgroups and returns a []*Cgroup struct locating this PID in each process
-// control hierarchy running on this system. On every system (v1 and v2), all hierarchies contain all processes,
-// so the len of the returned struct is equal to the number of active hierarchies on this system
-func (p Proc) Cgroups() ([]Cgroup, error) {
-	data, err := util.ReadFileNoStat(fmt.Sprintf("/proc/%d/cgroup", p.PID))
-	if err != nil {
-		return nil, err
-	}
-	return parseCgroups(data)
-}
diff --git a/proc_fdinfo.go b/proc_fdinfo.go
index 0c9c402..4e7597f 100644
--- a/proc_fdinfo.go
+++ b/proc_fdinfo.go
@@ -16,7 +16,6 @@ package procfs
 import (
 	"bufio"
 	"bytes"
-	"errors"
 	"regexp"
 
 	"github.com/prometheus/procfs/internal/util"
@@ -24,11 +23,10 @@ import (
 
 // Regexp variables
 var (
-	rPos          = regexp.MustCompile(`^pos:\s+(\d+)$`)
-	rFlags        = regexp.MustCompile(`^flags:\s+(\d+)$`)
-	rMntID        = regexp.MustCompile(`^mnt_id:\s+(\d+)$`)
-	rInotify      = regexp.MustCompile(`^inotify`)
-	rInotifyParts = regexp.MustCompile(`^inotify\s+wd:([0-9a-f]+)\s+ino:([0-9a-f]+)\s+sdev:([0-9a-f]+)(?:\s+mask:([0-9a-f]+))?`)
+	rPos     = regexp.MustCompile(`^pos:\s+(\d+)$`)
+	rFlags   = regexp.MustCompile(`^flags:\s+(\d+)$`)
+	rMntID   = regexp.MustCompile(`^mnt_id:\s+(\d+)$`)
+	rInotify = regexp.MustCompile(`^inotify`)
 )
 
 // ProcFDInfo contains represents file descriptor information.
@@ -98,21 +96,15 @@ type InotifyInfo struct {
 
 // InotifyInfo constructor. Only available on kernel 3.8+.
 func parseInotifyInfo(line string) (*InotifyInfo, error) {
-	m := rInotifyParts.FindStringSubmatch(line)
-	if len(m) >= 4 {
-		var mask string
-		if len(m) == 5 {
-			mask = m[4]
-		}
-		i := &InotifyInfo{
-			WD:   m[1],
-			Ino:  m[2],
-			Sdev: m[3],
-			Mask: mask,
-		}
-		return i, nil
+	r := regexp.MustCompile(`^inotify\s+wd:([0-9a-f]+)\s+ino:([0-9a-f]+)\s+sdev:([0-9a-f]+)\s+mask:([0-9a-f]+)`)
+	m := r.FindStringSubmatch(line)
+	i := &InotifyInfo{
+		WD:   m[1],
+		Ino:  m[2],
+		Sdev: m[3],
+		Mask: m[4],
 	}
-	return nil, errors.New("invalid inode entry: " + line)
+	return i, nil
 }
 
 // ProcFDInfos represents a list of ProcFDInfo structs.
diff --git a/proc_maps.go b/proc_maps.go
deleted file mode 100644
index 28d5c6e..0000000
--- a/proc_maps.go
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2019 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !windows
-
-package procfs
-
-import (
-	"bufio"
-	"fmt"
-	"os"
-	"strconv"
-	"strings"
-
-	"golang.org/x/sys/unix"
-)
-
-type ProcMapPermissions struct {
-	// mapping has the [R]ead flag set
-	Read bool
-	// mapping has the [W]rite flag set
-	Write bool
-	// mapping has the [X]ecutable flag set
-	Execute bool
-	// mapping has the [S]hared flag set
-	Shared bool
-	// mapping is marked as [P]rivate (copy on write)
-	Private bool
-}
-
-// ProcMap contains the process memory-mappings of the process,
-// read from /proc/[pid]/maps
-type ProcMap struct {
-	// The start address of current mapping.
-	StartAddr uintptr
-	// The end address of the current mapping
-	EndAddr uintptr
-	// The permissions for this mapping
-	Perms *ProcMapPermissions
-	// The current offset into the file/fd (e.g., shared libs)
-	Offset int64
-	// Device owner of this mapping (major:minor) in Mkdev format.
-	Dev uint64
-	// The inode of the device above
-	Inode uint64
-	// The file or psuedofile (or empty==anonymous)
-	Pathname string
-}
-
-// parseDevice parses the device token of a line and converts it to a dev_t
-// (mkdev) like structure.
-func parseDevice(s string) (uint64, error) {
-	toks := strings.Split(s, ":")
-	if len(toks) < 2 {
-		return 0, fmt.Errorf("unexpected number of fields")
-	}
-
-	major, err := strconv.ParseUint(toks[0], 16, 0)
-	if err != nil {
-		return 0, err
-	}
-
-	minor, err := strconv.ParseUint(toks[1], 16, 0)
-	if err != nil {
-		return 0, err
-	}
-
-	return unix.Mkdev(uint32(major), uint32(minor)), nil
-}
-
-// parseAddress just converts a hex-string to a uintptr
-func parseAddress(s string) (uintptr, error) {
-	a, err := strconv.ParseUint(s, 16, 0)
-	if err != nil {
-		return 0, err
-	}
-
-	return uintptr(a), nil
-}
-
-// parseAddresses parses the start-end address
-func parseAddresses(s string) (uintptr, uintptr, error) {
-	toks := strings.Split(s, "-")
-	if len(toks) < 2 {
-		return 0, 0, fmt.Errorf("invalid address")
-	}
-
-	saddr, err := parseAddress(toks[0])
-	if err != nil {
-		return 0, 0, err
-	}
-
-	eaddr, err := parseAddress(toks[1])
-	if err != nil {
-		return 0, 0, err
-	}
-
-	return saddr, eaddr, nil
-}
-
-// parsePermissions parses a token and returns any that are set.
-func parsePermissions(s string) (*ProcMapPermissions, error) {
-	if len(s) < 4 {
-		return nil, fmt.Errorf("invalid permissions token")
-	}
-
-	perms := ProcMapPermissions{}
-	for _, ch := range s {
-		switch ch {
-		case 'r':
-			perms.Read = true
-		case 'w':
-			perms.Write = true
-		case 'x':
-			perms.Execute = true
-		case 'p':
-			perms.Private = true
-		case 's':
-			perms.Shared = true
-		}
-	}
-
-	return &perms, nil
-}
-
-// parseProcMap will attempt to parse a single line within a proc/[pid]/maps
-// buffer.
-func parseProcMap(text string) (*ProcMap, error) {
-	fields := strings.Fields(text)
-	if len(fields) < 5 {
-		return nil, fmt.Errorf("truncated procmap entry")
-	}
-
-	saddr, eaddr, err := parseAddresses(fields[0])
-	if err != nil {
-		return nil, err
-	}
-
-	perms, err := parsePermissions(fields[1])
-	if err != nil {
-		return nil, err
-	}
-
-	offset, err := strconv.ParseInt(fields[2], 16, 0)
-	if err != nil {
-		return nil, err
-	}
-
-	device, err := parseDevice(fields[3])
-	if err != nil {
-		return nil, err
-	}
-
-	inode, err := strconv.ParseUint(fields[4], 10, 0)
-	if err != nil {
-		return nil, err
-	}
-
-	pathname := ""
-
-	if len(fields) >= 5 {
-		pathname = strings.Join(fields[5:], " ")
-	}
-
-	return &ProcMap{
-		StartAddr: saddr,
-		EndAddr:   eaddr,
-		Perms:     perms,
-		Offset:    offset,
-		Dev:       device,
-		Inode:     inode,
-		Pathname:  pathname,
-	}, nil
-}
-
-// ProcMaps reads from /proc/[pid]/maps to get the memory-mappings of the
-// process.
-func (p Proc) ProcMaps() ([]*ProcMap, error) {
-	file, err := os.Open(p.path("maps"))
-	if err != nil {
-		return nil, err
-	}
-	defer file.Close()
-
-	maps := []*ProcMap{}
-	scan := bufio.NewScanner(file)
-
-	for scan.Scan() {
-		m, err := parseProcMap(scan.Text())
-		if err != nil {
-			return nil, err
-		}
-
-		maps = append(maps, m)
-	}
-
-	return maps, nil
-}
diff --git a/proc_status.go b/proc_status.go
index c58346d..17b4516 100644
--- a/proc_status.go
+++ b/proc_status.go
@@ -33,37 +33,37 @@ type ProcStatus struct {
 	TGID int
 
 	// Peak virtual memory size.
-	VmPeak uint64 // nolint:golint
+	VmPeak uint64
 	// Virtual memory size.
-	VmSize uint64 // nolint:golint
+	VmSize uint64
 	// Locked memory size.
-	VmLck uint64 // nolint:golint
+	VmLck uint64
 	// Pinned memory size.
-	VmPin uint64 // nolint:golint
+	VmPin uint64
 	// Peak resident set size.
-	VmHWM uint64 // nolint:golint
+	VmHWM uint64
 	// Resident set size (sum of RssAnnon RssFile and RssShmem).
-	VmRSS uint64 // nolint:golint
+	VmRSS uint64
 	// Size of resident anonymous memory.
-	RssAnon uint64 // nolint:golint
+	RssAnon uint64
 	// Size of resident file mappings.
-	RssFile uint64 // nolint:golint
+	RssFile uint64
 	// Size of resident shared memory.
-	RssShmem uint64 // nolint:golint
+	RssShmem uint64
 	// Size of data segments.
-	VmData uint64 // nolint:golint
+	VmData uint64
 	// Size of stack segments.
-	VmStk uint64 // nolint:golint
+	VmStk uint64
 	// Size of text segments.
-	VmExe uint64 // nolint:golint
+	VmExe uint64
 	// Shared library code size.
-	VmLib uint64 // nolint:golint
+	VmLib uint64
 	// Page table entries size.
-	VmPTE uint64 // nolint:golint
+	VmPTE uint64
 	// Size of second-level page tables.
-	VmPMD uint64 // nolint:golint
+	VmPMD uint64
 	// Swapped-out virtual memory size by anonymous private.
-	VmSwap uint64 // nolint:golint
+	VmSwap uint64
 	// Size of hugetlb memory portions
 	HugetlbPages uint64
 
diff --git a/sysfs/class_infiniband.go b/sysfs/class_infiniband.go
index be900fa..9156474 100644
--- a/sysfs/class_infiniband.go
+++ b/sysfs/class_infiniband.go
@@ -97,7 +97,7 @@ func (fs FS) InfiniBandClass() (InfiniBandClass, error) {
 
 	dirs, err := ioutil.ReadDir(path)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to list InfiniBand devices at %q: %v", path, err)
 	}
 
 	ibc := make(InfiniBandClass, len(dirs))
@@ -251,7 +251,7 @@ func parseInfiniBandCounters(portPath string) (*InfiniBandCounters, error) {
 		name := filepath.Join(path, f.Name())
 		value, err := util.SysReadFile(name)
 		if err != nil {
-			if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
+			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
 				continue
 			}
 			return nil, fmt.Errorf("failed to read file %q: %v", name, err)
@@ -334,7 +334,7 @@ func parseInfiniBandCounters(portPath string) (*InfiniBandCounters, error) {
 		name := filepath.Join(path, f.Name())
 		value, err := util.SysReadFile(name)
 		if err != nil {
-			if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
+			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
 				continue
 			}
 			return nil, fmt.Errorf("failed to read file %q: %v", name, err)
diff --git a/sysfs/net_class.go b/sysfs/net_class.go
index 8f64987..9aa6b57 100644
--- a/sysfs/net_class.go
+++ b/sysfs/net_class.go
@@ -119,7 +119,7 @@ func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error)
 		name := filepath.Join(devicePath, f.Name())
 		value, err := util.SysReadFile(name)
 		if err != nil {
-			if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
+			if os.IsNotExist(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" {
 				continue
 			}
 			return nil, fmt.Errorf("failed to read file %q: %v", name, err)


Test patch:
diff --git a/fscache_test.go b/fscache_test.go
new file mode 100644
index 0000000..249dd43
--- /dev/null
+++ b/fscache_test.go
@@ -0,0 +1,136 @@
+// Copyright 2019 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package procfs
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestFscacheinfo(t *testing.T) {
+	expected := Fscacheinfo{
+		IndexCookiesAllocated:                              3,
+		DataStorageCookiesAllocated:                        67877,
+		SpecialCookiesAllocated:                            0,
+		ObjectsAllocated:                                   67473,
+		ObjectAllocationsFailure:                           0,
+		ObjectsAvailable:                                   67473,
+		ObjectsDead:                                        388,
+		ObjectsWithoutCoherencyCheck:                       12,
+		ObjectsWithCoherencyCheck:                          33,
+		ObjectsNeedCoherencyCheckUpdate:                    44,
+		ObjectsDeclaredObsolete:                            55,
+		PagesMarkedAsBeingCached:                           547164,
+		UncachePagesRequestSeen:                            364577,
+		AcquireCookiesRequestSeen:                          67880,
+		AcquireRequestsWithNullParent:                      98,
+		AcquireRequestsRejectedNoCacheAvailable:            25,
+		AcquireRequestsSucceeded:                           67780,
+		AcquireRequestsRejectedDueToError:                  39,
+		AcquireRequestsFailedDueToEnomem:                   26,
+		LookupsNumber:                                      67473,
+		LookupsNegative:                                    67470,
+		LookupsPositive:                                    58,
+		ObjectsCreatedByLookup:                             67473,
+		LookupsTimedOutAndRequed:                           85,
+		InvalidationsNumber:                                14,
+		InvalidationsRunning:                               13,
+		UpdateCookieRequestSeen:                            7,
+		UpdateRequestsWithNullParent:                       3,
+		UpdateRequestsRunning:                              8,
+		RelinquishCookiesRequestSeen:                       394,
+		RelinquishCookiesWithNullParent:                    1,
+		RelinquishRequestsWaitingCompleteCreation:          2,
+		RelinquishRetries:                                  3,
+		AttributeChangedRequestsSeen:                       6,
+		AttributeChangedRequestsQueued:                     5,
+		AttributeChangedRejectDueToEnobufs:                 4,
+		AttributeChangedFailedDueToEnomem:                  3,
+		AttributeChangedOps:                                2,
+		AllocationRequestsSeen:                             20,
+		AllocationOkRequests:                               19,
+		AllocationWaitingOnLookup:                          18,
+		AllocationsRejectedDueToEnobufs:                    17,
+		AllocationsAbortedDueToErestartsys:                 16,
+		AllocationOperationsSubmitted:                      15,
+		AllocationsWaitedForCPU:                            14,
+		AllocationsAbortedDueToObjectDeath:                 13,
+		RetrievalsReadRequests:                             151959,
+		RetrievalsOk:                                       82823,
+		RetrievalsWaitingLookupCompletion:                  23467,
+		RetrievalsReturnedEnodata:                          69136,
+		RetrievalsRejectedDueToEnobufs:                     15,
+		RetrievalsAbortedDueToErestartsys:                  69,
+		RetrievalsFailedDueToEnomem:                        43,
+		RetrievalsRequests:                                 151959,
+		RetrievalsWaitingCPU:                               42747,
+		RetrievalsAbortedDueToObjectDeath:                  44,
+		StoreWriteRequests:                                 225565,
+		StoreSuccessfulRequests:                            225565,
+		StoreRequestsOnPendingStorage:                      12,
+		StoreRequestsRejectedDueToEnobufs:                  13,
+		StoreRequestsFailedDueToEnomem:                     14,
+		StoreRequestsSubmitted:                             69156,
+		StoreRequestsRunning:                               294721,
+		StorePagesWithRequestsProcessing:                   225565,
+		StoreRequestsDeleted:                               225565,
+		StoreRequestsOverStoreLimit:                        43,
+		ReleaseRequestsAgainstPagesWithNoPendingStorage:    364512,
+		ReleaseRequestsAgainstPagesStoredByTimeLockGranted: 2,
+		ReleaseRequestsIgnoredDueToInProgressStore:         43,
+		PageStoresCancelledByReleaseRequests:               12,
+		VmscanWaiting:                                      66,
+		OpsPending:                                         42753,
+		OpsRunning:                                         221129,
+		OpsEnqueued:                                        628798,
+		OpsCancelled:                                       11,
+		OpsRejected:                                        88,
+		OpsInitialised:                                     377538,
+		OpsDeferred:                                        27,
+		OpsReleased:                                        377538,
+		OpsGarbageCollected:                                37,
+		CacheopAllocationsinProgress:                       1,
+		CacheopLookupObjectInProgress:                      2,
+		CacheopLookupCompleteInPorgress:                    3,
+		CacheopGrabObjectInProgress:                        4,
+		CacheopInvalidations:                               5,
+		CacheopUpdateObjectInProgress:                      6,
+		CacheopDropObjectInProgress:                        7,
+		CacheopPutObjectInProgress:                         8,
+		CacheopAttributeChangeInProgress:                   9,
+		CacheopSyncCacheInProgress:                         10,
+		CacheopReadOrAllocPageInProgress:                   11,
+		CacheopReadOrAllocPagesInProgress:                  12,
+		CacheopAllocatePageInProgress:                      13,
+		CacheopAllocatePagesInProgress:                     14,
+		CacheopWritePagesInProgress:                        15,
+		CacheopUncachePagesInProgress:                      16,
+		CacheopDissociatePagesInProgress:                   17,
+		CacheevLookupsAndCreationsRejectedLackSpace:        18,
+		CacheevStaleObjectsDeleted:                         19,
+		CacheevRetiredWhenReliquished:                      20,
+		CacheevObjectsCulled:                               21,
+	}
+
+	have, err := getProcFixtures(t).Fscacheinfo()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !reflect.DeepEqual(have, expected) {
+		t.Logf("have: %+v", have)
+		t.Logf("expected: %+v", expected)
+		t.Errorf("structs are not equal")
+	}
+}
diff --git a/iscsi/get_test.go b/iscsi/get_test.go
index f21b1ab..a2c24d8 100644
--- a/iscsi/get_test.go
+++ b/iscsi/get_test.go
@@ -160,45 +160,45 @@ func TestGetStats(t *testing.T) {
 				t.Errorf("unexpected iSCSI iops data :\nwant:\n%v\nhave:\n%v", readTests[i].iops, iops)
 			}
 			if stat.Tpgt[0].Luns[0].Backstore == "rd_mcp" {
-				haveRdmcp, err := sysconfigfs.GetRDMCPPath("119", "ramdisk_lio_1G")
+				have_rdmcp, err := sysconfigfs.GetRDMCPPath("119", "ramdisk_lio_1G")
 				if err != nil {
 					t.Errorf("fail rdmcp error %v", err)
 				}
 				// Name ObjectName
-				wantRdmcp := &iscsi.RDMCP{"rd_mcp_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].ObjectName}
+				want_rdmcp := &iscsi.RDMCP{"rd_mcp_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].ObjectName}
 
-				if !reflect.DeepEqual(wantRdmcp, haveRdmcp) {
-					t.Errorf("unexpected rdmcp data :\nwant:\n%v\nhave:\n%v", wantRdmcp, haveRdmcp)
+				if !reflect.DeepEqual(want_rdmcp, have_rdmcp) {
+					t.Errorf("unexpected rdmcp data :\nwant:\n%v\nhave:\n%v", want_rdmcp, have_rdmcp)
 				}
 			} else if stat.Tpgt[0].Luns[0].Backstore == "iblock" {
-				haveIblock, err := sysconfigfs.GetIblockUdev("0", "block_lio_rbd1")
+				have_iblock, err := sysconfigfs.GetIblockUdev("0", "block_lio_rbd1")
 				if err != nil {
 					t.Errorf("fail iblock error %v", err)
 				}
 				// Name Bnumber ObjectName Iblock
-				wantIblock := &iscsi.IBLOCK{"iblock_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].ObjectName, "/dev/rbd1"}
-				if !reflect.DeepEqual(wantIblock, haveIblock) {
-					t.Errorf("unexpected iblock data :\nwant:\n%v\nhave:\n%v", wantIblock, haveIblock)
+				want_iblock := &iscsi.IBLOCK{"iblock_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].ObjectName, "/dev/rbd1"}
+				if !reflect.DeepEqual(want_iblock, have_iblock) {
+					t.Errorf("unexpected iblock data :\nwant:\n%v\nhave:\n%v", want_iblock, have_iblock)
 				}
 			} else if stat.Tpgt[0].Luns[0].Backstore == "fileio" {
-				haveFileIO, err := sysconfigfs.GetFileioUdev("1", "file_lio_1G")
+				have_fileio, err := sysconfigfs.GetFileioUdev("1", "file_lio_1G")
 				if err != nil {
 					t.Errorf("fail fileio error %v", err)
 				}
 				// Name, Fnumber, ObjectName, Filename
-				wantFileIO := &iscsi.FILEIO{"fileio_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, "file_lio_1G", "/home/iscsi/file_back_1G"}
-				if !reflect.DeepEqual(wantFileIO, haveFileIO) {
-					t.Errorf("unexpected fileio data :\nwant:\n%v\nhave:\n%v", wantFileIO, haveFileIO)
+				want_fileio := &iscsi.FILEIO{"fileio_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, "file_lio_1G", "/home/iscsi/file_back_1G"}
+				if !reflect.DeepEqual(want_fileio, have_fileio) {
+					t.Errorf("unexpected fileio data :\nwant:\n%v\nhave:\n%v", want_fileio, have_fileio)
 				}
 			} else if stat.Tpgt[0].Luns[0].Backstore == "rbd" {
-				haveRBD, err := sysconfigfs.GetRBDMatch("0", "iscsi-images-demo")
+				have_rbd, err := sysconfigfs.GetRBDMatch("0", "iscsi-images-demo")
 				if err != nil {
 					t.Errorf("fail rbd error %v", err)
 				}
 				// Name, Rnumber, Pool, Image
-				wantRBD := &iscsi.RBD{"rbd_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, "iscsi-images", "demo"}
-				if !reflect.DeepEqual(wantRBD, haveRBD) {
-					t.Errorf("unexpected fileio data :\nwant:\n%v\nhave:\n%v", wantRBD, haveRBD)
+				want_rbd := &iscsi.RBD{"rbd_" + stat.Tpgt[0].Luns[0].TypeNumber, stat.Tpgt[0].Luns[0].TypeNumber, "iscsi-images", "demo"}
+				if !reflect.DeepEqual(want_rbd, have_rbd) {
+					t.Errorf("unexpected fileio data :\nwant:\n%v\nhave:\n%v", want_rbd, have_rbd)
 				}
 			}
 		}
diff --git a/mountinfo_test.go b/mountinfo_test.go
index de0ecc1..86fe85e 100644
--- a/mountinfo_test.go
+++ b/mountinfo_test.go
@@ -29,8 +29,8 @@ func TestMountInfo(t *testing.T) {
 			s:       "16 21 0:16 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw",
 			invalid: false,
 			mount: &MountInfo{
-				MountID:        16,
-				ParentID:       21,
+				MountId:        16,
+				ParentId:       21,
 				MajorMinorVer:  "0:16",
 				Root:           "/",
 				MountPoint:     "/sys",
@@ -50,8 +50,8 @@ func TestMountInfo(t *testing.T) {
 			name: "Tmpfs mounted at /run",
 			s:    "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116",
 			mount: &MountInfo{
-				MountID:        225,
-				ParentID:       20,
+				MountId:        225,
+				ParentId:       20,
 				MajorMinorVer:  "0:39",
 				Root:           "/",
 				MountPoint:     "/run/user/112",
@@ -67,8 +67,8 @@ func TestMountInfo(t *testing.T) {
 			name: "Tmpfs mounted at /run, but no optional values",
 			s:    "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime  - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116",
 			mount: &MountInfo{
-				MountID:        225,
-				ParentID:       20,
+				MountId:        225,
+				ParentId:       20,
 				MajorMinorVer:  "0:39",
 				Root:           "/",
 				MountPoint:     "/run/user/112",
@@ -84,8 +84,8 @@ func TestMountInfo(t *testing.T) {
 			name: "Tmpfs mounted at /run, with multiple optional values",
 			s:    "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 master:8 - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116",
 			mount: &MountInfo{
-				MountID:        225,
-				ParentID:       20,
+				MountId:        225,
+				ParentId:       20,
 				MajorMinorVer:  "0:39",
 				Root:           "/",
 				MountPoint:     "/run/user/112",
@@ -101,8 +101,8 @@ func TestMountInfo(t *testing.T) {
 			name: "Tmpfs mounted at /run, with a mixture of valid and invalid optional values",
 			s:    "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 master:8 foo:bar - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116",
 			mount: &MountInfo{
-				MountID:        225,
-				ParentID:       20,
+				MountId:        225,
+				ParentId:       20,
 				MajorMinorVer:  "0:39",
 				Root:           "/",
 				MountPoint:     "/run/user/112",
@@ -118,8 +118,8 @@ func TestMountInfo(t *testing.T) {
 			name: "CIFS mounted at /with/a-hyphen",
 			s:    "454 29 0:87 / /with/a-hyphen rw,relatime shared:255 - cifs //remote-storage/Path rw,vers=3.1.1,cache=strict,username=user,uid=1000,forceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,echo_interval=60,actimeo=1",
 			mount: &MountInfo{
-				MountID:        454,
-				ParentID:       29,
+				MountId:        454,
+				ParentId:       29,
 				MajorMinorVer:  "0:87",
 				Root:           "/",
 				MountPoint:     "/with/a-hyphen",
diff --git a/net_softnet_test.go b/net_softnet_test.go
index f25e09f..5a52131 100644
--- a/net_softnet_test.go
+++ b/net_softnet_test.go
@@ -29,11 +29,7 @@ func TestNetSoftnet(t *testing.T) {
 		Processed:    0x00015c73,
 		Dropped:      0x00020e76,
 		TimeSqueezed: 0xf0000769,
-	},
-		{
-			Processed:    0x01663fb2,
-			TimeSqueezed: 0x0109a4,
-		}}
+	}}
 
 	got, err := fs.NetSoftnetStat()
 	if err != nil {
@@ -44,16 +40,3 @@ func TestNetSoftnet(t *testing.T) {
 		t.Fatalf("unexpected softnet stats(-want +got):\n%s", diff)
 	}
 }
-
-func TestBadSoftnet(t *testing.T) {
-	softNetProcFile = "net/softnet_stat.broken"
-	fs, err := NewFS(procTestFixtures)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	_, err = fs.NetSoftnetStat()
-	if err == nil {
-		t.Fatal("expected error, got nil")
-	}
-}
diff --git a/proc_cgroup_test.go b/proc_cgroup_test.go
deleted file mode 100644
index f530edb..0000000
--- a/proc_cgroup_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2020 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package procfs
-
-import (
-	"reflect"
-	"testing"
-)
-
-func TestParseCgroupString(t *testing.T) {
-	tests := []struct {
-		name      string
-		s         string
-		shouldErr bool
-		cgroup    *Cgroup
-	}{
-		{
-			name:      "cgroups-v1 simple line",
-			s:         "10:rdma:/",
-			shouldErr: false,
-			cgroup: &Cgroup{
-				HierarchyID: 10,
-				Controllers: []string{"rdma"},
-				Path:        "/",
-			},
-		},
-		{
-			name:      "cgroups-v1 multi-hier line",
-			s:         "3:cpu,cpuacct:/user.slice/user-1000.slice/session-10.scope",
-			shouldErr: false,
-			cgroup: &Cgroup{
-				HierarchyID: 3,
-				Controllers: []string{"cpu", "cpuacct"},
-				Path:        "/user.slice/user-1000.slice/session-10.scope",
-			},
-		},
-		{
-			name:      "cgroup-v2 line",
-			s:         "0::/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service",
-			shouldErr: false,
-			cgroup: &Cgroup{
-				HierarchyID: 0,
-				Controllers: nil,
-				Path:        "/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service",
-			},
-		},
-		{
-			name:      "extra fields (such as those added by later kernel versions)",
-			s:         "0::/:foobar",
-			shouldErr: false,
-			cgroup: &Cgroup{
-				HierarchyID: 0,
-				Controllers: nil,
-				Path:        "/",
-			},
-		},
-		{
-			name:      "bad hierarchy ID field",
-			s:         "a:cpu:/",
-			shouldErr: true,
-			cgroup:    nil,
-		},
-	}
-
-	for i, test := range tests {
-		t.Logf("[%02d] test %q", i, test.name)
-
-		cgroup, err := parseCgroupString(test.s)
-
-		if test.shouldErr && err == nil {
-			t.Errorf("%s: expected an error, but none occurred", test.name)
-		}
-		if !test.shouldErr && err != nil {
-			t.Errorf("%s: unexpected error: %v", test.name, err)
-		}
-
-		if want, have := test.cgroup, cgroup; !reflect.DeepEqual(want, have) {
-			t.Errorf("cgroup:\nwant:\n%+v\nhave:\n%+v", want, have)
-		}
-	}
-
-}
diff --git a/proc_maps_test.go b/proc_maps_test.go
deleted file mode 100644
index 9bc8e95..0000000
--- a/proc_maps_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2019 The Prometheus Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build !windows
-
-package procfs
-
-import (
-	"testing"
-
-	"github.com/google/go-cmp/cmp"
-	"golang.org/x/sys/unix"
-)
-
-func TestProcMaps(t *testing.T) {
-	tsts32 := []*ProcMap{
-		{
-			StartAddr: 0x08048000,
-			EndAddr:   0x08089000,
-			Perms:     &ProcMapPermissions{true, false, true, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0x03, 0x01),
-			Inode:     104219,
-			Pathname:  "/bin/tcsh",
-		},
-		{
-			StartAddr: 0x08089000,
-			EndAddr:   0x0808c000,
-			Perms:     &ProcMapPermissions{true, true, false, false, true},
-			Offset:    266240,
-			Dev:       unix.Mkdev(0x03, 0x01),
-			Inode:     104219,
-			Pathname:  "/bin/tcsh",
-		},
-		{
-			StartAddr: 0x0808c000,
-			EndAddr:   0x08146000,
-			Perms:     &ProcMapPermissions{true, true, true, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0x00, 0x00),
-			Inode:     0,
-			Pathname:  "",
-		},
-		{
-			StartAddr: 0x40000000,
-			EndAddr:   0x40015000,
-			Perms:     &ProcMapPermissions{true, false, true, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0x03, 0x01),
-			Inode:     61874,
-			Pathname:  "/lib/ld-2.3.2.so",
-		},
-	}
-
-	tsts64 := []*ProcMap{
-		{
-			StartAddr: 0x55680ae1e000,
-			EndAddr:   0x55680ae20000,
-			Perms:     &ProcMapPermissions{true, false, false, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0xfd, 0x01),
-			Inode:     47316994,
-			Pathname:  "/bin/cat",
-		},
-		{
-			StartAddr: 0x55680ae29000,
-			EndAddr:   0x55680ae2a000,
-			Perms:     &ProcMapPermissions{true, true, true, true, false},
-			Offset:    40960,
-			Dev:       unix.Mkdev(0xfd, 0x01),
-			Inode:     47316994,
-			Pathname:  "/bin/cat",
-		},
-		{
-			StartAddr: 0x55680bed6000,
-			EndAddr:   0x55680bef7000,
-			Perms:     &ProcMapPermissions{true, true, false, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0, 0),
-			Inode:     0,
-			Pathname:  "[heap]",
-		},
-		{
-			StartAddr: 0x7fdf964fc000,
-			EndAddr:   0x7fdf973f2000,
-			Perms:     &ProcMapPermissions{true, false, false, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0xfd, 0x01),
-			Inode:     17432624,
-			Pathname:  "/usr/lib/locale/locale-archive",
-		},
-		{
-			StartAddr: 0x7fdf973f2000,
-			EndAddr:   0x7fdf97417000,
-			Perms:     &ProcMapPermissions{true, false, false, false, true},
-			Offset:    0,
-			Dev:       unix.Mkdev(0xfd, 0x01),
-			Inode:     60571062,
-			Pathname:  "/lib/x86_64-linux-gnu/libc-2.29.so",
-		},
-		{
-			StartAddr: 0x7ffe9215c000,
-			EndAddr:   0x7ffe9217f000,
-			Perms:     &ProcMapPermissions{true, true, false, false, true},
-			Offset:    0,
-			Dev:       0,
-			Inode:     0,
-			Pathname:  "[stack]",
-		},
-		{
-			StartAddr: 0x7ffe921da000,
-			EndAddr:   0x7ffe921dd000,
-			Perms:     &ProcMapPermissions{true, false, false, false, true},
-			Offset:    0,
-			Dev:       0,
-			Inode:     0,
-			Pathname:  "[vvar]",
-		},
-		{
-			StartAddr: 0x7ffe921dd000,
-			EndAddr:   0x7ffe921de000,
-			Perms:     &ProcMapPermissions{true, false, true, false, true},
-			Offset:    0,
-			Dev:       0,
-			Inode:     0,
-			Pathname:  "[vdso]",
-		},
-		{
-			StartAddr: 0xffffffffff600000,
-			EndAddr:   0xffffffffff601000,
-			Perms:     &ProcMapPermissions{false, false, true, false, true},
-			Offset:    0,
-			Dev:       0,
-			Inode:     0,
-			Pathname:  "[vsyscall]",
-		},
-	}
-
-	var (
-		tsts []*ProcMap
-		tpid int
-	)
-
-	if (32 << uintptr(^uintptr(0)>>63)) == 64 {
-		// 64b test pid
-		tpid = 26232
-		tsts = tsts64
-	} else {
-		// 32b test pid
-		tpid = 26234
-		tsts = tsts32
-	}
-
-	p, err := getProcFixtures(t).Proc(tpid)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	maps, err := p.ProcMaps()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if want, have := len(maps), len(tsts); want > have {
-		t.Errorf("want at least %d parsed proc/map entries, have %d", want, have)
-	}
-
-	for idx, tst := range tsts {
-		want, got := tst, maps[idx]
-		if diff := cmp.Diff(want, got); diff != "" {
-			t.Fatalf("unexpected proc/map entry (-want +got):\n%s", diff)
-		}
-	}
-
-}
diff --git a/sysfs/net_class_test.go b/sysfs/net_class_test.go
index 41963db..39a7c27 100644
--- a/sysfs/net_class_test.go
+++ b/sysfs/net_class_test.go
@@ -65,7 +65,7 @@ func TestNetClass(t *testing.T) {
 		linkMode         int64 = 1
 		mtu              int64 = 1500
 		nameAssignType   int64 = 2
-		netDevGroup      int64
+		netDevGroup      int64 = 0
 		speed            int64 = 1000
 		txQueueLen       int64 = 1000
 		netType          int64 = 1