From dbcaa504c6553f7f52b53b917d0f3c98416281c1 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 27 May 2026 13:04:08 +0900 Subject: [PATCH] runc-shim: don't hold the service lock across runc create The task service guards its containers map with s.mu, and getContainer() takes it on behalf of effectively every task RPC (State, Connect, Stats, Wait, Pause, Kill, ...). Create() held s.mu for its whole duration, including runc.NewContainer(), which runs the actual `runc create`. `runc create` can be slow on a loaded host. While it runs, any concurrent task RPC blocks on s.mu. The tasks service applies a 2s timeout to State (io.containerd.timeout.task.state), so a concurrent State waits on s.mu, exceeds the deadline, and the ttrpc call is abandoned -- the late shim reply then shows up as: ttrpc: received message on inactive stream stream=3 Since deadline errors are now surfaced to clients, this is treated as a fatal failure and the just-created container is torn down right after start (observed on Lima/vz: nginx -> Exited (1)). Move runc.NewContainer() out of the s.mu critical section, mirroring the runtime v1 shim lock optimization. s.mu is taken only once the container exists, to guard the map and the remaining (fast) setup, so a slow create no longer blocks concurrent State and other lookups. preStart/handleStarted/cleanup only use s.lifecycleMu, so early-exit handling is unchanged. See lima-vm/lima#5030. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Akihiro Suda --- cmd/containerd-shim-runc-v2/task/service.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/containerd-shim-runc-v2/task/service.go b/cmd/containerd-shim-runc-v2/task/service.go index 46bbcf4848..e46da2fe5d 100644 --- a/cmd/containerd-shim-runc-v2/task/service.go +++ b/cmd/containerd-shim-runc-v2/task/service.go @@ -221,9 +221,6 @@ func (s *service) preStart(c *runc.Container) (handleStarted func(*runc.Containe // Create a new initial process and container with the underlying OCI runtime func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { - s.mu.Lock() - defer s.mu.Unlock() - s.lifecycleMu.Lock() handleStarted, cleanup := s.preStart(nil) s.lifecycleMu.Unlock() @@ -234,7 +231,9 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ * return nil, err } + s.mu.Lock() s.containers[r.ID] = container + s.mu.Unlock() s.send(&eventstypes.TaskCreate{ ContainerID: r.ID,