Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

container deletion - EBUSY improvement #1382

Merged
merged 3 commits into from
Oct 13, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 21 additions & 7 deletions pkg/mount/unmount_unix.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
//go:build !windows
// +build !windows

package mount

import "golang.org/x/sys/unix"
import (
"time"

"golang.org/x/sys/unix"
)

func unmount(target string, flags int) error {
err := unix.Unmount(target, flags)
if err == nil || err == unix.EINVAL {
// Ignore "not mounted" error here. Note the same error
// can be returned if flags are invalid, so this code
// assumes that the flags value is always correct.
return nil
var err error
for i := 0; i < 50; i++ {
err = unix.Unmount(target, flags)
switch err {
case unix.EBUSY:
time.Sleep(50 * time.Millisecond)
continue
case unix.EINVAL, nil:
// Ignore "not mounted" error here. Note the same error
// can be returned if flags are invalid, so this code
// assumes that the flags value is always correct.
return nil
default:
break
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From staticcheck as run by VS Code:

ineffective break statement. Did you mean to break out of the outer loop? (SA4011)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting and reporting!

I keep forgetting the break semantics. Opened #1401 to fix it.

}
}

return &mountError{
Expand Down
3 changes: 1 addition & 2 deletions pkg/system/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package system
import (
"fmt"
"os"
"syscall"
"time"

"github.com/containers/storage/pkg/mount"
Expand Down Expand Up @@ -65,7 +64,7 @@ func EnsureRemoveAll(dir string) error {
continue
}

if pe.Err != syscall.EBUSY {
if !IsEBUSY(pe.Err) {
return err
}

Expand Down
118 changes: 61 additions & 57 deletions store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2504,68 +2504,72 @@ func (s *store) DeleteContainer(id string) error {
return err
}

if rcstore.Exists(id) {
if container, err := rcstore.Get(id); err == nil {
errChan := make(chan error)
var wg sync.WaitGroup
if !rcstore.Exists(id) {
return ErrNotAContainer
}

if rlstore.Exists(container.LayerID) {
wg.Add(1)
go func() {
errChan <- rlstore.Delete(container.LayerID)
wg.Done()
}()
}
wg.Add(1)
go func() {
errChan <- rcstore.Delete(id)
wg.Done()
}()

middleDir := s.graphDriverName + "-containers"
gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID)
wg.Add(1)
go func() {
defer wg.Done()
// attempt a simple rm -rf first
err := os.RemoveAll(gcpath)
if err == nil {
errChan <- nil
return
}
// and if it fails get to the more complicated cleanup
errChan <- system.EnsureRemoveAll(gcpath)
}()

rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID)
wg.Add(1)
go func() {
defer wg.Done()
// attempt a simple rm -rf first
err := os.RemoveAll(rcpath)
if err == nil {
errChan <- nil
return
}
// and if it fails get to the more complicated cleanup
errChan <- system.EnsureRemoveAll(rcpath)
}()
container, err := rcstore.Get(id)
if err != nil {
return ErrNotAContainer
}

go func() {
wg.Wait()
close(errChan)
}()
errChan := make(chan error)
var wg sync.WaitGroup

var errors []error
for err := range errChan {
if err != nil {
errors = append(errors, err)
}
}
return multierror.Append(nil, errors...).ErrorOrNil()
if rlstore.Exists(container.LayerID) {
wg.Add(1)
go func() {
errChan <- rlstore.Delete(container.LayerID)
wg.Done()
}()
}
wg.Add(1)
go func() {
errChan <- rcstore.Delete(id)
wg.Done()
}()

middleDir := s.graphDriverName + "-containers"
gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID)
wg.Add(1)
go func() {
defer wg.Done()
// attempt a simple rm -rf first
err := os.RemoveAll(gcpath)
if err == nil {
errChan <- nil
return
}
// and if it fails get to the more complicated cleanup
errChan <- system.EnsureRemoveAll(gcpath)
}()

rcpath := filepath.Join(s.RunRoot(), middleDir, container.ID)
wg.Add(1)
go func() {
defer wg.Done()
// attempt a simple rm -rf first
err := os.RemoveAll(rcpath)
if err == nil {
errChan <- nil
return
}
// and if it fails get to the more complicated cleanup
errChan <- system.EnsureRemoveAll(rcpath)
}()

go func() {
wg.Wait()
close(errChan)
}()

var errors []error
for err := range errChan {
if err != nil {
errors = append(errors, err)
}
}
return ErrNotAContainer
return multierror.Append(nil, errors...).ErrorOrNil()
}

func (s *store) Delete(id string) error {
Expand Down