Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Fix concurrent VM creation due to busy device error #712

Merged
merged 1 commit into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/ignite-spawn/ignite-spawn.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/weaveworks/ignite/pkg/apis/ignite/scheme"
"github.com/weaveworks/ignite/pkg/constants"
"github.com/weaveworks/ignite/pkg/container"
dmcleanup "github.com/weaveworks/ignite/pkg/dmlegacy/cleanup"
"github.com/weaveworks/ignite/pkg/dmlegacy"
"github.com/weaveworks/ignite/pkg/prometheus"
"github.com/weaveworks/ignite/pkg/util"
patchutil "github.com/weaveworks/libgitops/pkg/util/patch"
Expand Down Expand Up @@ -60,7 +60,7 @@ func StartVM(vm *api.VM) (err error) {
defer util.DeferErr(&err, func() error { return patchStopped(vm) })

// Remove the snapshot overlay post-run, which also removes the detached backing loop devices
defer util.DeferErr(&err, func() error { return dmcleanup.DeactivateSnapshot(vm) })
defer util.DeferErr(&err, func() error { return dmlegacy.DeactivateSnapshot(vm) })

// Remove the Prometheus socket post-run
defer util.DeferErr(&err, func() error { return os.Remove(metricsSocket) })
Expand Down
25 changes: 23 additions & 2 deletions pkg/dmlegacy/cleanup/deactivate.go → pkg/dmlegacy/deactivate.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
package cleanup
package dmlegacy

import (
"fmt"
"os"
"path/filepath"

"github.com/nightlyone/lockfile"

api "github.com/weaveworks/ignite/pkg/apis/ignite"
"github.com/weaveworks/ignite/pkg/util"
)

// DeactivateSnapshot deactivates the snapshot by removing it with dmsetup
func DeactivateSnapshot(vm *api.VM) error {
// Global lock path.
glpath := filepath.Join(os.TempDir(), snapshotLockFileName)

// Create a lockfile and obtain a lock.
lock, err := lockfile.New(glpath)
if err != nil {
err = fmt.Errorf("failed to create lockfile: %w", err)
return err
}
if err = obtainLock(lock); err != nil {
return err
}
// Release the lock at the end.
defer util.DeferErr(&err, lock.Unlock)

dmArgs := []string{
"remove",
"--verifyudev", // if udevd is not running, dmsetup will manage the device node in /dev/mapper
Expand All @@ -21,6 +42,6 @@ func DeactivateSnapshot(vm *api.VM) error {
dmArgs = append(dmArgs, baseDev)
}

_, err := util.ExecuteCommand("dmsetup", dmArgs...)
_, err = util.ExecuteCommand("dmsetup", dmArgs...)
return err
}
4 changes: 4 additions & 0 deletions pkg/dmlegacy/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func ActivateSnapshot(vm *api.VM) (devicePath string, err error) {
// Serialize this operation by creating a global lock file when creating a
// loop device and release the lock after setting up device mapper using the
// loop device.
// Also, concurrent interactions with device mapper results in the error:
// Device or resource busy
// Serializing the interaction with device mapper helps avoid issues due to
// race conditions.

// Global lock path.
glpath := filepath.Join(os.TempDir(), snapshotLockFileName)
Expand Down
4 changes: 2 additions & 2 deletions pkg/dmlegacy/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"path/filepath"

log "github.com/sirupsen/logrus"

api "github.com/weaveworks/ignite/pkg/apis/ignite"
meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1"
"github.com/weaveworks/ignite/pkg/constants"
"github.com/weaveworks/ignite/pkg/dmlegacy/cleanup"
"github.com/weaveworks/ignite/pkg/operations/lookup"
"github.com/weaveworks/ignite/pkg/providers"
"github.com/weaveworks/ignite/pkg/util"
Expand Down Expand Up @@ -87,7 +87,7 @@ func copyToOverlay(vm *api.VM) (err error) {
if err != nil {
return
}
defer util.DeferErr(&err, func() error { return cleanup.DeactivateSnapshot(vm) })
defer util.DeferErr(&err, func() error { return DeactivateSnapshot(vm) })

mp, err := util.Mount(vm.SnapshotDev())
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/operations/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
api "github.com/weaveworks/ignite/pkg/apis/ignite"
meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1"
"github.com/weaveworks/ignite/pkg/client"
"github.com/weaveworks/ignite/pkg/dmlegacy/cleanup"
"github.com/weaveworks/ignite/pkg/dmlegacy"
"github.com/weaveworks/ignite/pkg/logs"
"github.com/weaveworks/ignite/pkg/providers"
"github.com/weaveworks/ignite/pkg/runtime"
Expand Down Expand Up @@ -50,7 +50,7 @@ func CleanupVM(vm *api.VM) error {
// After removing the VM container, if the Snapshot Device is still there, clean up
if _, err := os.Stat(vm.SnapshotDev()); err == nil {
// try remove it again with DeactivateSnapshot
if err := cleanup.DeactivateSnapshot(vm); err != nil {
if err := dmlegacy.DeactivateSnapshot(vm); err != nil {
return err
}
}
Expand Down