File: //proc/thread-self/root/opt/go/pkg/mod/github.com/prometheus/
[email protected]/sysfs/mdraid.go
// Copyright 2023 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.
//go:build linux
// +build linux
package sysfs
import (
"fmt"
"path/filepath"
"strings"
"github.com/prometheus/procfs/internal/util"
)
// Mdraid holds info parsed from relevant files in the /sys/block/md*/md directory.
type Mdraid struct {
Device string // Kernel device name of array.
Level string // mdraid level.
ArrayState string // State of the array.
MetadataVersion string // mdraid metadata version.
Disks uint64 // Number of devices in a fully functional array.
Components []MdraidComponent // mdraid component devices.
UUID string // UUID of the array.
// The following item is only valid for raid0, 4, 5, 6 and 10.
ChunkSize uint64 // Chunk size
// The following items are only valid for raid1, 4, 5, 6 and 10.
DegradedDisks uint64 // Number of degraded disks in the array.
SyncAction string // Current sync action.
SyncCompleted float64 // Fraction (0-1) representing the completion status of current sync operation.
}
type MdraidComponent struct {
Device string // Kernel device name.
State string // Current state of device.
}
// Mdraids gathers information and statistics about mdraid devices present. Based on upstream
// kernel documentation https://docs.kernel.org/admin-guide/md.html.
func (fs FS) Mdraids() ([]Mdraid, error) {
matches, err := filepath.Glob(fs.sys.Path("block/md*/md"))
if err != nil {
return nil, err
}
mdraids := make([]Mdraid, 0)
for _, m := range matches {
md := Mdraid{Device: filepath.Base(filepath.Dir(m))}
path := fs.sys.Path("block", md.Device, "md")
if val, err := util.SysReadFile(filepath.Join(path, "level")); err == nil {
md.Level = val
} else {
return mdraids, err
}
// Array state can be one of: clear, inactive, readonly, read-auto, clean, active,
// write-pending, active-idle.
if val, err := util.SysReadFile(filepath.Join(path, "array_state")); err == nil {
md.ArrayState = val
} else {
return mdraids, err
}
if val, err := util.SysReadFile(filepath.Join(path, "metadata_version")); err == nil {
md.MetadataVersion = val
} else {
return mdraids, err
}
if val, err := util.ReadUintFromFile(filepath.Join(path, "raid_disks")); err == nil {
md.Disks = val
} else {
return mdraids, err
}
if val, err := util.SysReadFile(filepath.Join(path, "uuid")); err == nil {
md.UUID = val
} else {
return mdraids, err
}
if devs, err := filepath.Glob(filepath.Join(path, "dev-*")); err == nil {
for _, dev := range devs {
comp := MdraidComponent{Device: strings.TrimPrefix(filepath.Base(dev), "dev-")}
// Component state can be a comma-separated list of: faulty, in_sync, writemostly,
// blocked, spare, write_error, want_replacement, replacement.
if val, err := util.SysReadFile(filepath.Join(dev, "state")); err == nil {
comp.State = val
} else {
return mdraids, err
}
md.Components = append(md.Components, comp)
}
} else {
return mdraids, err
}
switch md.Level {
case "raid0", "raid4", "raid5", "raid6", "raid10":
if val, err := util.ReadUintFromFile(filepath.Join(path, "chunk_size")); err == nil {
md.ChunkSize = val
} else {
return mdraids, err
}
}
switch md.Level {
case "raid1", "raid4", "raid5", "raid6", "raid10":
if val, err := util.ReadUintFromFile(filepath.Join(path, "degraded")); err == nil {
md.DegradedDisks = val
} else {
return mdraids, err
}
// Array sync action can be one of: resync, recover, idle, check, repair.
if val, err := util.SysReadFile(filepath.Join(path, "sync_action")); err == nil {
md.SyncAction = val
} else {
return mdraids, err
}
if val, err := util.SysReadFile(filepath.Join(path, "sync_completed")); err == nil {
if val != "none" {
var a, b uint64
// File contains two values representing the fraction of number of completed
// sectors divided by number of total sectors to process.
if _, err := fmt.Sscanf(val, "%d / %d", &a, &b); err == nil {
md.SyncCompleted = float64(a) / float64(b)
} else {
return mdraids, err
}
}
} else {
return mdraids, err
}
}
mdraids = append(mdraids, md)
}
return mdraids, nil
}