1// Copyright 2019 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package procfs 15 16import ( 17 "bufio" 18 "bytes" 19 "fmt" 20 "io" 21 "strconv" 22 "strings" 23 24 "github.com/prometheus/procfs/internal/util" 25) 26 27// Fscacheinfo represents fscache statistics. 28type Fscacheinfo struct { 29 // Number of index cookies allocated 30 IndexCookiesAllocated uint64 31 // data storage cookies allocated 32 DataStorageCookiesAllocated uint64 33 // Number of special cookies allocated 34 SpecialCookiesAllocated uint64 35 // Number of objects allocated 36 ObjectsAllocated uint64 37 // Number of object allocation failures 38 ObjectAllocationsFailure uint64 39 // Number of objects that reached the available state 40 ObjectsAvailable uint64 41 // Number of objects that reached the dead state 42 ObjectsDead uint64 43 // Number of objects that didn't have a coherency check 44 ObjectsWithoutCoherencyCheck uint64 45 // Number of objects that passed a coherency check 46 ObjectsWithCoherencyCheck uint64 47 // Number of objects that needed a coherency data update 48 ObjectsNeedCoherencyCheckUpdate uint64 49 // Number of objects that were declared obsolete 50 ObjectsDeclaredObsolete uint64 51 // Number of pages marked as being cached 52 PagesMarkedAsBeingCached uint64 53 // Number of uncache page requests seen 54 UncachePagesRequestSeen uint64 55 // Number of acquire cookie requests seen 56 AcquireCookiesRequestSeen uint64 57 // Number of acq reqs given a NULL parent 58 AcquireRequestsWithNullParent uint64 59 // Number of acq reqs rejected due to no cache available 60 AcquireRequestsRejectedNoCacheAvailable uint64 61 // Number of acq reqs succeeded 62 AcquireRequestsSucceeded uint64 63 // Number of acq reqs rejected due to error 64 AcquireRequestsRejectedDueToError uint64 65 // Number of acq reqs failed on ENOMEM 66 AcquireRequestsFailedDueToEnomem uint64 67 // Number of lookup calls made on cache backends 68 LookupsNumber uint64 69 // Number of negative lookups made 70 LookupsNegative uint64 71 // Number of positive lookups made 72 LookupsPositive uint64 73 // Number of objects created by lookup 74 ObjectsCreatedByLookup uint64 75 // Number of lookups timed out and requeued 76 LookupsTimedOutAndRequed uint64 77 InvalidationsNumber uint64 78 InvalidationsRunning uint64 79 // Number of update cookie requests seen 80 UpdateCookieRequestSeen uint64 81 // Number of upd reqs given a NULL parent 82 UpdateRequestsWithNullParent uint64 83 // Number of upd reqs granted CPU time 84 UpdateRequestsRunning uint64 85 // Number of relinquish cookie requests seen 86 RelinquishCookiesRequestSeen uint64 87 // Number of rlq reqs given a NULL parent 88 RelinquishCookiesWithNullParent uint64 89 // Number of rlq reqs waited on completion of creation 90 RelinquishRequestsWaitingCompleteCreation uint64 91 // Relinqs rtr 92 RelinquishRetries uint64 93 // Number of attribute changed requests seen 94 AttributeChangedRequestsSeen uint64 95 // Number of attr changed requests queued 96 AttributeChangedRequestsQueued uint64 97 // Number of attr changed rejected -ENOBUFS 98 AttributeChangedRejectDueToEnobufs uint64 99 // Number of attr changed failed -ENOMEM 100 AttributeChangedFailedDueToEnomem uint64 101 // Number of attr changed ops given CPU time 102 AttributeChangedOps uint64 103 // Number of allocation requests seen 104 AllocationRequestsSeen uint64 105 // Number of successful alloc reqs 106 AllocationOkRequests uint64 107 // Number of alloc reqs that waited on lookup completion 108 AllocationWaitingOnLookup uint64 109 // Number of alloc reqs rejected -ENOBUFS 110 AllocationsRejectedDueToEnobufs uint64 111 // Number of alloc reqs aborted -ERESTARTSYS 112 AllocationsAbortedDueToErestartsys uint64 113 // Number of alloc reqs submitted 114 AllocationOperationsSubmitted uint64 115 // Number of alloc reqs waited for CPU time 116 AllocationsWaitedForCPU uint64 117 // Number of alloc reqs aborted due to object death 118 AllocationsAbortedDueToObjectDeath uint64 119 // Number of retrieval (read) requests seen 120 RetrievalsReadRequests uint64 121 // Number of successful retr reqs 122 RetrievalsOk uint64 123 // Number of retr reqs that waited on lookup completion 124 RetrievalsWaitingLookupCompletion uint64 125 // Number of retr reqs returned -ENODATA 126 RetrievalsReturnedEnodata uint64 127 // Number of retr reqs rejected -ENOBUFS 128 RetrievalsRejectedDueToEnobufs uint64 129 // Number of retr reqs aborted -ERESTARTSYS 130 RetrievalsAbortedDueToErestartsys uint64 131 // Number of retr reqs failed -ENOMEM 132 RetrievalsFailedDueToEnomem uint64 133 // Number of retr reqs submitted 134 RetrievalsRequests uint64 135 // Number of retr reqs waited for CPU time 136 RetrievalsWaitingCPU uint64 137 // Number of retr reqs aborted due to object death 138 RetrievalsAbortedDueToObjectDeath uint64 139 // Number of storage (write) requests seen 140 StoreWriteRequests uint64 141 // Number of successful store reqs 142 StoreSuccessfulRequests uint64 143 // Number of store reqs on a page already pending storage 144 StoreRequestsOnPendingStorage uint64 145 // Number of store reqs rejected -ENOBUFS 146 StoreRequestsRejectedDueToEnobufs uint64 147 // Number of store reqs failed -ENOMEM 148 StoreRequestsFailedDueToEnomem uint64 149 // Number of store reqs submitted 150 StoreRequestsSubmitted uint64 151 // Number of store reqs granted CPU time 152 StoreRequestsRunning uint64 153 // Number of pages given store req processing time 154 StorePagesWithRequestsProcessing uint64 155 // Number of store reqs deleted from tracking tree 156 StoreRequestsDeleted uint64 157 // Number of store reqs over store limit 158 StoreRequestsOverStoreLimit uint64 159 // Number of release reqs against pages with no pending store 160 ReleaseRequestsAgainstPagesWithNoPendingStorage uint64 161 // Number of release reqs against pages stored by time lock granted 162 ReleaseRequestsAgainstPagesStoredByTimeLockGranted uint64 163 // Number of release reqs ignored due to in-progress store 164 ReleaseRequestsIgnoredDueToInProgressStore uint64 165 // Number of page stores cancelled due to release req 166 PageStoresCancelledByReleaseRequests uint64 167 VmscanWaiting uint64 168 // Number of times async ops added to pending queues 169 OpsPending uint64 170 // Number of times async ops given CPU time 171 OpsRunning uint64 172 // Number of times async ops queued for processing 173 OpsEnqueued uint64 174 // Number of async ops cancelled 175 OpsCancelled uint64 176 // Number of async ops rejected due to object lookup/create failure 177 OpsRejected uint64 178 // Number of async ops initialised 179 OpsInitialised uint64 180 // Number of async ops queued for deferred release 181 OpsDeferred uint64 182 // Number of async ops released (should equal ini=N when idle) 183 OpsReleased uint64 184 // Number of deferred-release async ops garbage collected 185 OpsGarbageCollected uint64 186 // Number of in-progress alloc_object() cache ops 187 CacheopAllocationsinProgress uint64 188 // Number of in-progress lookup_object() cache ops 189 CacheopLookupObjectInProgress uint64 190 // Number of in-progress lookup_complete() cache ops 191 CacheopLookupCompleteInPorgress uint64 192 // Number of in-progress grab_object() cache ops 193 CacheopGrabObjectInProgress uint64 194 CacheopInvalidations uint64 195 // Number of in-progress update_object() cache ops 196 CacheopUpdateObjectInProgress uint64 197 // Number of in-progress drop_object() cache ops 198 CacheopDropObjectInProgress uint64 199 // Number of in-progress put_object() cache ops 200 CacheopPutObjectInProgress uint64 201 // Number of in-progress attr_changed() cache ops 202 CacheopAttributeChangeInProgress uint64 203 // Number of in-progress sync_cache() cache ops 204 CacheopSyncCacheInProgress uint64 205 // Number of in-progress read_or_alloc_page() cache ops 206 CacheopReadOrAllocPageInProgress uint64 207 // Number of in-progress read_or_alloc_pages() cache ops 208 CacheopReadOrAllocPagesInProgress uint64 209 // Number of in-progress allocate_page() cache ops 210 CacheopAllocatePageInProgress uint64 211 // Number of in-progress allocate_pages() cache ops 212 CacheopAllocatePagesInProgress uint64 213 // Number of in-progress write_page() cache ops 214 CacheopWritePagesInProgress uint64 215 // Number of in-progress uncache_page() cache ops 216 CacheopUncachePagesInProgress uint64 217 // Number of in-progress dissociate_pages() cache ops 218 CacheopDissociatePagesInProgress uint64 219 // Number of object lookups/creations rejected due to lack of space 220 CacheevLookupsAndCreationsRejectedLackSpace uint64 221 // Number of stale objects deleted 222 CacheevStaleObjectsDeleted uint64 223 // Number of objects retired when relinquished 224 CacheevRetiredWhenReliquished uint64 225 // Number of objects culled 226 CacheevObjectsCulled uint64 227} 228 229// Fscacheinfo returns information about current fscache statistics. 230// See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt 231func (fs FS) Fscacheinfo() (Fscacheinfo, error) { 232 b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats")) 233 if err != nil { 234 return Fscacheinfo{}, err 235 } 236 237 m, err := parseFscacheinfo(bytes.NewReader(b)) 238 if err != nil { 239 return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err) 240 } 241 242 return *m, nil 243} 244 245func setFSCacheFields(fields []string, setFields ...*uint64) error { 246 var err error 247 if len(fields) < len(setFields) { 248 return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields)) 249 } 250 251 for i := range setFields { 252 *setFields[i], err = strconv.ParseUint(strings.Split(fields[i], "=")[1], 0, 64) 253 if err != nil { 254 return err 255 } 256 } 257 return nil 258} 259 260func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) { 261 var m Fscacheinfo 262 s := bufio.NewScanner(r) 263 for s.Scan() { 264 fields := strings.Fields(s.Text()) 265 if len(fields) < 2 { 266 return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text()) 267 } 268 269 switch fields[0] { 270 case "Cookies:": 271 err := setFSCacheFields(fields[1:], &m.IndexCookiesAllocated, &m.DataStorageCookiesAllocated, 272 &m.SpecialCookiesAllocated) 273 if err != nil { 274 return &m, err 275 } 276 case "Objects:": 277 err := setFSCacheFields(fields[1:], &m.ObjectsAllocated, &m.ObjectAllocationsFailure, 278 &m.ObjectsAvailable, &m.ObjectsDead) 279 if err != nil { 280 return &m, err 281 } 282 case "ChkAux": 283 err := setFSCacheFields(fields[2:], &m.ObjectsWithoutCoherencyCheck, &m.ObjectsWithCoherencyCheck, 284 &m.ObjectsNeedCoherencyCheckUpdate, &m.ObjectsDeclaredObsolete) 285 if err != nil { 286 return &m, err 287 } 288 case "Pages": 289 err := setFSCacheFields(fields[2:], &m.PagesMarkedAsBeingCached, &m.UncachePagesRequestSeen) 290 if err != nil { 291 return &m, err 292 } 293 case "Acquire:": 294 err := setFSCacheFields(fields[1:], &m.AcquireCookiesRequestSeen, &m.AcquireRequestsWithNullParent, 295 &m.AcquireRequestsRejectedNoCacheAvailable, &m.AcquireRequestsSucceeded, &m.AcquireRequestsRejectedDueToError, 296 &m.AcquireRequestsFailedDueToEnomem) 297 if err != nil { 298 return &m, err 299 } 300 case "Lookups:": 301 err := setFSCacheFields(fields[1:], &m.LookupsNumber, &m.LookupsNegative, &m.LookupsPositive, 302 &m.ObjectsCreatedByLookup, &m.LookupsTimedOutAndRequed) 303 if err != nil { 304 return &m, err 305 } 306 case "Invals": 307 err := setFSCacheFields(fields[2:], &m.InvalidationsNumber, &m.InvalidationsRunning) 308 if err != nil { 309 return &m, err 310 } 311 case "Updates:": 312 err := setFSCacheFields(fields[1:], &m.UpdateCookieRequestSeen, &m.UpdateRequestsWithNullParent, 313 &m.UpdateRequestsRunning) 314 if err != nil { 315 return &m, err 316 } 317 case "Relinqs:": 318 err := setFSCacheFields(fields[1:], &m.RelinquishCookiesRequestSeen, &m.RelinquishCookiesWithNullParent, 319 &m.RelinquishRequestsWaitingCompleteCreation, &m.RelinquishRetries) 320 if err != nil { 321 return &m, err 322 } 323 case "AttrChg:": 324 err := setFSCacheFields(fields[1:], &m.AttributeChangedRequestsSeen, &m.AttributeChangedRequestsQueued, 325 &m.AttributeChangedRejectDueToEnobufs, &m.AttributeChangedFailedDueToEnomem, &m.AttributeChangedOps) 326 if err != nil { 327 return &m, err 328 } 329 case "Allocs": 330 if strings.Split(fields[2], "=")[0] == "n" { 331 err := setFSCacheFields(fields[2:], &m.AllocationRequestsSeen, &m.AllocationOkRequests, 332 &m.AllocationWaitingOnLookup, &m.AllocationsRejectedDueToEnobufs, &m.AllocationsAbortedDueToErestartsys) 333 if err != nil { 334 return &m, err 335 } 336 } else { 337 err := setFSCacheFields(fields[2:], &m.AllocationOperationsSubmitted, &m.AllocationsWaitedForCPU, 338 &m.AllocationsAbortedDueToObjectDeath) 339 if err != nil { 340 return &m, err 341 } 342 } 343 case "Retrvls:": 344 if strings.Split(fields[1], "=")[0] == "n" { 345 err := setFSCacheFields(fields[1:], &m.RetrievalsReadRequests, &m.RetrievalsOk, &m.RetrievalsWaitingLookupCompletion, 346 &m.RetrievalsReturnedEnodata, &m.RetrievalsRejectedDueToEnobufs, &m.RetrievalsAbortedDueToErestartsys, 347 &m.RetrievalsFailedDueToEnomem) 348 if err != nil { 349 return &m, err 350 } 351 } else { 352 err := setFSCacheFields(fields[1:], &m.RetrievalsRequests, &m.RetrievalsWaitingCPU, &m.RetrievalsAbortedDueToObjectDeath) 353 if err != nil { 354 return &m, err 355 } 356 } 357 case "Stores": 358 if strings.Split(fields[2], "=")[0] == "n" { 359 err := setFSCacheFields(fields[2:], &m.StoreWriteRequests, &m.StoreSuccessfulRequests, 360 &m.StoreRequestsOnPendingStorage, &m.StoreRequestsRejectedDueToEnobufs, &m.StoreRequestsFailedDueToEnomem) 361 if err != nil { 362 return &m, err 363 } 364 } else { 365 err := setFSCacheFields(fields[2:], &m.StoreRequestsSubmitted, &m.StoreRequestsRunning, 366 &m.StorePagesWithRequestsProcessing, &m.StoreRequestsDeleted, &m.StoreRequestsOverStoreLimit) 367 if err != nil { 368 return &m, err 369 } 370 } 371 case "VmScan": 372 err := setFSCacheFields(fields[2:], &m.ReleaseRequestsAgainstPagesWithNoPendingStorage, 373 &m.ReleaseRequestsAgainstPagesStoredByTimeLockGranted, &m.ReleaseRequestsIgnoredDueToInProgressStore, 374 &m.PageStoresCancelledByReleaseRequests, &m.VmscanWaiting) 375 if err != nil { 376 return &m, err 377 } 378 case "Ops": 379 if strings.Split(fields[2], "=")[0] == "pend" { 380 err := setFSCacheFields(fields[2:], &m.OpsPending, &m.OpsRunning, &m.OpsEnqueued, &m.OpsCancelled, &m.OpsRejected) 381 if err != nil { 382 return &m, err 383 } 384 } else { 385 err := setFSCacheFields(fields[2:], &m.OpsInitialised, &m.OpsDeferred, &m.OpsReleased, &m.OpsGarbageCollected) 386 if err != nil { 387 return &m, err 388 } 389 } 390 case "CacheOp:": 391 if strings.Split(fields[1], "=")[0] == "alo" { 392 err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress, 393 &m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress) 394 if err != nil { 395 return &m, err 396 } 397 } else if strings.Split(fields[1], "=")[0] == "inv" { 398 err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress, 399 &m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress, 400 &m.CacheopSyncCacheInProgress) 401 if err != nil { 402 return &m, err 403 } 404 } else { 405 err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress, 406 &m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress, 407 &m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress) 408 if err != nil { 409 return &m, err 410 } 411 } 412 case "CacheEv:": 413 err := setFSCacheFields(fields[1:], &m.CacheevLookupsAndCreationsRejectedLackSpace, &m.CacheevStaleObjectsDeleted, 414 &m.CacheevRetiredWhenReliquished, &m.CacheevObjectsCulled) 415 if err != nil { 416 return &m, err 417 } 418 } 419 } 420 421 return &m, nil 422} 423