mirror of
https://github.com/minio/minio.git
synced 2025-01-11 15:03:22 -05:00
XL/heal: heal missing format.json on replaced drives. (#1828)
fixes #1817
This commit is contained in:
parent
116b5607d7
commit
9b79760dcf
@ -143,11 +143,104 @@ func loadFormat(disk StorageAPI) (format *formatConfigV1, err error) {
|
||||
return format, nil
|
||||
}
|
||||
|
||||
// Heals any missing format.json on the drives. Returns error only for unexpected errors
|
||||
// as regular errors can be ignored since there might be enough quorum to be operational.
|
||||
func healFormatXL(bootstrapDisks []StorageAPI) error {
|
||||
uuidUsage := make([]struct {
|
||||
uuid string // Disk uuid
|
||||
inuse bool // indicates if the uuid is used by any disk
|
||||
}, len(bootstrapDisks))
|
||||
|
||||
needHeal := make([]bool, len(bootstrapDisks)) // Slice indicating which drives needs healing.
|
||||
|
||||
// Returns any unused drive UUID.
|
||||
getUnusedUUID := func() string {
|
||||
for index := range uuidUsage {
|
||||
if !uuidUsage[index].inuse {
|
||||
uuidUsage[index].inuse = true
|
||||
return uuidUsage[index].uuid
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
formatConfigs := make([]*formatConfigV1, len(bootstrapDisks))
|
||||
var referenceConfig *formatConfigV1
|
||||
for index, disk := range bootstrapDisks {
|
||||
formatXL, err := loadFormat(disk)
|
||||
if err == errUnformattedDisk {
|
||||
// format.json is missing, should be healed.
|
||||
needHeal[index] = true
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
if referenceConfig == nil {
|
||||
// this config will be used to update the drives missing format.json
|
||||
referenceConfig = formatXL
|
||||
}
|
||||
formatConfigs[index] = formatXL
|
||||
} else {
|
||||
// Abort format.json healing if any one of the drives is not available because we don't
|
||||
// know if that drive is down permanently or temporarily. So we don't want to reuse
|
||||
// its uuid for any other disks.
|
||||
// Return nil so that operations can continue if quorum is available.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if referenceConfig == nil {
|
||||
// All disks are fresh, format.json will be written by initFormatXL()
|
||||
return nil
|
||||
}
|
||||
for index, diskUUID := range referenceConfig.XL.JBOD {
|
||||
uuidUsage[index].uuid = diskUUID
|
||||
uuidUsage[index].inuse = false
|
||||
}
|
||||
for _, config := range formatConfigs {
|
||||
if config == nil {
|
||||
continue
|
||||
}
|
||||
for index := range uuidUsage {
|
||||
if config.XL.Disk == uuidUsage[index].uuid {
|
||||
uuidUsage[index].inuse = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for index, heal := range needHeal {
|
||||
if !heal {
|
||||
// Previously we detected that heal is not needed on the disk.
|
||||
continue
|
||||
}
|
||||
config := &formatConfigV1{}
|
||||
*config = *referenceConfig
|
||||
config.XL.Disk = getUnusedUUID()
|
||||
if config.XL.Disk == "" {
|
||||
// getUnusedUUID() should have returned an unused uuid, if not return error.
|
||||
return errUnexpected
|
||||
}
|
||||
|
||||
formatBytes, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Fresh disk without format.json
|
||||
_, _ = bootstrapDisks[index].AppendFile(minioMetaBucket, formatConfigFile, formatBytes)
|
||||
// Ignore any error from AppendFile() as quorum might still be there to be operational.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadFormatXL - load XL format.json.
|
||||
func loadFormatXL(bootstrapDisks []StorageAPI) (disks []StorageAPI, err error) {
|
||||
var unformattedDisksFoundCnt = 0
|
||||
var diskNotFoundCount = 0
|
||||
formatConfigs := make([]*formatConfigV1, len(bootstrapDisks))
|
||||
|
||||
// Heal missing format.json on the drives.
|
||||
if err = healFormatXL(bootstrapDisks); err != nil {
|
||||
// There was an unexpected unrecoverable error during healing.
|
||||
return
|
||||
}
|
||||
|
||||
for index, disk := range bootstrapDisks {
|
||||
var formatXL *formatConfigV1
|
||||
formatXL, err = loadFormat(disk)
|
||||
|
Loading…
Reference in New Issue
Block a user