Skip to content

Skip reuse of removed layers in copyFileFromOtherLayer#890

Open
Honny1 wants to merge 1 commit into
podman-container-tools:mainfrom
Honny1:flake-partial-pull
Open

Skip reuse of removed layers in copyFileFromOtherLayer#890
Honny1 wants to merge 1 commit into
podman-container-tools:mainfrom
Honny1:flake-partial-pull

Conversation

@Honny1
Copy link
Copy Markdown
Contributor

@Honny1 Honny1 commented Jun 4, 2026

When copyFileFromOtherLayer opens a source layer directory that was removed by a concurrent rmi, return "not found" instead of a fatal error so the differ fetches content from the remote blob instead.

Fixes podman flake: quadlet - kube build from unavailable image with no tag

not ok 271 |252| quadlet - kube build from unavailable image with no tag in 8211ms

# tags: ci:parallel
# (from function `systemctl_start' in file test/system/helpers.systemd.bash, line 91,
#  from function `service_setup' in file test/system/252-quadlet.bats, line 117,
#  in test file test/system/252-quadlet.bats, line 1915)
#   `service_setup $QUADLET_SERVICE_NAME' failed
#
# [04:29:50.769995278] # /var/tmp/podman/bin/podman  rmi -i quay.io/libpod/busybox:latest
# # /var/tmp/podman/bin/quadlet  /run/systemd/system
#
# # Automatically generated by /var/tmp/podman/bin/quadlet
# #
# [X-Kube]
# Yaml=/tmp/podman_bats.7mPsrV/quadlets/built-t271-17q7xio9/build_t271-17q7xio9.yaml
# PodmanArgs=--build
# SetWorkingDirectory=yaml
#
# [Unit]
# Wants=network-online.target
# After=network-online.target
# SourcePath=/tmp/podman_bats.7mPsrV/quadlet.WmxqUC/build_t271-17q7xio9.kube
# RequiresMountsFor=%t/containers
#
# [Service]
# KillMode=mixed
# Environment=PODMAN_SYSTEMD_UNIT=%n
# Type=notify
# NotifyAccess=all
# SyslogIdentifier=%N
# ExecStart=/var/tmp/podman/bin/podman kube play --replace --service-container=true --build /tmp/podman_bats.7mPsrV/quadlets/built-t271-17q7xio9/build_t271-17q7xio9.yaml
# ExecStopPost=/var/tmp/podman/bin/podman kube down /tmp/podman_bats.7mPsrV/quadlets/built-t271-17q7xio9/build_t271-17q7xio9.yaml
# WorkingDirectory=/tmp/podman_bats.7mPsrV/quadlets/built-t271-17q7xio9
# # systemctl  start build_t271-17q7xio9.service
# Job for build_t271-17q7xio9.service failed because the control process exited with error code.
# See "systemctl status build_t271-17q7xio9.service" and "journalctl -xeu build_t271-17q7xio9.service" for details.
#
# ***** systemctl start build_t271-17q7xio9.service -- FAILED!
#
# # systemctl status build_t271-17q7xio9.service
# × build_t271-17q7xio9.service
#      Loaded: loaded (/tmp/podman_bats.7mPsrV/quadlet.WmxqUC/build_t271-17q7xio9.kube; static)
#     Drop-In: /usr/lib/systemd/system/service.d
#              └─10-timeout-abort.conf
#      Active: failed (Result: exit-code) since Thu 2026-06-04 04:29:56 UTC; 68ms ago
#  Invocation: 78ab0ab943ae41d988c244da9fd3e7f4
#     Process: 301037 ExecStopPost=/var/tmp/podman/bin/podman kube down /tmp/podman_bats.7mPsrV/quadlets/built-t271-17q7xio9/build_t271-17q7xio9.yaml (code=exited, status=0/SUCCESS)
#    Main PID: 300161 (code=exited, status=125)
#    Mem peak: 21.4M
#         CPU: 405ms
#
# Jun 04 04:29:55 lima-podman-ci podman[301037]: 2026-06-04 04:29:55.993666304 +0000 UTC m=+1.636544423 pod remove 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0 (image=, name=p-t271-17q7xio9)
# Jun 04 04:29:56 lima-podman-ci podman[301037]: 2026-06-04 04:29:56.000648439 +0000 UTC m=+1.643526338 container remove 474f6844db7fcaae6e74e9d68718b05007f7176d7a4ab1d21d4dd7c9976fd5d8 (image=, name=801b5239fda1-service, PODMAN_SYSTEMD_UNIT=build_t271-17q7xio9.service)
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Pods stopped:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Pods removed:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Secrets removed:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Volumes removed:
# Jun 04 04:29:56 lima-podman-ci systemd[1]: build_t271-17q7xio9.service: Failed with result 'exit-code'.
# Jun 04 04:29:56 lima-podman-ci systemd[1]: Failed to start build_t271-17q7xio9.service.
#
# # journalctl -xeu build_t271-17q7xio9.service
# Jun 04 04:29:53 lima-podman-ci systemd[1]: Starting build_t271-17q7xio9.service...
# ░░ Subject: A start job for unit build_t271-17q7xio9.service has begun execution
# ░░ Defined-By: systemd
# ░░ Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
# ░░
# ░░ A start job for unit build_t271-17q7xio9.service has begun execution.
# ░░
# ░░ The job identifier is 42348.
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Pods stopped:
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Pods removed:
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Secrets removed:
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Volumes removed:
# Jun 04 04:29:53 lima-podman-ci podman[300161]: 2026-06-04 04:29:53.508900468 +0000 UTC m=+0.069147268 network create 820b7a062fb7172bb962ae4c03a5d22df79ff427c900f175135aa18ea8fd5e44 (name=podman-default-kube-network, type=bridge)
# Jun 04 04:29:53 lima-podman-ci podman[300161]: 2026-06-04 04:29:53.538473872 +0000 UTC m=+0.098720622 container create 474f6844db7fcaae6e74e9d68718b05007f7176d7a4ab1d21d4dd7c9976fd5d8 (image=, name=801b5239fda1-service, PODMAN_SYSTEMD_UNIT=build_t271-17q7xio9.service)
# Jun 04 04:29:53 lima-podman-ci podman[300161]: 2026-06-04 04:29:53.62629594 +0000 UTC m=+0.186542660 container create 171087b5dfa2fbec5bdc9d50a3d91296b9e6ccac30a313f847ff49ef44ccd8b1 (image=, name=13ddf6a58aed-infra, pod_id=13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0, PODMAN_SYSTEMD_UNIT=build_t271-17q7xio9.service)
# Jun 04 04:29:53 lima-podman-ci podman[300161]: 2026-06-04 04:29:53.626446449 +0000 UTC m=+0.186693238 pod create 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0 (image=, name=p-t271-17q7xio9)
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: STEP 1/1: FROM quay.io/libpod/busybox
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Trying to pull quay.io/libpod/busybox:latest...
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Pulling image //quay.io/libpod/busybox:latest inside systemd: setting pull timeout to 5m0s
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Getting image source signatures
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Copying blob sha256:9758c28807f21c13d05c704821fdd56c0b9574912f9b916c65e1df3e6b8bc572
# Jun 04 04:29:53 lima-podman-ci podman[300161]: 2026-06-04 04:29:53.880330667 +0000 UTC m=+0.440577537 image build
# Jun 04 04:29:53 lima-podman-ci build_t271-17q7xio9[300161]: Error: creating build container: unable to copy from source docker://quay.io/libpod/busybox:latest: copying system image from manifest list: partial pull of blob sha256:9758c28807f21c13d05c704821fdd56c0b9574912f9b916c65e1df3e6b8bc572: staging a partially-pulled layer: open /var/lib/containers/storage/overlay/7ffd7a2b9a8f5c3c0380c79e24059605cf353be164d3870658eca385ffc89535/diff: no such file or directory
# Jun 04 04:29:54 lima-podman-ci systemd[1]: build_t271-17q7xio9.service: Main process exited, code=exited, status=125/n/a
# ░░ Subject: Unit process exited
# ░░ Defined-By: systemd
# ░░ Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
# ░░
# ░░ An ExecStart= process belonging to unit build_t271-17q7xio9.service has exited.
# ░░
# ░░ The process' exit code is 'exited' and its exit status is 125.
# Jun 04 04:29:54 lima-podman-ci podman[301037]: 2026-06-04 04:29:54.387352461 +0000 UTC m=+0.030230329 pod stop 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0 (image=, name=p-t271-17q7xio9)
# Jun 04 04:29:54 lima-podman-ci podman[301037]: 2026-06-04 04:29:54.484166382 +0000 UTC m=+0.127044190 container remove 171087b5dfa2fbec5bdc9d50a3d91296b9e6ccac30a313f847ff49ef44ccd8b1 (image=, name=13ddf6a58aed-infra, pod_id=13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0, PODMAN_SYSTEMD_UNIT=build_t271-17q7xio9.service)
# Jun 04 04:29:55 lima-podman-ci podman[301037]: 2026-06-04 04:29:55.993666304 +0000 UTC m=+1.636544423 pod remove 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0 (image=, name=p-t271-17q7xio9)
# Jun 04 04:29:56 lima-podman-ci podman[301037]: 2026-06-04 04:29:56.000648439 +0000 UTC m=+1.643526338 container remove 474f6844db7fcaae6e74e9d68718b05007f7176d7a4ab1d21d4dd7c9976fd5d8 (image=, name=801b5239fda1-service, PODMAN_SYSTEMD_UNIT=build_t271-17q7xio9.service)
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Pods stopped:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Pods removed:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: 13ddf6a58aedaba54dbe02819da78f65233bed6150374b5122c7d2878aea60d0
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Secrets removed:
# Jun 04 04:29:56 lima-podman-ci build_t271-17q7xio9[301037]: Volumes removed:
# Jun 04 04:29:56 lima-podman-ci systemd[1]: build_t271-17q7xio9.service: Failed with result 'exit-code'.
# ░░ Subject: Unit failed
# ░░ Defined-By: systemd
# ░░ Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
# ░░
# ░░ The unit build_t271-17q7xio9.service has entered the 'failed' state with result 'exit-code'.
# Jun 04 04:29:56 lima-podman-ci systemd[1]: Failed to start build_t271-17q7xio9.service.
# ░░ Subject: A start job for unit build_t271-17q7xio9.service has failed
# ░░ Defined-By: systemd
# ░░ Support: https://lists.freedesktop.org/mailman/listinfo/systemd-devel
# ░░
# ░░ A start job for unit build_t271-17q7xio9.service has finished with a failure.
# ░░
# ░░ The job identifier is 42348 and the job result is failed.
# # [teardown]

The test (tagged ci:parallel) removes quay.io/libpod/busybox:latest with rmi -i, then a systemd service re-pulls it via podman kube play --build. During the partial pull, the chunked differ's layers cache (getLayersCache(store)) finds a reference to local layer 7ffd7a2b... for content reuse. When copyFileFromOtherLayer tries to open that layer's diff directory, it gets ENOENT because rmi already deleted the overlay.

Fix (in storage/pkg/chunked/storage_linux.go): The fix belongs in storage where the layers cache is consulted. When copyFileFromOtherLayer opens a source layer directory that no longer exists, it should return "not found" (skip reuse) rather than a fatal error.

@github-actions github-actions Bot added the image Related to "image" package label Jun 4, 2026
@Honny1
Copy link
Copy Markdown
Contributor Author

Honny1 commented Jun 4, 2026

I am not sure how to test this since it fixes the flaking test.

@Luap99
Copy link
Copy Markdown
Member

Luap99 commented Jun 4, 2026

If you fix flakes it is always good to include a log and/or example failure output so reviewers can verify that your theory makes sense.

Copy link
Copy Markdown
Contributor

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the failure log + path?

Intuitively, this fix looks unlikely.

  • Most importantly, the storage should be in control of the fallback path: if convert_images is set, we must not fallback (“the user wants composefs and we don’t have a non-partial-pull composefs code path”)
  • IIRC nothing in the partial pull code path references the BlobInfoCache.
  • PrepareStagedLayer can easily fail on network issues, but that should be handled by a higher-level retry like c/common/pkg/retry. This fallback is not the right mechanism for handling transient network errors.

@mtrmac
Copy link
Copy Markdown
Contributor

mtrmac commented Jun 4, 2026

Most importantly, the storage should be in control of the fallback path

= return chunked.ErrFallbackToOrdinaryLayerDownload in the right cases, or not. Matching on any ErrNotExist is a pretty coarse filter.

When `copyFileFromOtherLayer` opens a source layer directory that was
removed by a concurrent `rmi`, return "not found" instead of a fatal
error so the differ fetches content from the remote blob instead.

Fixes podman flake: "quadlet - kube build from unavailable image with no tag

Signed-off-by: Jan Rodák <hony.com@seznam.cz>
@Honny1 Honny1 force-pushed the flake-partial-pull branch from 4e35efb to 6114e0a Compare June 5, 2026 13:46
@github-actions github-actions Bot added the storage Related to "storage" package label Jun 5, 2026
@Honny1 Honny1 changed the title Fall back to full pull on PrepareStagedLayer ENOENT Skip reuse of removed layers in copyFileFromOtherLayer Jun 5, 2026
@Honny1 Honny1 removed the image Related to "image" package label Jun 5, 2026
@Honny1 Honny1 marked this pull request as ready for review June 5, 2026 14:04
@Honny1 Honny1 requested review from Luap99 and mtrmac June 5, 2026 14:04
Copy link
Copy Markdown
Contributor

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= we build the cache in layersCache.load (within chunked.NewDiffer), that temporarily locks the store but we don’t hold any locks between then and PrepareStagedLayer, so the layer can be removed in the meantime.

Thanks, that makes sense to me.

Cc: @giuseppe


Note that PrepareStagedLayer does not hold a storage lock at all, so we might succeed in opening srcDirfd here, but still fail opening srcFile if the layer is concurrently being deleted.


I think the findChunkInOtherLayers path should also check for a missing file… and that might be a more difficult fix because we build a list of ranges to download, and later we might find that the chunk has been removed in the meantime.

I’m not sure what is a good fix here — in principle we need to fall back to downloading from the remote, that might be a fairly invasive restructuring.

Maybe, for now, we can just have the initial checksum computation resilient, and still flake/fail if the file is removed concurrently (+ filing an issue to track the outstanding case) — that way the recurring flake would be fixed and not blocked on a larger redesign. But I might well be missing something here, maybe the restructuring is easy, maybe we can do something else here. (Keep an open file descriptor? Probably not.)

@giuseppe
Copy link
Copy Markdown
Contributor

giuseppe commented Jun 5, 2026

(Keep an open file descriptor? Probably not.)

we will need some more fixes around handling ENOENT, but I think this should fix the root issue because the file will still be accessible.

@giuseppe
Copy link
Copy Markdown
Contributor

giuseppe commented Jun 5, 2026

(Keep an open file descriptor? Probably not.)

we will need some more fixes around handling ENOENT, but I think this should fix the root issue because the file will still be accessible.

I've asked Claude Code to implement this logic (keep an open file descriptor and use that), I've got this:

#892

I've reviewed and it makes sense to me, but I've not tested it yet

@mtrmac
Copy link
Copy Markdown
Contributor

mtrmac commented Jun 5, 2026

(Keep an open file descriptor? Probably not.)

we will need some more fixes around handling ENOENT, but I think this should fix the root issue because the file will still be accessible.

Without some extra trick, I don’t think we can rely on keeping… potentially millions of file descriptors open concurrently.

Copy link
Copy Markdown
Contributor

@giuseppe giuseppe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

I'll deal separately with the chunks deduplication race condition

@Luap99
Copy link
Copy Markdown
Member

Luap99 commented Jun 5, 2026

This needs to rebased to properly trigger CI.

As for the logic I cannot really speak to that code paths and have no time to dive deeper into but if @giuseppe is good with it that is good enough for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

storage Related to "storage" package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants