Retry resize2fs on transient Permission denied during persistent disk grow - #463
Retry resize2fs on transient Permission denied during persistent disk grow#463neddp wants to merge 4 commits into
resize2fs on transient Permission denied during persistent disk grow#463Conversation
When a persistent disk is extended online, the block device's new size may not yet be consistently visible to the guest at the time the agent calls resize2fs. This causes a transient EPERM that resolves once the underlying storage layer settles. Retry resize2fs up to 10 times with a 5s sleep between attempts, but only on "Permission denied to resize filesystem" — any other error still fails immediately. Follows the same clock-injection pattern used by NewPartedPartitioner and NewSfdiskPartitioner in the same package.
WalkthroughThe Linux formatter now accepts a clock service. Ext4 growth delegates to a retry helper. Permission-denied Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@platform/disk/linux_formatter.go`:
- Around line 112-120: Update the retry loop around resize2fs in
platform/disk/linux_formatter.go lines 112-120 to sleep only when another
attempt remains, preserving immediate returns for success and non-permission
errors. Update the corresponding expectation in
platform/disk/linux_formatter_test.go lines 308-315 to assert nine sleeps for
ten failed attempts.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 9b65b799-b77b-4ae5-bdf3-dcbcb623e607
📒 Files selected for processing (3)
platform/disk/linux_disk_manager.goplatform/disk/linux_formatter.goplatform/disk/linux_formatter_test.go
There was a problem hiding this comment.
Pull request overview
Adds targeted retry logic around resize2fs during online ext4 filesystem growth to mitigate transient EPERM (“Permission denied to resize filesystem”) observed on some IaaS environments. This is implemented with an injected clock to make retry delays testable and updates the disk manager wiring and unit tests accordingly.
Changes:
- Inject
clock.ClockintoNewLinuxFormatterand use it to sleep betweenresize2fsretries. - Add ext4 grow retry logic gated specifically on the “Permission denied to resize filesystem” error substring.
- Extend
platform/diskunit specs to cover retryable vs non-retryableresize2fsfailures.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| platform/disk/linux_formatter.go | Adds retry wrapper for ext4 grow and injects a clock for testable delays. |
| platform/disk/linux_formatter_test.go | Updates formatter construction and adds specs validating retry behavior. |
| platform/disk/linux_disk_manager.go | Updates formatter instantiation to pass a real clock. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sleep only between retries (not after the last failure). The loop now performs one initial attempt plus up to 10 retries, sleeping before each retry — 11 total resize2fs calls, 10 sleeps, 50s max delay. Rename growFilesystemMaxAttempts to growFilesystemMaxRetries to match the PR description semantics.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
platform/disk/linux_formatter.go:30
NewLinuxFormatteris an exported constructor in a non-internal/package, so changing its signature is a breaking API change for any downstream Go code that importsgithub.com/cloudfoundry/bosh-agent/v2/platform/disk. The PR description says this is internal/no external consumers; that may be true in practice, but it’s not enforced by the package structure. Consider keeping the existingNewLinuxFormatter(runner, fs)signature as a compatibility wrapper (calling a new clock-injectable constructor) if you want to avoid a breaking change.
func NewLinuxFormatter(runner boshsys.CmdRunner, fs boshsys.FileSystem, timeService clock.Clock) Formatter {
return linuxFormatter{
runner: runner,
fs: fs,
timeService: timeService,
}
NewLinuxFormatter is exported from a non-internal package, so changing its signature is a breaking API change for downstream importers. Restore the original two-arg signature as a compatibility wrapper and introduce NewLinuxFormatterWithClock for clock injection in tests.
|
The root cause was actually a corrupted file system. Unfortunately, the error from |
|
We could do a if it fails to check for a quick file system corruption? Or add a extra debugging line. That mentions that filesystem could be corrupted |
|
Hi @ramonskie, I looked into it and we'll need to check the kernel logs. It didn't sound like it's worth the effort and additional code for such an edge case. I think the Something else we noticed. We ran into this issue in a CI pipeline and it fails the first time (partition resized, the filesystem fails to be resized). Any following runs actually succeed, since the code does not check if there is a discrepancy between the partition and filesystem size. I tried to add a new check with #465, but I didn't like the implementation and couldn't think of a better one. |
|
Maby put it within the bosh docs then? |
|
Documented with cloudfoundry/docs-bosh#918. |
What is this change about?
When a persistent disk is extended online, the agent calls
resize2fsto grow the ext4 filesystem after resizing the partition. We noticed this on OpenStack and it fails transiently with:The
EXT4_IOC_RESIZE_FSioctl returns EPERM when the kernel cannot yet confirm the block device's new size - a race between the storage layer acknowledging the extension and the guest-visible device reflecting it. The error resolves on its own once the storage layer settles.This change retries
resize2fsup to 10 times with a 5s sleep between attempts, but only on"Permission denied to resize filesystem"- any other error still fails immediately. Maximum additional wait before giving up: 50 seconds.Please provide contextual information.
Observed repeatedly in production during a disk type change (
100G→1T).The fix follows the existing clock-injection pattern used by
NewPartedPartitionerandNewSfdiskPartitionerin the same package, making the retry delay injectable for tests. The originalNewLinuxFormatter(runner, fs)signature is preserved; a newNewLinuxFormatterWithClock(runner, fs, clock)is added for test injection.What tests have you run against this PR?
platform/diskunit test suite: 173 passed, 0 failedSleepCallCount() == 0)How should this change be described in bosh-agent release notes?
Persistent disk grows that fail with a transient "Permission denied" from
resize2fsare now retried automatically (up to 10 times, 5s apart), avoiding deploy failures during online disk extension on affected IaaS environments.Does this PR introduce a breaking change?
No. The
NewLinuxFormatter(runner, fs)signature is unchanged. A newNewLinuxFormatterWithClock(runner, fs, clock)constructor is added alongside it for clock injection in tests.