mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Fix uneccessary calls to volume.Unmount()
Fixes #22564 When an error occurs on mount, there should not be any call later to unmount. This can throw off refcounting in the underlying driver unexpectedly. Consider these two cases: ``` $ docker run -v foo:/bar busybox true ``` ``` $ docker run -v foo:/bar -w /foo busybox true ``` In the first case, if mounting `foo` fails, the volume driver will not get a call to unmount (this is the incorrect behavior). In the second case, the volume driver will not get a call to unmount (correct behavior). This occurs because in the first case, `/bar` does not exist in the container, and as such there is no call to `volume.Mount()` during the `create` phase. It will error out during the `start` phase. In the second case `/bar` is created before dealing with the volume because of the `-w`. Because of this, when the volume is being setup docker will try to copy the image path contents in the volume, in which case it will attempt to mount the volume and fail. This happens during the `create` phase. This makes it so the container will not be created (or at least fully created) and the user gets the error on `create` instead of `start`. The error handling is different in these two phases. Changed to only send `unmount` if the volume is mounted. While investigating the cause of the reported issue I found some odd behavior in unmount calls so I've cleaned those up a bit here as well. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
parent
c13bf5ba51
commit
9a2d0bc3ad
7 changed files with 113 additions and 107 deletions
|
@ -73,6 +73,7 @@ type vol struct {
|
|||
Mountpoint string
|
||||
Ninja bool // hack used to trigger a null volume return on `Get`
|
||||
Status map[string]interface{}
|
||||
Options map[string]string
|
||||
}
|
||||
|
||||
func (p *volumePlugin) Close() {
|
||||
|
@ -130,7 +131,7 @@ func newVolumePlugin(c *check.C, name string) *volumePlugin {
|
|||
}
|
||||
_, isNinja := pr.Opts["ninja"]
|
||||
status := map[string]interface{}{"Hello": "world"}
|
||||
s.vols[pr.Name] = vol{Name: pr.Name, Ninja: isNinja, Status: status}
|
||||
s.vols[pr.Name] = vol{Name: pr.Name, Ninja: isNinja, Status: status, Options: pr.Opts}
|
||||
send(w, nil)
|
||||
})
|
||||
|
||||
|
@ -212,6 +213,14 @@ func newVolumePlugin(c *check.C, name string) *volumePlugin {
|
|||
return
|
||||
}
|
||||
|
||||
if v, exists := s.vols[pr.Name]; exists {
|
||||
// Use this to simulate a mount failure
|
||||
if _, exists := v.Options["invalidOption"]; exists {
|
||||
send(w, fmt.Errorf("invalid argument"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
p := hostVolumePath(pr.Name)
|
||||
if err := os.MkdirAll(p, 0755); err != nil {
|
||||
send(w, &pluginResp{Err: err.Error()})
|
||||
|
@ -562,3 +571,13 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverOutOfBandDelete(c *c
|
|||
out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
}
|
||||
|
||||
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnMountFail(c *check.C) {
|
||||
c.Assert(s.d.StartWithBusybox(), checker.IsNil)
|
||||
s.d.Cmd("volume", "create", "-d", "test-external-volume-driver", "--opt=invalidOption=1", "--name=testumount")
|
||||
|
||||
out, _ := s.d.Cmd("run", "-v", "testumount:/foo", "busybox", "true")
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 0, check.Commentf(out))
|
||||
out, _ = s.d.Cmd("run", "-w", "/foo", "-v", "testumount:/foo", "busybox", "true")
|
||||
c.Assert(s.ec.unmounts, checker.Equals, 0, check.Commentf(out))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue