info: Always refresh the root disk status (#20023)

Add root drive status in the disk info cache function, so unmounting a
drive without restarting a local node reflects the correct value.
This commit is contained in:
Anis Eleuch 2024-07-02 21:41:29 +01:00 committed by GitHub
parent 2040559f71
commit 2ec1f404ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 40 additions and 54 deletions

View File

@ -365,7 +365,7 @@ func getLocalDisksToHeal() (disksToHeal Endpoints) {
localDrives := cloneDrives(globalLocalDrives) localDrives := cloneDrives(globalLocalDrives)
globalLocalDrivesMu.RUnlock() globalLocalDrivesMu.RUnlock()
for _, disk := range localDrives { for _, disk := range localDrives {
_, err := disk.GetDiskID() _, err := disk.DiskInfo(context.Background(), DiskInfoOptions{})
if errors.Is(err, errUnformattedDisk) { if errors.Is(err, errUnformattedDisk) {
disksToHeal = append(disksToHeal, disk.Endpoint()) disksToHeal = append(disksToHeal, disk.Endpoint())
continue continue
@ -393,6 +393,17 @@ func healFreshDisk(ctx context.Context, z *erasureServerPools, endpoint Endpoint
return fmt.Errorf("Unexpected error disk must be initialized by now after formatting: %s", endpoint) return fmt.Errorf("Unexpected error disk must be initialized by now after formatting: %s", endpoint)
} }
_, err := disk.DiskInfo(ctx, DiskInfoOptions{})
if err != nil {
if errors.Is(err, errDriveIsRoot) {
// This is a root drive, ignore and move on
return nil
}
if !errors.Is(err, errUnformattedDisk) {
return err
}
}
// Prevent parallel erasure set healing // Prevent parallel erasure set healing
locker := z.NewNSLock(minioMetaBucket, fmt.Sprintf("new-drive-healing/%d/%d", poolIdx, setIdx)) locker := z.NewNSLock(minioMetaBucket, fmt.Sprintf("new-drive-healing/%d/%d", poolIdx, setIdx))
lkctx, err := locker.GetLock(ctx, newDiskHealingTimeout) lkctx, err := locker.GetLock(ctx, newDiskHealingTimeout)

View File

@ -120,13 +120,6 @@ func connectEndpoint(endpoint Endpoint) (StorageAPI, *formatErasureV3, error) {
format, err := loadFormatErasure(disk, false) format, err := loadFormatErasure(disk, false)
if err != nil { if err != nil {
if errors.Is(err, errUnformattedDisk) {
info, derr := disk.DiskInfo(context.TODO(), DiskInfoOptions{})
if derr != nil && info.RootDisk {
disk.Close()
return nil, nil, fmt.Errorf("Drive: %s is a root drive", disk)
}
}
disk.Close() disk.Close()
return nil, nil, fmt.Errorf("Drive: %s returned %w", disk, err) // make sure to '%w' to wrap the error return nil, nil, fmt.Errorf("Drive: %s returned %w", disk, err) // make sure to '%w' to wrap the error
} }
@ -230,7 +223,7 @@ func (s *erasureSets) connectDisks() {
if err != nil { if err != nil {
if endpoint.IsLocal && errors.Is(err, errUnformattedDisk) { if endpoint.IsLocal && errors.Is(err, errUnformattedDisk) {
globalBackgroundHealState.pushHealLocalDisks(endpoint) globalBackgroundHealState.pushHealLocalDisks(endpoint)
} else { } else if !errors.Is(err, errDriveIsRoot) {
printEndpointError(endpoint, err, true) printEndpointError(endpoint, err, true)
} }
return return

View File

@ -102,6 +102,8 @@ func diskErrToDriveState(err error) (state string) {
state = madmin.DriveStatePermission state = madmin.DriveStatePermission
case errors.Is(err, errFaultyDisk): case errors.Is(err, errFaultyDisk):
state = madmin.DriveStateFaulty state = madmin.DriveStateFaulty
case errors.Is(err, errDriveIsRoot):
state = madmin.DriveStateRootMount
case err == nil: case err == nil:
state = madmin.DriveStateOk state = madmin.DriveStateOk
default: default:

View File

@ -98,12 +98,6 @@ func TestReleaseTagToNFromTimeConversion(t *testing.T) {
} }
func TestDownloadURL(t *testing.T) { func TestDownloadURL(t *testing.T) {
sci := globalIsCICD
globalIsCICD = false
defer func() {
globalIsCICD = sci
}()
minioVersion1 := releaseTimeToReleaseTag(UTCNow()) minioVersion1 := releaseTimeToReleaseTag(UTCNow())
durl := getDownloadURL(minioVersion1) durl := getDownloadURL(minioVersion1)
if IsDocker() { if IsDocker() {
@ -164,9 +158,6 @@ func TestUserAgent(t *testing.T) {
} }
for i, testCase := range testCases { for i, testCase := range testCases {
sci := globalIsCICD
globalIsCICD = false
if testCase.envName != "" { if testCase.envName != "" {
t.Setenv(testCase.envName, testCase.envValue) t.Setenv(testCase.envName, testCase.envValue)
if testCase.envName == "MESOS_CONTAINER_NAME" { if testCase.envName == "MESOS_CONTAINER_NAME" {
@ -182,7 +173,6 @@ func TestUserAgent(t *testing.T) {
if !strings.Contains(str, expectedStr) { if !strings.Contains(str, expectedStr) {
t.Errorf("Test %d: expected: %s, got: %s", i+1, expectedStr, str) t.Errorf("Test %d: expected: %s, got: %s", i+1, expectedStr, str)
} }
globalIsCICD = sci
os.Unsetenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION") os.Unsetenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION")
os.Unsetenv(testCase.envName) os.Unsetenv(testCase.envName)
} }
@ -190,12 +180,6 @@ func TestUserAgent(t *testing.T) {
// Tests if the environment we are running is in DCOS. // Tests if the environment we are running is in DCOS.
func TestIsDCOS(t *testing.T) { func TestIsDCOS(t *testing.T) {
sci := globalIsCICD
globalIsCICD = false
defer func() {
globalIsCICD = sci
}()
t.Setenv("MESOS_CONTAINER_NAME", "mesos-1111") t.Setenv("MESOS_CONTAINER_NAME", "mesos-1111")
dcos := IsDCOS() dcos := IsDCOS()
if !dcos { if !dcos {
@ -210,12 +194,6 @@ func TestIsDCOS(t *testing.T) {
// Tests if the environment we are running is in kubernetes. // Tests if the environment we are running is in kubernetes.
func TestIsKubernetes(t *testing.T) { func TestIsKubernetes(t *testing.T) {
sci := globalIsCICD
globalIsCICD = false
defer func() {
globalIsCICD = sci
}()
t.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5") t.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5")
kubernetes := IsKubernetes() kubernetes := IsKubernetes()
if !kubernetes { if !kubernetes {

View File

@ -236,30 +236,17 @@ func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
return s, err return s, err
} }
info, err := disk.GetInfo(s.drivePath, true) info, rootDrive, err := getDiskInfo(s.drivePath)
if err != nil { if err != nil {
return s, err return s, err
} }
s.major = info.Major s.major = info.Major
s.minor = info.Minor s.minor = info.Minor
s.fsType = info.FSType s.fsType = info.FSType
if !globalIsCICD && !globalIsErasureSD { if rootDrive {
var rootDrive bool return s, errDriveIsRoot
if globalRootDiskThreshold > 0 {
// Use MINIO_ROOTDISK_THRESHOLD_SIZE to figure out if
// this disk is a root disk. treat those disks with
// size less than or equal to the threshold as rootDrives.
rootDrive = info.Total <= globalRootDiskThreshold
} else {
rootDrive, err = disk.IsRootDisk(s.drivePath, SlashSeparator)
if err != nil {
return nil, err
}
}
if rootDrive {
return s, errDriveIsRoot
}
} }
// Sanitize before setting it // Sanitize before setting it
@ -333,10 +320,11 @@ func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
s.diskInfoCache.InitOnce(time.Second, cachevalue.Opts{}, s.diskInfoCache.InitOnce(time.Second, cachevalue.Opts{},
func(ctx context.Context) (DiskInfo, error) { func(ctx context.Context) (DiskInfo, error) {
dcinfo := DiskInfo{} dcinfo := DiskInfo{}
di, err := getDiskInfo(s.drivePath) di, root, err := getDiskInfo(s.drivePath)
if err != nil { if err != nil {
return dcinfo, err return dcinfo, err
} }
dcinfo.RootDisk = root
dcinfo.Major = di.Major dcinfo.Major = di.Major
dcinfo.Minor = di.Minor dcinfo.Minor = di.Minor
dcinfo.Total = di.Total dcinfo.Total = di.Total
@ -345,6 +333,10 @@ func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
dcinfo.UsedInodes = di.Files - di.Ffree dcinfo.UsedInodes = di.Files - di.Ffree
dcinfo.FreeInodes = di.Ffree dcinfo.FreeInodes = di.Ffree
dcinfo.FSType = di.FSType dcinfo.FSType = di.FSType
if root {
return dcinfo, errDriveIsRoot
}
diskID, err := s.GetDiskID() diskID, err := s.GetDiskID()
// Healing is 'true' when // Healing is 'true' when
// - if we found an unformatted disk (no 'format.json') // - if we found an unformatted disk (no 'format.json')
@ -360,10 +352,22 @@ func newXLStorage(ep Endpoint, cleanUp bool) (s *xlStorage, err error) {
} }
// getDiskInfo returns given disk information. // getDiskInfo returns given disk information.
func getDiskInfo(drivePath string) (di disk.Info, err error) { func getDiskInfo(drivePath string) (di disk.Info, rootDrive bool, err error) {
if err = checkPathLength(drivePath); err == nil { if err = checkPathLength(drivePath); err == nil {
di, err = disk.GetInfo(drivePath, false) di, err = disk.GetInfo(drivePath, false)
if !globalIsCICD && !globalIsErasureSD {
if globalRootDiskThreshold > 0 {
// Use MINIO_ROOTDISK_THRESHOLD_SIZE to figure out if
// this disk is a root disk. treat those disks with
// size less than or equal to the threshold as rootDrives.
rootDrive = di.Total <= globalRootDiskThreshold
} else {
rootDrive, err = disk.IsRootDisk(drivePath, SlashSeparator)
}
}
} }
switch { switch {
case osIsNotExist(err): case osIsNotExist(err):
err = errDiskNotFound err = errDiskNotFound
@ -373,7 +377,7 @@ func getDiskInfo(drivePath string) (di disk.Info, err error) {
err = errFaultyDisk err = errFaultyDisk
} }
return di, err return
} }
// Implements stringer compatible interface. // Implements stringer compatible interface.

View File

@ -196,7 +196,7 @@ func TestXLStorageGetDiskInfo(t *testing.T) {
// Check test cases. // Check test cases.
for _, testCase := range testCases { for _, testCase := range testCases {
if _, err := getDiskInfo(testCase.diskPath); err != testCase.expectedErr { if _, _, err := getDiskInfo(testCase.diskPath); err != testCase.expectedErr {
t.Fatalf("expected: %s, got: %s", testCase.expectedErr, err) t.Fatalf("expected: %s, got: %s", testCase.expectedErr, err)
} }
} }

2
go.sum
View File

@ -456,8 +456,6 @@ github.com/minio/kms-go/kes v0.3.0 h1:SU8VGVM/Hk9w1OiSby3OatkcojooUqIdDHl6dtM6Nk
github.com/minio/kms-go/kes v0.3.0/go.mod h1:w6DeVT878qEOU3nUrYVy1WOT5H1Ig9hbDIh698NYJKY= github.com/minio/kms-go/kes v0.3.0/go.mod h1:w6DeVT878qEOU3nUrYVy1WOT5H1Ig9hbDIh698NYJKY=
github.com/minio/kms-go/kms v0.4.0 h1:cLPZceEp+05xHotVBaeFJrgL7JcXM4lBy6PU0idkE7I= github.com/minio/kms-go/kms v0.4.0 h1:cLPZceEp+05xHotVBaeFJrgL7JcXM4lBy6PU0idkE7I=
github.com/minio/kms-go/kms v0.4.0/go.mod h1:q12CehiIy2qgBnDKq6Q7wmPi2PHSyRVug5DKp0HAVeE= github.com/minio/kms-go/kms v0.4.0/go.mod h1:q12CehiIy2qgBnDKq6Q7wmPi2PHSyRVug5DKp0HAVeE=
github.com/minio/madmin-go/v3 v3.0.57 h1:fXoOnYP8/k9x0MWWowXkAQWYu59hongieCcT3urUaAQ=
github.com/minio/madmin-go/v3 v3.0.57/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw=
github.com/minio/madmin-go/v3 v3.0.58-0.20240701162942-671010069ecb h1:6Hx1+R0GR79Vt4gOKgadH4OG8tkrq/UNyxfmR1C7C14= github.com/minio/madmin-go/v3 v3.0.58-0.20240701162942-671010069ecb h1:6Hx1+R0GR79Vt4gOKgadH4OG8tkrq/UNyxfmR1C7C14=
github.com/minio/madmin-go/v3 v3.0.58-0.20240701162942-671010069ecb/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw= github.com/minio/madmin-go/v3 v3.0.58-0.20240701162942-671010069ecb/go.mod h1:IFAwr0XMrdsLovxAdCcuq/eoL4nRuMVQQv0iubJANQw=
github.com/minio/mc v0.0.0-20240612143403-e7c9a733c680 h1:Ns5mhSm86qJx6a9GJ1kzHkZMjRMZrQGsptakVRmq4QA= github.com/minio/mc v0.0.0-20240612143403-e7c9a733c680 h1:Ns5mhSm86qJx6a9GJ1kzHkZMjRMZrQGsptakVRmq4QA=