mirror of
https://github.com/containers/podman.git
synced 2025-07-04 10:10:32 +08:00
Fix a potential deadlock during podman cp
Have one function without a `defer lock.unlock()` as one of the commands in it calls a function that also takes the same lock, so the unlock has to happen prior to function completion. Unfortunately, this is prone to errors, like the one here: I missed a case, and we could return without unlocking, causing a deadlock later in the cleanup code as we tried to take the same lock again. Refactor the command to use `defer unlock()` to simplify and avoid any further errors of this type. Introduced by e66b788a514fb8df2c8b8d3c000e0d543bbd60df - this should be included in any backports of that commit. Fixes #25585 Signed-off-by: Matt Heon <mheon@redhat.com>
This commit is contained in:
@ -160,10 +160,10 @@ func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir boo
|
|||||||
// populated the volume and that will block a future
|
// populated the volume and that will block a future
|
||||||
// copy-up.
|
// copy-up.
|
||||||
volume.lock.Lock()
|
volume.lock.Lock()
|
||||||
|
defer volume.lock.Unlock()
|
||||||
|
|
||||||
if err := volume.update(); err != nil {
|
if err := volume.update(); err != nil {
|
||||||
logrus.Errorf("Unable to update volume %s status: %v", volume.Name(), err)
|
logrus.Errorf("Unable to update volume %s status: %v", volume.Name(), err)
|
||||||
volume.lock.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,15 +172,12 @@ func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir boo
|
|||||||
volume.state.CopiedUp = true
|
volume.state.CopiedUp = true
|
||||||
if err := volume.save(); err != nil {
|
if err := volume.save(); err != nil {
|
||||||
logrus.Errorf("Unable to save volume %s state: %v", volume.Name(), err)
|
logrus.Errorf("Unable to save volume %s state: %v", volume.Name(), err)
|
||||||
volume.lock.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
volume.lock.Unlock()
|
|
||||||
|
|
||||||
for _, namedVol := range c.config.NamedVolumes {
|
for _, namedVol := range c.config.NamedVolumes {
|
||||||
if namedVol.Name == volume.Name() {
|
if namedVol.Name == volume.Name() {
|
||||||
if err := c.fixVolumePermissions(namedVol); err != nil {
|
if err := c.fixVolumePermissionsUnlocked(namedVol, volume); err != nil {
|
||||||
logrus.Errorf("Unable to fix volume %s permissions: %v", volume.Name(), err)
|
logrus.Errorf("Unable to fix volume %s permissions: %v", volume.Name(), err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -2949,6 +2949,10 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
|
|||||||
vol.lock.Lock()
|
vol.lock.Lock()
|
||||||
defer vol.lock.Unlock()
|
defer vol.lock.Unlock()
|
||||||
|
|
||||||
|
return c.fixVolumePermissionsUnlocked(v, vol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) fixVolumePermissionsUnlocked(v *ContainerNamedVolume, vol *Volume) error {
|
||||||
// The volume may need a copy-up. Check the state.
|
// The volume may need a copy-up. Check the state.
|
||||||
if err := vol.update(); err != nil {
|
if err := vol.update(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -280,22 +280,18 @@ RUN chown 9999:9999 %s`, ALPINE, ctrVolPath, ctrVolPath)
|
|||||||
defer srcFile.Close()
|
defer srcFile.Close()
|
||||||
defer os.Remove(srcFile.Name())
|
defer os.Remove(srcFile.Name())
|
||||||
|
|
||||||
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
|
_ = podmanTest.PodmanExitCleanly("volume", "create", volName)
|
||||||
volCreate.WaitWithDefaultTimeout()
|
_ = podmanTest.PodmanExitCleanly("create", "--name", ctrName, "-v", fmt.Sprintf("%s:%s", volName, ctrVolPath), imgName, "sh")
|
||||||
Expect(volCreate).Should(ExitCleanly())
|
|
||||||
|
|
||||||
ctrCreate := podmanTest.Podman([]string{"create", "--name", ctrName, "-v", fmt.Sprintf("%s:%s", volName, ctrVolPath), imgName, "sh"})
|
_ = podmanTest.PodmanExitCleanly("cp", srcFile.Name(), fmt.Sprintf("%s:%s", ctrName, ctrVolPath))
|
||||||
ctrCreate.WaitWithDefaultTimeout()
|
|
||||||
Expect(ctrCreate).To(ExitCleanly())
|
|
||||||
|
|
||||||
cp := podmanTest.Podman([]string{"cp", srcFile.Name(), fmt.Sprintf("%s:%s", ctrName, ctrVolPath)})
|
ls := podmanTest.PodmanExitCleanly("run", "-v", fmt.Sprintf("%s:%s", volName, ctrVolPath), ALPINE, "ls", "-al", ctrVolPath)
|
||||||
cp.WaitWithDefaultTimeout()
|
|
||||||
Expect(cp).To(ExitCleanly())
|
|
||||||
|
|
||||||
ls := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:%s", volName, ctrVolPath), ALPINE, "ls", "-al", ctrVolPath})
|
|
||||||
ls.WaitWithDefaultTimeout()
|
|
||||||
Expect(ls).To(ExitCleanly())
|
|
||||||
Expect(ls.OutputToString()).To(ContainSubstring("9999 9999"))
|
Expect(ls.OutputToString()).To(ContainSubstring("9999 9999"))
|
||||||
Expect(ls.OutputToString()).To(ContainSubstring(filepath.Base(srcFile.Name())))
|
Expect(ls.OutputToString()).To(ContainSubstring(filepath.Base(srcFile.Name())))
|
||||||
|
|
||||||
|
// Test for #25585
|
||||||
|
_ = podmanTest.PodmanExitCleanly("rm", ctrName)
|
||||||
|
_ = podmanTest.PodmanExitCleanly("create", "--name", ctrName, "-v", fmt.Sprintf("%s:%s", volName, ctrVolPath), imgName, "sh")
|
||||||
|
_ = podmanTest.PodmanExitCleanly("cp", srcFile.Name(), fmt.Sprintf("%s:%sfile2", ctrName, ctrVolPath))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user