mirror of
https://github.com/containers/podman.git
synced 2025-05-23 10:07:33 +08:00

After a restart, pods and containers both run a refresh() function to prepare to run after a reboot. Until now, volumes have not had a similar function, because they had no per-boot setup to perform. Unfortunately, this was not noticed when in-memory locking was introduced to volumes. The refresh() routine is, among other things, responsible for ensuring that locks are reserved after a reboot, ensuring they cannot be taken by a freshly-created container, pod, or volume. If this reservation is not done, we can end up with two objects using the same lock, potentially needing to lock each other for some operations - classic recipe for deadlocks. Add a refresh() function to volumes to perform lock reservation and ensure it is called as part of overall refresh(). Fixes #4605 Fixes #4621 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package libpod
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containers/libpod/libpod/define"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Creates a new volume
|
|
func newVolume(runtime *Runtime) (*Volume, error) {
|
|
volume := new(Volume)
|
|
volume.config = new(VolumeConfig)
|
|
volume.state = new(VolumeState)
|
|
volume.runtime = runtime
|
|
volume.config.Labels = make(map[string]string)
|
|
volume.config.Options = make(map[string]string)
|
|
volume.state.NeedsCopyUp = true
|
|
|
|
return volume, nil
|
|
}
|
|
|
|
// teardownStorage deletes the volume from volumePath
|
|
func (v *Volume) teardownStorage() error {
|
|
return os.RemoveAll(filepath.Join(v.runtime.config.VolumePath, v.Name()))
|
|
}
|
|
|
|
// Volumes with options set, or a filesystem type, or a device to mount need to
|
|
// be mounted and unmounted.
|
|
func (v *Volume) needsMount() bool {
|
|
return len(v.config.Options) > 0 && v.config.Driver == define.VolumeDriverLocal
|
|
}
|
|
|
|
// update() updates the volume state from the DB.
|
|
func (v *Volume) update() error {
|
|
if err := v.runtime.state.UpdateVolume(v); err != nil {
|
|
return err
|
|
}
|
|
if !v.valid {
|
|
return define.ErrVolumeRemoved
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// save() saves the volume state to the DB
|
|
func (v *Volume) save() error {
|
|
return v.runtime.state.SaveVolume(v)
|
|
}
|
|
|
|
// Refresh volume state after a restart.
|
|
func (v *Volume) refresh() error {
|
|
lock, err := v.runtime.lockManager.AllocateAndRetrieveLock(v.config.LockID)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error acquiring lock %d for volume %s", v.config.LockID, v.Name())
|
|
}
|
|
v.lock = lock
|
|
|
|
return nil
|
|
}
|