diff --git a/cache/blobs.go b/cache/blobs.go index 09836772d..3acc23c00 100644 --- a/cache/blobs.go +++ b/cache/blobs.go @@ -109,7 +109,7 @@ func computeBlobChain(ctx context.Context, sr *immutableRef, createIfNeeded bool } defer func() { if err != nil { - l.Discard() + l.Discard(ctx) } }() @@ -461,7 +461,7 @@ func ensureCompression(ctx context.Context, ref *immutableRef, comp compression. } defer func() { if err != nil { - l.Discard() + l.Discard(ctx) } }() diff --git a/cache/manager.go b/cache/manager.go index bd109c9eb..7cb408115 100644 --- a/cache/manager.go +++ b/cache/manager.go @@ -235,7 +235,7 @@ func (cm *cacheManager) GetByBlob(ctx context.Context, desc ocispecs.Descriptor, snapshotID := chainID.String() if link != nil { snapshotID = link.getSnapshotID() - go link.Release(context.TODO()) + go link.Release(context.WithoutCancel(ctx)) } l, err := cm.LeaseManager.Create(ctx, func(l *leases.Lease) error { diff --git a/cache/refs.go b/cache/refs.go index 220c629f7..1ad7caf47 100644 --- a/cache/refs.go +++ b/cache/refs.go @@ -1519,8 +1519,9 @@ func (cr *cacheRecord) finalize(ctx context.Context) error { go func() { cr.cm.mu.Lock() defer cr.cm.mu.Unlock() - if err := mutable.remove(context.TODO(), true); err != nil { - bklog.G(ctx).Error(err) + cleanupCtx := context.WithoutCancel(ctx) + if err := mutable.remove(cleanupCtx, true); err != nil { + bklog.G(cleanupCtx).Error(err) } }() diff --git a/client/client_test.go b/client/client_test.go index 1ea3b36ba..7c76d0aa8 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -13726,8 +13726,12 @@ func testGitBundleRoundTrip(t *testing.T, sb integration.Sandbox) { localBare := t.TempDir() err = runInDir(localBare, "git init --bare") require.NoError(t, err) - bundlePath := filepath.Join(t.TempDir(), "bundle.pack") - require.NoError(t, os.WriteFile(bundlePath, bundleBytes, 0644)) + bundleRoot := t.TempDir() + root, err := os.OpenRoot(bundleRoot) + require.NoError(t, err) + require.NoError(t, root.WriteFile("bundle.pack", bundleBytes, 0644)) + require.NoError(t, root.Close()) + bundlePath := filepath.Join(bundleRoot, "bundle.pack") err = runInDir(localBare, fmt.Sprintf("git fetch %s +refs/*:refs/*", bundlePath)) require.NoError(t, err) //nolint:gosec // Test-controlled temp dir and commit SHA are not attacker input. diff --git a/docs/generate.go b/docs/generate.go index 4b710371e..70c3044d4 100644 --- a/docs/generate.go +++ b/docs/generate.go @@ -15,18 +15,24 @@ import ( func main() { re := regexp.MustCompile("(?s)(.*?)\n") - err := filepath.Walk("./docs", func(path string, stat fs.FileInfo, err error) error { + root, err := os.OpenRoot("./docs") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = fs.WalkDir(root.FS(), ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } - if stat.IsDir() { + if d.IsDir() { return nil } if filepath.Ext(path) != ".md" { return nil } - data, err := os.ReadFile(path) + data, err := root.ReadFile(path) if err != nil { return err } @@ -61,14 +67,21 @@ func main() { } if !bytes.Equal(data, dataNew) { - fmt.Println(path) - if err := os.WriteFile(path, dataNew, stat.Mode()); err != nil { + info, err := d.Info() + if err != nil { + return err + } + fmt.Println(filepath.Join("docs", path)) + if err := root.WriteFile(path, dataNew, info.Mode()); err != nil { return err } } return nil }) + if closeErr := root.Close(); closeErr != nil && err == nil { + err = closeErr + } if err != nil { fmt.Println(err) os.Exit(1) diff --git a/executor/runcexecutor/executor.go b/executor/runcexecutor/executor.go index c4e5f8fd0..5bf2c78ec 100644 --- a/executor/runcexecutor/executor.go +++ b/executor/runcexecutor/executor.go @@ -646,7 +646,7 @@ func runcProcessHandle(ctx context.Context, killer procKiller) (*procHandle, con for { select { case <-ctx.Done(): - killCtx, timeout := context.WithCancelCause(context.Background()) //nolint:govet + killCtx, timeout := context.WithCancelCause(context.WithoutCancel(ctx)) //nolint:govet killCtx, _ = context.WithTimeoutCause(killCtx, 7*time.Second, errors.WithStack(context.DeadlineExceeded)) //nolint:govet if err := p.killer.Kill(killCtx); err != nil { select { diff --git a/frontend/dockerfile/parser/dumper/main.go b/frontend/dockerfile/parser/dumper/main.go index 461066b73..10ea8e552 100644 --- a/frontend/dockerfile/parser/dumper/main.go +++ b/frontend/dockerfile/parser/dumper/main.go @@ -8,16 +8,13 @@ import ( ) func main() { - var f *os.File - var err error - if len(os.Args) < 2 { fmt.Println("please supply filename(s)") os.Exit(1) } for _, fn := range os.Args[1:] { - f, err = os.Open(fn) + f, err := os.Open(fn) //nolint:gosec // not using os.Root to support symlinks if err != nil { panic(err) } diff --git a/hack/dockerfiles/lint.Dockerfile b/hack/dockerfiles/lint.Dockerfile index a31de4cee..2158e41f3 100644 --- a/hack/dockerfiles/lint.Dockerfile +++ b/hack/dockerfiles/lint.Dockerfile @@ -4,7 +4,7 @@ ARG GO_VERSION=1.26 ARG ALPINE_VERSION=3.23 ARG XX_VERSION=1.9.0 ARG PROTOLINT_VERSION=0.50.5 -ARG GOLANGCI_LINT_VERSION=v2.8.0 +ARG GOLANGCI_LINT_VERSION=v2.12.2 ARG GOLANGCI_FROM_SOURCE=false ARG GOPLS_VERSION=v0.38.0 # GOPLS_ANALYZERS defines gopls analyzers to be run. disabled by default: deprecated simplifyrange unusedfunc unusedvariable @@ -34,7 +34,7 @@ RUN apk add --no-cache gcc musl-dev yamllint ARG GOLANGCI_LINT_VERSION ARG GOLANGCI_FROM_SOURCE COPY --link --from=golangci-binary / /usr/bin/ -RUN [ "${GOLANGCI_FROM_SOURCE}" = "true" ] && exit 0; wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s ${GOLANGCI_LINT_VERSION} +RUN [ "${GOLANGCI_FROM_SOURCE}" = "true" ] && exit 0; wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/${GOLANGCI_LINT_VERSION}/install.sh | sh -s ${GOLANGCI_LINT_VERSION} COPY --link --from=protolint-base /usr/local/bin/protolint /usr/local/bin/protolint COPY --link --from=xx / / WORKDIR /go/src/github.com/moby/buildkit diff --git a/session/sshforward/sshprovider/agentprovider.go b/session/sshforward/sshprovider/agentprovider.go index f29531a56..78930203d 100644 --- a/session/sshforward/sshprovider/agentprovider.go +++ b/session/sshforward/sshprovider/agentprovider.go @@ -130,7 +130,7 @@ func toDialer(paths []string, raw bool) (func(context.Context) (net.Conn, error) continue } - fi, err := os.Stat(p) + fi, err := os.Stat(p) //nolint:gosec // SSH agent paths are explicit user inputs and may intentionally be symlinks. if err != nil { return nil, errors.WithStack(err) } @@ -142,7 +142,7 @@ func toDialer(paths []string, raw bool) (func(context.Context) (net.Conn, error) return nil, errors.Errorf("raw mode only supported with socket paths") } - f, err := os.Open(p) + f, err := os.Open(p) //nolint:gosec // SSH key paths are explicit user inputs and may intentionally be symlinks. if err != nil { return nil, errors.Wrapf(err, "failed to open %s", p) } diff --git a/session/testutil/testutil.go b/session/testutil/testutil.go index 34d969eff..755b11b26 100644 --- a/session/testutil/testutil.go +++ b/session/testutil/testutil.go @@ -20,7 +20,7 @@ func TestStream(handler Handler) Dialer { s1, s2 := sockPair() return func(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) { go func() { - err := handler(context.TODO(), s1, meta) + err := handler(context.WithoutCancel(ctx), s1, meta) if err != nil { bklog.G(ctx).Error(err) } diff --git a/solver/edge.go b/solver/edge.go index 94ff753f3..8059bdf45 100644 --- a/solver/edge.go +++ b/solver/edge.go @@ -972,7 +972,7 @@ func (e *edge) execOp(ctx context.Context) (any, error) { for i := range results { if i != int(index) { - go results[i].Release(context.TODO()) + go results[i].Release(context.WithoutCancel(ctx)) } } diff --git a/solver/llbsolver/history/buildhistory.go b/solver/llbsolver/history/buildhistory.go index 2e43bae66..9349f2b2a 100644 --- a/solver/llbsolver/history/buildhistory.go +++ b/solver/llbsolver/history/buildhistory.go @@ -290,7 +290,7 @@ func (h *Queue) addResource(ctx context.Context, l leases.Lease, desc *controlap if err != nil { return err } - defer lr.Discard() + defer lr.Discard(ctx) ok, err := h.migrateBlobV2(ctx, desc.Digest, detectSkipLayers) if err != nil { return err diff --git a/source/git/source.go b/source/git/source.go index 2571d09c2..2f33bc5ab 100644 --- a/source/git/source.go +++ b/source/git/source.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "fmt" "io" + "io/fs" "net/url" "os" "os/exec" @@ -1326,8 +1327,14 @@ func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g sessi } } + checkoutRoot, err := os.OpenRoot(checkoutDir) + if err != nil { + return nil, errors.Wrap(err, "failed to open git checkout root") + } + defer checkoutRoot.Close() + if compatibilityVersion == compat.CompatibilityVersion013 { - if err := resetCompatibility014FileModes(checkoutDir); err != nil { + if err := resetCompatibility014FileModes(checkoutRoot); err != nil { return nil, errors.Wrapf(err, "failed to normalize compatibility file modes for %s", urlutil.RedactCredentials(gs.src.Remote)) } } @@ -1337,16 +1344,23 @@ func (gs *gitSourceHandler) checkout(ctx context.Context, repo *gitRepo, g sessi if err != nil { return nil, errors.Wrapf(err, "failed to get commit time for %s", urlutil.RedactCredentials(gs.src.Remote)) } - if err := resetSnapshotMtimes(checkoutDir, commitTime); err != nil { + if err := resetSnapshotMtimes(checkoutRoot, commitTime); err != nil { return nil, errors.Wrapf(err, "failed to normalize mtimes for %s", urlutil.RedactCredentials(gs.src.Remote)) } } if idmap := mount.IdentityMapping(); idmap != nil { uid, gid := idmap.RootPair() - err := filepath.WalkDir(gitDir, func(p string, _ os.DirEntry, _ error) error { - return os.Lchown(p, uid, gid) + root, err := os.OpenRoot(gitDir) + if err != nil { + return nil, errors.Wrap(err, "failed to open git checkout root") + } + err = fs.WalkDir(root.FS(), ".", func(p string, _ os.DirEntry, _ error) error { + return root.Lchown(p, uid, gid) }) + if closeErr := root.Close(); closeErr != nil && err == nil { + err = closeErr + } if err != nil { return nil, errors.Wrap(err, "failed to remap git checkout") } @@ -1388,9 +1402,9 @@ func getCommitTime(ctx context.Context, git *gitutil.GitCLI, ref string) (time.T // resetSnapshotMtimes walks dir and sets the mtime of every file, // symlink, and directory to t. Directories are set bottom-up so that // a parent's mtime is not invalidated by a later child write. -func resetSnapshotMtimes(dir string, t time.Time) error { +func resetSnapshotMtimes(root *os.Root, t time.Time) error { var dirs []string - err := filepath.WalkDir(dir, func(p string, d os.DirEntry, err error) error { + err := fs.WalkDir(root.FS(), ".", func(p string, d os.DirEntry, err error) error { if err != nil { return err } @@ -1399,15 +1413,15 @@ func resetSnapshotMtimes(dir string, t time.Time) error { return nil } if d.Type()&os.ModeSymlink != 0 { - return lchtimes(p, t) + return lchtimes(filepath.Join(root.Name(), p), t) } - return os.Chtimes(p, t, t) + return root.Chtimes(p, t, t) }) if err != nil { return err } for i := len(dirs) - 1; i >= 0; i-- { - if err := os.Chtimes(dirs[i], t, t); err != nil { + if err := root.Chtimes(dirs[i], t, t); err != nil { return err } } @@ -1420,8 +1434,8 @@ func resetSnapshotMtimes(dir string, t time.Time) error { // left untouched: their pre-v0.15 behavior is not covered by the current // compatibility matrix, and blindly adding write bits to 0o755 would be a // guess. -func resetCompatibility014FileModes(dir string) error { - return filepath.WalkDir(dir, func(p string, d os.DirEntry, err error) error { +func resetCompatibility014FileModes(root *os.Root) error { + return fs.WalkDir(root.FS(), ".", func(p string, d os.DirEntry, err error) error { if err != nil { return err } @@ -1437,7 +1451,7 @@ func resetCompatibility014FileModes(dir string) error { if !mode.IsRegular() || mode&0o111 != 0 { return nil } - return os.Chmod(p, mode|0o222) + return root.Chmod(p, mode|0o222) }) } diff --git a/source/git/source_test.go b/source/git/source_test.go index 3adeb9ed7..a7b2ed53a 100644 --- a/source/git/source_test.go +++ b/source/git/source_test.go @@ -2016,13 +2016,17 @@ func testCheckSignatures(t *testing.T, keepGitDir bool, format string) { fixturesBase := os.Getenv("BUILDKIT_TEST_SIGN_FIXTURES") - user1GPGPub, err := os.ReadFile(fixturesBase + "/user1.gpg.pub") + fixturesRoot, err := os.OpenRoot(fixturesBase) + require.NoError(t, err) + defer fixturesRoot.Close() + + user1GPGPub, err := fixturesRoot.ReadFile("user1.gpg.pub") require.NoError(t, err) err = gitsign.VerifySignature(ob, user1GPGPub, nil) require.NoError(t, err) - user2GPGPub, err := os.ReadFile(fixturesBase + "/user2.gpg.pub") + user2GPGPub, err := fixturesRoot.ReadFile("user2.gpg.pub") require.NoError(t, err) err = gitsign.VerifySignature(ob, user2GPGPub, nil) @@ -2052,10 +2056,10 @@ func testCheckSignatures(t *testing.T, keepGitDir bool, format string) { require.NoError(t, err) require.Greater(t, len(ob.Signature), 50) - sshkey1, err := os.ReadFile(fixturesBase + "/user1.ssh.pub") + sshkey1, err := fixturesRoot.ReadFile("user1.ssh.pub") require.NoError(t, err) - sshkey2, err := os.ReadFile(fixturesBase + "/user2.ssh.pub") + sshkey2, err := fixturesRoot.ReadFile("user2.ssh.pub") require.NoError(t, err) err = gitsign.VerifySignature(ob, sshkey2, nil) @@ -2107,16 +2111,20 @@ func testVerifySignatures(t *testing.T, keepGitDir bool, format string) { fixturesBase := os.Getenv("BUILDKIT_TEST_SIGN_FIXTURES") - user1GPGPub, err := os.ReadFile(fixturesBase + "/user1.gpg.pub") + fixturesRoot, err := os.OpenRoot(fixturesBase) + require.NoError(t, err) + defer fixturesRoot.Close() + + user1GPGPub, err := fixturesRoot.ReadFile("user1.gpg.pub") require.NoError(t, err) - user2GPGPub, err := os.ReadFile(fixturesBase + "/user2.gpg.pub") + user2GPGPub, err := fixturesRoot.ReadFile("user2.gpg.pub") require.NoError(t, err) - user1SSHPub, err := os.ReadFile(fixturesBase + "/user1.ssh.pub") + user1SSHPub, err := fixturesRoot.ReadFile("user1.ssh.pub") require.NoError(t, err) - user2SSHPub, err := os.ReadFile(fixturesBase + "/user2.ssh.pub") + user2SSHPub, err := fixturesRoot.ReadFile("user2.ssh.pub") require.NoError(t, err) // a/v1.2.3 commit is signed by user1 gpg @@ -2672,7 +2680,7 @@ func logProgressStreams(ctx context.Context, t *testing.T) context.Context { go func() { defer close(done) for { - prog, err := pr.Read(context.Background()) + prog, err := pr.Read(ctx) if err != nil { return } @@ -2714,7 +2722,10 @@ func TestResetSnapshotMtimes(t *testing.T) { require.NoError(t, os.Symlink("file.txt", filepath.Join(dir, "link"))) target := time.Date(2023, 6, 15, 12, 0, 0, 0, time.UTC) - require.NoError(t, resetSnapshotMtimes(dir, target)) + root, err := os.OpenRoot(dir) + require.NoError(t, err) + require.NoError(t, resetSnapshotMtimes(root, target)) + require.NoError(t, root.Close()) // Regular files should have mtime set fi, err := os.Lstat(filepath.Join(dir, "file.txt")) diff --git a/util/appdefaults/appdefaults_unix.go b/util/appdefaults/appdefaults_unix.go index a351a7944..beb2e39e7 100644 --- a/util/appdefaults/appdefaults_unix.go +++ b/util/appdefaults/appdefaults_unix.go @@ -37,11 +37,15 @@ func EnsureUserAddressDir() error { xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR") if xdgRuntimeDir != "" { dirs := strings.Split(xdgRuntimeDir, ":") - dir := filepath.Join(dirs[0], "buildkit") - if err := os.MkdirAll(dir, 0700); err != nil { + root, err := os.OpenRoot(dirs[0]) + if err != nil { return err } - return os.Chmod(dir, 0700|os.ModeSticky) + defer root.Close() + if err := root.MkdirAll("buildkit", 0700); err != nil { + return err + } + return root.Chmod("buildkit", 0700|os.ModeSticky) } return nil } diff --git a/util/leaseutil/manager.go b/util/leaseutil/manager.go index da90a6827..5ccb9eefc 100644 --- a/util/leaseutil/manager.go +++ b/util/leaseutil/manager.go @@ -47,8 +47,8 @@ type LeaseRef struct { err error } -func (l *LeaseRef) Discard() error { - return l.lm.Delete(context.Background(), l.l) +func (l *LeaseRef) Discard(ctx context.Context) error { + return l.lm.Delete(context.WithoutCancel(ctx), l.l) } func (l *LeaseRef) Adopt(ctx context.Context) error { @@ -73,10 +73,10 @@ func (l *LeaseRef) Adopt(ctx context.Context) error { } } if len(l.resources) == 0 { - l.Discard() + l.Discard(ctx) return nil } - go l.Discard() + go l.Discard(ctx) return nil } diff --git a/util/network/cniprovider/cni_linux.go b/util/network/cniprovider/cni_linux.go index 526fc71bc..3279a9017 100644 --- a/util/network/cniprovider/cni_linux.go +++ b/util/network/cniprovider/cni_linux.go @@ -83,8 +83,13 @@ func readFileAt(dirfd int, filename string, buf []byte) (int64, error) { // https://github.com/containerd/nerdctl/pull/2723 func withDetachedNetNSIfAny(ctx context.Context, fn func(context.Context) error) error { if stateDir := os.Getenv("ROOTLESSKIT_STATE_DIR"); stateDir != "" { - detachedNetNS := filepath.Join(stateDir, "netns") - if _, err := os.Lstat(detachedNetNS); !errors.Is(err, os.ErrNotExist) { + root, err := os.OpenRoot(stateDir) + if err != nil { + return err + } + defer root.Close() + if _, err := root.Lstat("netns"); !errors.Is(err, os.ErrNotExist) { + detachedNetNS := filepath.Join(stateDir, "netns") return ns.WithNetNSPath(detachedNetNS, func(_ ns.NetNS) error { ctx := context.WithValue(ctx, contextKeyDetachedNetNS, detachedNetNS) bklog.G(ctx).Debugf("Entering RootlessKit's detached netns %q", detachedNetNS) @@ -92,6 +97,8 @@ func withDetachedNetNSIfAny(ctx context.Context, fn func(context.Context) error) bklog.G(ctx).WithError(err2).Debugf("Leaving RootlessKit's detached netns %q", detachedNetNS) return err2 }) + } else if err != nil { + return err } } return fn(ctx) diff --git a/util/progress/multireader.go b/util/progress/multireader.go index bcc9eb897..3a1b15b67 100644 --- a/util/progress/multireader.go +++ b/util/progress/multireader.go @@ -100,16 +100,16 @@ func (mr *MultiReader) Reader(ctx context.Context) Reader { }() if !mr.initialized { - go mr.handle() + go mr.handle(context.WithoutCancel(ctx)) mr.initialized = true } return pr } -func (mr *MultiReader) handle() error { +func (mr *MultiReader) handle(ctx context.Context) error { for { - p, err := mr.main.Read(context.TODO()) + p, err := mr.main.Read(ctx) if err != nil { if errors.Is(err, io.EOF) { mr.mu.Lock() diff --git a/util/pull/pullprogress/progress.go b/util/pull/pullprogress/progress.go index df56b985a..fa71d69fa 100644 --- a/util/pull/pullprogress/progress.go +++ b/util/pull/pullprogress/progress.go @@ -31,9 +31,9 @@ func (p *ProviderWithProgress) ReaderAt(ctx context.Context, desc ocispecs.Descr return nil, err } - ctx, cancel := context.WithCancelCause(ctx) + progressCtx, cancel := context.WithCancelCause(context.WithoutCancel(ctx)) doneCh := make(chan struct{}) - go trackProgress(ctx, desc, p.Manager, doneCh) + go trackProgress(progressCtx, desc, p.Manager, doneCh) //nolint:gosec // Progress tracking is tied to the reader lifetime and canceled by Close. return readerAtWithCancel{ReaderAt: ra, cancel: cancel, doneCh: doneCh, logger: bklog.G(ctx)}, nil } @@ -65,9 +65,9 @@ func (f *FetcherWithProgress) Fetch(ctx context.Context, desc ocispecs.Descripto return nil, err } - ctx, cancel := context.WithCancelCause(ctx) + progressCtx, cancel := context.WithCancelCause(context.WithoutCancel(ctx)) doneCh := make(chan struct{}) - go trackProgress(ctx, desc, f.Manager, doneCh) + go trackProgress(progressCtx, desc, f.Manager, doneCh) //nolint:gosec // Progress tracking is tied to the reader lifetime and canceled by Close. return readerWithCancel{ReadCloser: rc, cancel: cancel, doneCh: doneCh, logger: bklog.G(ctx)}, nil } diff --git a/util/testutil/integration/registry.go b/util/testutil/integration/registry.go index 0cbc74342..2c595a014 100644 --- a/util/testutil/integration/registry.go +++ b/util/testutil/integration/registry.go @@ -38,7 +38,13 @@ func NewRegistry(dir string) (url string, cl func() error, err error) { dir = tmpdir } - if _, err := os.Stat(filepath.Join(dir, "config.yaml")); err != nil { + root, err := os.OpenRoot(dir) + if err != nil { + return "", nil, errors.WithStack(err) + } + defer root.Close() + + if _, err := root.Stat("config.yaml"); err != nil { if !errors.Is(err, os.ErrNotExist) { return "", nil, err } @@ -51,7 +57,7 @@ http: addr: 127.0.0.1:0 `, filepath.Join(dir, "data")) - if err := os.WriteFile(filepath.Join(dir, "config.yaml"), []byte(template), 0600); err != nil { + if err := root.WriteFile("config.yaml", []byte(template), 0600); err != nil { return "", nil, err } } diff --git a/worker/base/worker.go b/worker/base/worker.go index 8fcb47231..b81967b33 100644 --- a/worker/base/worker.go +++ b/worker/base/worker.go @@ -395,7 +395,7 @@ func (w *Worker) PruneCacheMounts(ctx context.Context, ids map[string]bool) erro } // if ref is unused try to clean it up right away by releasing it if mref, err := w.CacheMgr.GetMutable(ctx, md.ID()); err == nil { - go mref.Release(context.TODO()) + go mref.Release(context.WithoutCancel(ctx)) } } }