diff --git a/cmd/containerd-shim-runc-v2/task/service.go b/cmd/containerd-shim-runc-v2/task/service.go index 1a1a960ff..fce141ce5 100644 --- a/cmd/containerd-shim-runc-v2/task/service.go +++ b/cmd/containerd-shim-runc-v2/task/service.go @@ -82,6 +82,7 @@ func NewTaskService(ctx context.Context, publisher shim.Publisher, sd shutdown.S containers: make(map[string]*runc.Container), running: make(map[int][]containerProcess), pendingExecs: make(map[*runc.Container]int), + execable: make(map[*runc.Container]bool), exitSubscribers: make(map[*map[int][]runcC.Exit]struct{}), } go s.processExits() @@ -118,6 +119,12 @@ type service struct { lifecycleMu sync.Mutex running map[int][]containerProcess // pid -> running process, guarded by lifecycleMu pendingExecs map[*runc.Container]int // container -> num pending execs, guarded by lifecycleMu + // container -> execs can be started, guarded by lifecycleMu. + // Execs can be started if the container's init process (read: pid, not [process.Init]) + // has been started and not yet reaped by the shim. + // Note that this flag gets updated before the container's [process.Init.Status] + // is transitioned to "stopped". + execable map[*runc.Container]bool // Subscriptions to exits for PIDs. Adding/deleting subscriptions and // dereferencing the subscription pointers must only be done while holding // lifecycleMu. @@ -231,6 +238,9 @@ func (s *service) preStart(c *runc.Container) (handleStarted func(*runc.Containe Container: c, Process: p, }) + if init { + s.execable[c] = true + } s.lifecycleMu.Unlock() } } @@ -305,6 +315,10 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI. if r.ExecID == "" { cinit = container } else { + if !s.execable[container] { + s.lifecycleMu.Unlock() + return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container %s init process is not running", container.ID) + } s.pendingExecs[container]++ } handleStarted, cleanup := s.preStart(cinit) @@ -680,6 +694,9 @@ func (s *service) processExits() { var cps, skipped []containerProcess for _, cp := range s.running[e.Pid] { _, init := cp.Process.(*process.Init) + if init { + delete(s.execable, cp.Container) + } if init && s.pendingExecs[cp.Container] != 0 { // This exit relates to a container for which we have pending execs. In // order to ensure order between execs and the init process for a given