Skip to content

Commit a475083

Browse files
Merge pull request #25169 from mheon/graph_stop
Add graph-based pod stop
2 parents 8d42125 + 46d874a commit a475083

File tree

6 files changed

+375
-164
lines changed

6 files changed

+375
-164
lines changed

libpod/container_api.go

Lines changed: 30 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -85,34 +85,23 @@ func (c *Container) initUnlocked(ctx context.Context, recursive bool) error {
8585
// Start requires that all dependency containers (e.g. pod infra containers) are
8686
// running before starting the container. The recursive parameter, if set, will start all
8787
// dependencies before starting this container.
88-
func (c *Container) Start(ctx context.Context, recursive bool) (finalErr error) {
89-
if !c.batched {
90-
c.lock.Lock()
91-
defer c.lock.Unlock()
92-
93-
// defer's are executed LIFO so we are locked here
94-
// as long as we call this after the defer unlock()
95-
defer func() {
96-
if finalErr != nil {
97-
if err := saveContainerError(c, finalErr); err != nil {
98-
logrus.Debug(err)
99-
}
100-
}
101-
}()
102-
103-
if err := c.syncContainer(); err != nil {
104-
return err
88+
func (c *Container) Start(ctx context.Context, recursive bool) error {
89+
// Have to lock the pod the container is a part of.
90+
// This prevents running `podman start` at the same time a
91+
// `podman pod stop` is running, which could lead to weird races.
92+
// Pod locks come before container locks, so do this first.
93+
if c.config.Pod != "" {
94+
// If we get an error, the pod was probably removed.
95+
// So we get an expected ErrCtrRemoved instead of ErrPodRemoved,
96+
// just ignore this and move on to syncing the container.
97+
pod, _ := c.runtime.state.Pod(c.config.Pod)
98+
if pod != nil {
99+
pod.lock.Lock()
100+
defer pod.lock.Unlock()
105101
}
106102
}
107-
if err := c.prepareToStart(ctx, recursive); err != nil {
108-
return err
109-
}
110103

111-
// Start the container
112-
if err := c.start(); err != nil {
113-
return err
114-
}
115-
return c.waitForHealthy(ctx)
104+
return c.startNoPodLock(ctx, recursive)
116105
}
117106

118107
// Update updates the given container.
@@ -294,6 +283,21 @@ func (c *Container) Stop() error {
294283
// manually. If timeout is 0, SIGKILL will be used immediately to kill the
295284
// container.
296285
func (c *Container) StopWithTimeout(timeout uint) (finalErr error) {
286+
// Have to lock the pod the container is a part of.
287+
// This prevents running `podman stop` at the same time a
288+
// `podman pod start` is running, which could lead to weird races.
289+
// Pod locks come before container locks, so do this first.
290+
if c.config.Pod != "" {
291+
// If we get an error, the pod was probably removed.
292+
// So we get an expected ErrCtrRemoved instead of ErrPodRemoved,
293+
// just ignore this and move on to syncing the container.
294+
pod, _ := c.runtime.state.Pod(c.config.Pod)
295+
if pod != nil {
296+
pod.lock.Lock()
297+
defer pod.lock.Unlock()
298+
}
299+
}
300+
297301
if !c.batched {
298302
c.lock.Lock()
299303
defer c.lock.Unlock()
@@ -852,58 +856,7 @@ func (c *Container) Cleanup(ctx context.Context, onlyStopped bool) error {
852856
}
853857
}
854858

855-
// Check if state is good
856-
if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateCreated, define.ContainerStateStopped, define.ContainerStateStopping, define.ContainerStateExited) {
857-
return fmt.Errorf("container %s is running or paused, refusing to clean up: %w", c.ID(), define.ErrCtrStateInvalid)
858-
}
859-
if onlyStopped && !c.ensureState(define.ContainerStateStopped) {
860-
return fmt.Errorf("container %s is not stopped and only cleanup for a stopped container was requested: %w", c.ID(), define.ErrCtrStateInvalid)
861-
}
862-
863-
// if the container was not created in the oci runtime or was already cleaned up, then do nothing
864-
if c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
865-
return nil
866-
}
867-
868-
// Handle restart policy.
869-
// Returns a bool indicating whether we actually restarted.
870-
// If we did, don't proceed to cleanup - just exit.
871-
didRestart, err := c.handleRestartPolicy(ctx)
872-
if err != nil {
873-
return err
874-
}
875-
if didRestart {
876-
return nil
877-
}
878-
879-
// If we didn't restart, we perform a normal cleanup
880-
881-
// make sure all the container processes are terminated if we are running without a pid namespace.
882-
hasPidNs := false
883-
if c.config.Spec.Linux != nil {
884-
for _, i := range c.config.Spec.Linux.Namespaces {
885-
if i.Type == spec.PIDNamespace {
886-
hasPidNs = true
887-
break
888-
}
889-
}
890-
}
891-
if !hasPidNs {
892-
// do not fail on errors
893-
_ = c.ociRuntime.KillContainer(c, uint(unix.SIGKILL), true)
894-
}
895-
896-
// Check for running exec sessions
897-
sessions, err := c.getActiveExecSessions()
898-
if err != nil {
899-
return err
900-
}
901-
if len(sessions) > 0 {
902-
return fmt.Errorf("container %s has active exec sessions, refusing to clean up: %w", c.ID(), define.ErrCtrStateInvalid)
903-
}
904-
905-
defer c.newContainerEvent(events.Cleanup)
906-
return c.cleanup(ctx)
859+
return c.fullCleanup(ctx, onlyStopped)
907860
}
908861

909862
// Batch starts a batch operation on the given container

0 commit comments

Comments
 (0)