-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'rm_container' into 'huawei-1.11.2'
Do not remove containers from memory on error Before this, if `forceRemove` is set the container data will be removed<br> no matter what, including if there are issues with removing container<br> on-disk state (rw layer, container root). <br> In practice this causes a lot of issues with leaked data sitting on<br> disk that users are not able to clean up themselves. <br> This is particularly a problem while the `EBUSY` errors on remove are so<br> prevalent. So for now let's not keep this behavior. <br> Cherry-pick from <a href="moby#31012" rel="nofollow noreferrer" target="_blank">https://github.com/moby/moby/pull/31012</a> <br> Signed-off-by: Brian Goff <a href="mailto:cpuguy83@gmail.com">cpuguy83@gmail.com</a><br> Signed-off-by: Wentao Zhang <a href="mailto:zhangwentao234@huawei.com">zhangwentao234@huawei.com</a><br> (cherry picked from commit <a href="/docker/docker/commit/54dcbab25ea4771da303fa95e0c26f2d39487b49" data-original="54dcbab2" data-link="false" data-project="7713" data-commit="54dcbab25ea4771da303fa95e0c26f2d39487b49" data-reference-type="commit" title="" class="gfm gfm-commit has-tooltip" data-original-title="Do not remove containers from memory on error">54dcbab2</a>) <br> Conflicts:<br> daemon/delete.go<br> daemon/graphdriver/aufs/aufs.go<br> daemon/graphdriver/btrfs/btrfs.go<br> daemon/graphdriver/devmapper/driver.go<br> daemon/graphdriver/overlay/overlay.go<br> daemon/monitor.go<br> pkg/mount/mount.go See merge request docker/docker!519
- Loading branch information
Showing
11 changed files
with
233 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package system | ||
|
||
import ( | ||
"os" | ||
"syscall" | ||
"time" | ||
|
||
"github.com/docker/docker/pkg/mount" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
// EnsureRemoveAll wraps `os.RemoveAll` to check for specific errors that can | ||
// often be remedied. | ||
// Only use `EnsureRemoveAll` if you really want to make every effort to remove | ||
// a directory. | ||
// | ||
// Because of the way `os.Remove` (and by extension `os.RemoveAll`) works, there | ||
// can be a race between reading directory entries and then actually attempting | ||
// to remove everything in the directory. | ||
// These types of errors do not need to be returned since it's ok for the dir to | ||
// be gone we can just retry the remove operation. | ||
// | ||
// This should not return a `os.ErrNotExist` kind of error under any cirucmstances | ||
func EnsureRemoveAll(dir string) error { | ||
notExistErr := make(map[string]bool) | ||
|
||
// track retries | ||
exitOnErr := make(map[string]int) | ||
maxRetry := 5 | ||
|
||
// Attempt to unmount anything beneath this dir first | ||
mount.RecursiveUnmount(dir) | ||
|
||
for { | ||
err := os.RemoveAll(dir) | ||
if err == nil { | ||
return err | ||
} | ||
|
||
pe, ok := err.(*os.PathError) | ||
if !ok { | ||
return err | ||
} | ||
|
||
if os.IsNotExist(err) { | ||
if notExistErr[pe.Path] { | ||
return err | ||
} | ||
notExistErr[pe.Path] = true | ||
|
||
// There is a race where some subdir can be removed but after the parent | ||
// dir entries have been read. | ||
// So the path could be from `os.Remove(subdir)` | ||
// If the reported non-existent path is not the passed in `dir` we | ||
// should just retry, but otherwise return with no error. | ||
if pe.Path == dir { | ||
return nil | ||
} | ||
continue | ||
} | ||
|
||
if pe.Err != syscall.EBUSY { | ||
return err | ||
} | ||
|
||
if mounted, _ := mount.Mounted(pe.Path); mounted { | ||
if e := mount.Unmount(pe.Path); e != nil { | ||
if mounted, _ := mount.Mounted(pe.Path); mounted { | ||
return errors.Wrapf(e, "error while removing %s", dir) | ||
} | ||
} | ||
} | ||
|
||
if exitOnErr[pe.Path] == maxRetry { | ||
return err | ||
} | ||
exitOnErr[pe.Path]++ | ||
time.Sleep(100 * time.Millisecond) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package system | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"testing" | ||
"time" | ||
|
||
"github.com/docker/docker/pkg/mount" | ||
) | ||
|
||
func TestEnsureRemoveAllNotExist(t *testing.T) { | ||
// should never return an error for a non-existent path | ||
if err := EnsureRemoveAll("/non/existent/path"); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestEnsureRemoveAllWithDir(t *testing.T) { | ||
dir, err := ioutil.TempDir("", "test-ensure-removeall-with-dir") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := EnsureRemoveAll(dir); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestEnsureRemoveAllWithFile(t *testing.T) { | ||
tmp, err := ioutil.TempFile("", "test-ensure-removeall-with-dir") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
tmp.Close() | ||
if err := EnsureRemoveAll(tmp.Name()); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestEnsureRemoveAllWithMount(t *testing.T) { | ||
if runtime.GOOS == "windows" { | ||
t.Skip("mount not supported on Windows") | ||
} | ||
|
||
dir1, err := ioutil.TempDir("", "test-ensure-removeall-with-dir1") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
dir2, err := ioutil.TempDir("", "test-ensure-removeall-with-dir2") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer os.RemoveAll(dir2) | ||
|
||
bindDir := filepath.Join(dir1, "bind") | ||
if err := os.MkdirAll(bindDir, 0755); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if err := mount.Mount(dir2, bindDir, "none", "bind"); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
done := make(chan struct{}) | ||
go func() { | ||
err = EnsureRemoveAll(dir1) | ||
close(done) | ||
}() | ||
|
||
select { | ||
case <-done: | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
case <-time.After(5 * time.Second): | ||
t.Fatal("timeout waiting for EnsureRemoveAll to finish") | ||
} | ||
|
||
if _, err := os.Stat(dir1); !os.IsNotExist(err) { | ||
t.Fatalf("expected %q to not exist", dir1) | ||
} | ||
} |