Skip to content

Commit

Permalink
Do not mount unassembled dmraid arrays
Browse files Browse the repository at this point in the history
Some of the dmraid device configurations might exist in non-safe
(non-working) mode. An example is an array is constructed incrementally from
multiple devices. The first device creates an array that is reported via
udev, but this array is not usable, it needs more block devices added to
start serving I/O.

Instead of starting to use an mdarray at "add" udev device we have to
check whether 'mdadm --incremental' actually starts the array. Use 'mdadm
--export' to get status of the array and mount it only when MD_STARTED
property is set (i.e. array is live).

Fixes #97
  • Loading branch information
anatol committed Aug 31, 2021
1 parent 6cc11b2 commit 4063cc2
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 37 deletions.
23 changes: 17 additions & 6 deletions init/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ var (
// from subsystem “block”.
func addBlockDevice(devname string) error {
// Some devices might receive multiple udev add events
// Avoid processing these node twice by tracking what has been added already
// Avoid processing these nodes twice by tracking what has been added already
addedDevicesMutex.Lock()
if _, ok := addedDevices[devname]; ok {
addedDevicesMutex.Unlock()
Expand Down Expand Up @@ -190,12 +190,23 @@ func handleMdraidBlockDevice(info *blkInfo, devpath string) error {
return fmt.Errorf("unknown raid level for device %s", devpath)
}

cmd := exec.Command("mdadm", "--incremental", devpath)
if verbosityLevel >= levelDebug {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
out, err := exec.Command("mdadm", "--export", "--incremental", devpath).CombinedOutput()
if err != nil {
return err
}
return cmd.Run()

props := parseProperties(string(out))
arrayName, hasArrayName := props["MD_DEVNAME"]
if !hasArrayName {
return fmt.Errorf("mdraid array at %s does not have a MD_DEVNAME property", info.uuid.toString())
}

if started, ok := props["MD_STARTED"]; !ok || started != "yes" {
debug("mdraid array %s is not complete, ignore it", arrayName)
return nil
}

return addBlockDevice("md/" + arrayName)
} else {
debug("MdRaid support is disabled, ignoring mdraid device %s", devpath)
return nil
Expand Down
31 changes: 0 additions & 31 deletions init/udev.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"log"
"net"
"os"
"os/exec"
"path"
"regexp"
"strconv"
Expand Down Expand Up @@ -142,7 +141,6 @@ func handleNetworkUevent(ev *uevent.Uevent) error {

var (
dmNameRe = regexp.MustCompile(`dm-\d+`)
mdNameRe = regexp.MustCompile(`md\d+`)
)

func handleBlockDeviceUevent(ev *uevent.Uevent) error {
Expand All @@ -157,42 +155,13 @@ func handleBlockDeviceUevent(ev *uevent.Uevent) error {
return err
}

if mdNameRe.MatchString(devName) {
return handleMdRaidUevent(ev)
}

if ev.Action == "add" {
return addBlockDevice(devName)
}

return nil
}

func handleMdRaidUevent(ev *uevent.Uevent) error {
devName := ev.Vars["DEVNAME"]

if err := addBlockDevice(devName); err != nil {
return err
}

// for mdraid there is a special case - add /dev/md/ArrayName symlink
out, err := exec.Command("mdadm", "--export", "--detail", "/dev/"+devName).CombinedOutput()
if err != nil {
return err
}

props := parseProperties(string(out))
if n, ok := props["MD_DEVNAME"]; ok {
if err := addBlockDevice("md/" + n); err != nil {
return err
}
} else {
return fmt.Errorf("mdraid array %s does not have a MD_DEVNAME property", devName)
}

return nil
}

var errIgnoredMapperEvent = fmt.Errorf("ignored device mapper event")

// handleMapperDeviceUevent handles device mapper related uevent
Expand Down

0 comments on commit 4063cc2

Please sign in to comment.