← Back to issue list

fix: synchronize with udev via BSD flock after losetup to avoid race condition

View original Github issue

Metadata

Project
imagecraft
Number
#330
Type
pull request
State
open
Author
Copilot
Labels
Created
Updated
Closed

Current evaluation

Adds BSD flock synchronization after losetup to avoid the udev race on loop partition nodes, in both pack and services attach paths, with unit and root integration tests. Changes requested; 6 unresolved comments; lint/files failing; awaiting maintainer review of latest commit.

Suggested action: needs review

Reason: After lengau's 2026-05-03 request for an integration test, the author added test_attach_images_partition_nodes_exist in 8cc64c5, but no maintainer has reviewed that commit and the review status remains changes_requested with 6 unresolved comments plus a failing lint/files check. The underlying issue #300 is still open and was hit in CI ~19 days ago, so the PR is still relevant and needs a maintainer review of the latest iteration rather than closure.

Impact: 55 Quick Win: 22.0 Staleness: 55 Complexity: 60 Confidence: 75

Issue body

After `losetup --find --show --partscan`, udev holds an exclusive BSD flock on the whole-disk device while processing it. Mounting immediately after attach can fail with `special device /dev/loopNpM does not exist` because udev's inotify watch hasn't finished. The correct fix per <a href="https://systemd.io/BLOCK_DEVICE_LOCKING/">systemd BLOCK_DEVICE_LOCKING</a> is to briefly acquire a shared flock on the loop device as a synchronization barrier — blocking until udev releases its exclusive lock — then release it immediately so udev remains free to process further events. ## Changes - **`imagecraft/pack/image.py`** - `Image.attach_loopdev()` briefly acquires `fcntl.LOCK_SH` on the loop device after attaching (inside the fresh-attach branch). The lock is acquired and released before `yield`, ensuring udev has finished processing without holding the lock for the duration of the context manager. - **`imagecraft/services/image.py`** - `ImageService.attach_images()` acquires and immediately releases `LOCK_SH` on each loop device (fresh and reused) using a `with open(dev, "rb") as loop_fd: flock(...)` block. No persistent file handles are stored; no flock cleanup is needed in `detach_images()`. - **Tests** - Removed polling-based tests; tests now mock `fcntl.flock` and `builtins.open` - Added `test_attach_images_flock_sync_and_release` (unit) to verify the shared lock is acquired and immediately released (not held persistently) - Added `test_attach_images_partition_nodes_exist` (integration, requires root) to verify that every partition device node returned by `get_loop_paths()` actually exists on the filesystem as a block device immediately after `attach_images()` returns — directly demonstrating that the flock synchronization prevents the udev race condition ```python # After losetup --find --show --partscan returns /dev/loop7: with open("/dev/loop7", "rb") as loop_fd: fcntl.flock(loop_fd, fcntl.LOCK_SH) # blocks until udev is done, then releases # lock released — partition nodes are guaranteed to exist, udev free to continue yield "/dev/loop7" ```

Evaluation history

Date Model Scores Action Summary
qwen/qwen3.8-27b
Impact: 55
Quick Win: 22.0
Staleness: 55
Complexity: 60
Confidence: 75
needs review Adds BSD flock synchronization after losetup to avoid the udev race on loop partition nodes, in both pack and services attach paths, with unit and root integration tests. Changes requested; 6 unresolved comments; lint/files failing; awaiting maintainer review of latest commit.
qwen/qwen3.6-35b-a3b
Staleness: 60
Complexity: 45
Confidence: 75
needs review Fixes a udev race condition after losetup by using BSD flock as a synchronization barrier. Currently has 6 unresolved review comments, a failing lint check, and pending maintainer validation of the approach.
qwen3.6-35b-a3b-mtp-q6
Staleness: 65
Complexity: 60
Confidence: 40
needs review Fixes a udev race condition after losetup by using BSD flock as a synchronization barrier. Maintainer doubts correctness; integration test added but technical feedback remains unresolved.
qwen3.6-35b-a3b-mtp-q6
Staleness: 40
Complexity: 45
Confidence: 75
needs review Implements BSD flock synchronization after losetup to resolve udev partition race conditions. Addresses maintainer feedback and adds integration tests verifying partition node existence.
qwen3.6-35b-a3b-mtp-q6
Staleness: 45
Complexity: 60
Confidence: 80
needs review Fixes a loop device mount race by using BSD flock to synchronize with udev. Maintainer requested locking and test adjustments, which have been applied. Currently under active review.

Update history

No update history recorded yet.

Related work

  • Caused By: canonical/imagecraft#300 (confidence 90%)

    Issue #300 describes the same 'special device /dev/loopNpM does not exist' race after losetup --partscan and is still open with the failure recurring in CI; this PR is the flock-based fix for it.

Related issues

Issue Project State Summary Similarity
#340 fix: Avoid races with udev and loop devices imagecraft open Adds flock LOCK_EX on the whole-disk node during mkfs and across loop partition mounts to fix udev/loop-device races; supersedes #330's approach. Open 118 days with no review or comments; CI mostly green but lint, title policy, and snap-builds checks failing.
78%