Storage pool capacity TSG: capacity-pressure guidance and correct VM-offline handling (follow-up to #300)#312
Conversation
…offline handling Follow-up to Azure#300 addressing the post-merge change request (add capacity escalation guidance; steer away from "pause VM" under capacity pressure). - Clarify pool allocation vs volume fill: the 80/90 figures are the default *volume* CapacityThreshold.Warning/.Critical health settings, not pool auto-actions. The pool raises only the configurable 70% thin alert (PoolCapacityThresholdExceeded) and the reserve-capacity fault, and goes read-only only on quorum loss or admin policy -- there is no 80/90/95 pool ladder and no capacity-based read-only "block." Verified against Microsoft Learn, Azure Local Health Service settings, and the product fault model. - Add "what happens if the pool fills" escalation plus an ordered admin response (audit/prune, restrict provisioning, freeze auto-expansion, expand). - Add a CAUTION against saving VM state under capacity pressure: Save writes a memory-sized saved-state file to the volume, and a Save automatic stop action can flood an already-full CSV on a cluster-wide stop. Set the stop action to Shut Down; a node drain is space-safe (live-migrates). - Path B: prefer a clean Stop-VM shutdown (releases VHDX handles, no saved-state file), Stop-VM -TurnOff as fallback. Correct that Suspend-VM only pauses (memory in RAM, handles stay open, so consolidation cannot run) and that Save is what writes the memory-sized file. - References: add Health Service settings and Set-VM.
There was a problem hiding this comment.
Pull request overview
This is a documentation-only follow-up to #300 that refines the S2D storage pool capacity TSG (TSG/Storage/Troubleshoot-Storage-StoragePoolCapacityThreshold.md). It corrects a common misconception that the pool auto-escalates at 80/90/95% (those are per-volume Health Service thresholds; the pool only raises the configurable 70% thin-provisioning alert and reserve-capacity fault, and goes read-only only on quorum loss or admin policy). It adds capacity-escalation guidance with an ordered admin response, warns against saving VM state under capacity pressure (a saved-state file the size of VM memory can flood an already-full CSV), and reconciles Path B to prefer a clean Stop-VM guest shutdown over Suspend-VM.
Changes:
- New sections clarifying pool allocation vs. volume fill signals, and "what happens if the pool is allowed to fill" with an ordered remediation ladder and a CAUTION against saving VM state.
- Path B rewritten to use
Stop-VM/Stop-VM -TurnOff(shutdown, no saved-state file) andStart-VM, replacingSuspend-VM/Resume-VM, with an accompanying CAUTION explaining why suspend/save don't work for slab consolidation. - Added references for Health Service settings and
Set-VM.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
aldawson33
left a comment
There was a problem hiding this comment.
Good, necessary changes on the wording to best align w/ the product operations.
|
Thank you @AlBurns-MSFT for incorporating the feedback this way. Much appreciated. |
Karl-WE
left a comment
There was a problem hiding this comment.
Shall a PS command be added at this point?
- Identify low free space CSV, then identifying the related VMs and disks placed on this one, then putting this into an array so PS can loop through it with Get-VM | Set-VM?
|
Since 22H2 and later I am seeing a behaviour that when MSFT defrag runs slab consolidation on this provisioned CSV, file explorer will show an increased logical volume usage. This is usually not visible for CSV as the mounting point is hidden but is visible when using storage spaces thin provisioned volumes with a mount point displayed in file explorer. Repro: |
|
TSG grader results, storage pool capacity (fixed vs thin) I ran this through our TSG grader (static structure/safety lint plus a 13-reader persona usability panel) and also lab-tested the reclaim path. Overall it is a strong, technically precise guide: static lint A, usability 3.8/5. One correctness fix, a usability backlog, and one FYI. 1. Correctness fix, verified on a live cluster. In Path B, the documented command
On a CSV the Get-Volume -FilePath "C:\ClusterStorage\<volume>" | Optimize-Volume -SlabConsolidate -Verbose2. Usability work items (highest-leverage first).
3. FYI, not a defect: I could not reproduce the Path B reclaim on a nested lab. Across three fragmented-slab patterns, Nice touches already: the fixed-vs-thin framing and the explicit "SlabConsolidate does nothing on a fixed volume" guard are exactly right, and the Save-VM caution is a good catch. |
|
Update: Path B thin-volume reclaim validated live on physical hardware (ran cleanly). Following up on my earlier note. I ran the full reclaim validation end to end on a physical 3-node S2D cluster (build 2607) and it completed cleanly. Results and timing:
Real hardware clusters are required to see this remediation take effect. On a nested / VM-based substrate the same procedure had zero effect (every purgable slab came back "pinned unmovable", 0 bytes recovered, footprint flat for 20+ minutes). Only on a physical S2D cluster does The one command fix still worth making is the CSV form from my first comment: use |
Step 3 used `Optimize-Volume -Path "C:\ClusterStorage\<volume>"`, which fails on a CSV with "No MSFT_Volume objects found" because -Path binds to the volume's own path (MSFT_Volume.Path), not the CSV mount/access path. Resolve the CSV with `Get-Volume -FilePath` and pipe to Optimize-Volume instead, with a Format-List confirm step to guard against wrong-node/wrong-volume runs. Also enumerate the legitimate low/zero-recovery causes in the end-of-Path-B note (footprint already matches live data, or slabs pinned by in-use VMs/checkpoints) so operators check preconditions before escalating. Addresses review feedback on Azure#312. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks all for the careful review. Here is what I changed, how I validated it, and answers to the open questions. Correctness fix:
|
1008covingtonlane
left a comment
There was a problem hiding this comment.
Re-ran the grader on the updated head: correctness (now clean) plus the 13-reader usability panel.
Correctness, re-validated. The Step 3 fix and the VM-offline rewrite both hold up, no correctness issues left on my side. Get-Volume -FilePath "C:\ClusterStorage\<volume>" | Optimize-Volume -SlabConsolidate is the form I validated live, and the Format-List confirm before acting is a good guard. The Suspend-VM to Stop-VM change is a real correctness improvement: pausing keeps the VHDX handles open (so consolidation cannot reclaim), and the old "suspend writes a saved-state file" line was conflating pause with save. Stop-VM (or -TurnOff for a hung guest) releases the handles without writing a memory-sized state file, which matches the documented Hyper-V behavior.
Usability panel: 3.7/5. The hands-on correctness reads are already at 5 (the fixed-vs-thin gate, the corrected command, the CAUTION and Arc-VM guidance). The remaining gap is orientation for skimmers and beginners, which lines up with the usability follow-up you said you would take separately. For when you get to it, these five reader-driven items are what would carry the panel to 5/5:
- A top-of-doc at-a-glance box: business impact, who owns it (customer IT / storage, not network or OEM), rough duration, and downtime/maintenance-window risk. (4 readers)
- A copy-paste quick-triage block up top: run the Step 1 provisioning-type check, then branch to Path A or Path B. (3 readers)
- A short glossary (slab, unmap, footprint, thin vs fixed, primordial) and expand S2D/CSV/ReFS on first use. (beginner reader)
- For CSS: the exact health-fault names / EventIDs to collect, and a firm "escalate to PG/OEM when..." rule beyond "open a support case."
- A one-line plain-language orientation note for a mixed-skill global audience.
Items 1 and 2 alone cover nine of the thirteen readers. This is all the usability follow-up, not a blocker here; correctness is clean.
Implements the usability panel from the PR Azure#312 approval review (1008covingtonlane): a top-of-doc at-a-glance box (impact / owner / time-to-resolve / downtime), a copy-paste quick-triage block, a terminology glossary with S2D/CSV/ReFS expansion, a plain-language orientation line, and a "Data to Collect Before Opening a Support Case" + "When to escalate" (OEM vs Microsoft) section for CSS. The CSS fault names and event IDs were verified against source (Windows Storage Health Service constants; AEO alert catalog) and a live Azure Local cluster's Storage Spaces provider manifest, and every collection command was run on the cluster to confirm it executes read-only: - Get-HealthFault: Microsoft.Health.FaultType.StoragePool.InsufficientReserveCapacityFault (on-box, per the Health Service faults reference) and ...PoolCapacityThresholdExceeded (Azure portal / Insights; on-box correlate EventID 103). - Microsoft-Windows-StorageSpaces-Driver/Operational EventIDs 103/104/310 (read from the provider manifest; noted as build-observed, distinct from the documented 311). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks again @1008covingtonlane — implemented all five usability items in
For item 4 I verified the identifiers rather than quoting from memory: |
1008covingtonlane
left a comment
There was a problem hiding this comment.
Thanks for the follow-up. The usability sections read well, and I re-checked the new content in this commit before signing off.
What I re-verified in the new material:
- Fault type strings:
Microsoft.Health.FaultType.StoragePool.PoolCapacityThresholdExceededis correct and matches what the platform emits. - The new PowerShell is all read-only, and every property it reads is real:
ProvisioningTypeandFootprintOnPoolonGet-VirtualDisk;ReadOnlyReason,IsPrimordial, andThinProvisioningAlertThresholdsonGet-StoragePool;UsageonGet-PhysicalDisk. Both the-IsPrimordial $falseparameter and theWhere-Object IsPrimordial -eq $falsefilter are valid, so the triage block and the collection block agree. - The five new in-doc links (Path A, Path B, Step 1, the fixed-provisioning explainer, Option A1) all resolve to real headings.
- Terminology checks out: the slab and footprint definitions are right, a three-way mirror really is 3x written data, and the top-of-page Medium severity matches the "At a glance" box.
One thing to fix:
- The reserve fault type picked up a wrong suffix. This commit changed
StoragePool.InsufficientReserveCapacitytoStoragePool.InsufficientReserveCapacityFault. On an Azure Local clusterGet-HealthFaultreturns this fault asMicrosoft.Health.FaultType.StoragePool.InsufficientReserveCapacity, with noFaultsuffix, so the suffixed form is not a real fault name and an operator grepping forInsufficientReserveCapacityFaultwould match nothing. It is worth flagging because the "Data to Collect" table row is labeled "documented" and citesGet-HealthFaultas its source, yet the string in that row does not match whatGet-HealthFaultemits. The suffixed form appears in three spots: the "two threshold controls" paragraph, the "Data to Collect" fault table, and the "When to escalate" section. Reverting all three toInsufficientReserveCapacitylines them up with what the cmdlet returns. One word each, low risk.
Minor, no action needed: I could not confirm EventIDs 103, 104, and 310 from public docs, but the note already tells the reader to verify them with wevtutil and warns they can vary by build, so that reads fine as written.
Addresses the CHANGES_REQUESTED review: Get-HealthFault on Azure Local emits Microsoft.Health.FaultType.StoragePool.InsufficientReserveCapacity with NO "Fault" suffix. Confirmed against fleet telemetry (HealthMgmt, last 30d): the no-suffix form has 79,140 occurrences and the suffixed form 0. The suffix came from a Windows Server 2016 doc that does not match what the cmdlet emits on Azure Local. Reverts all three occurrences (pool-vs-volume signals paragraph, the Data-to-Collect fault table, When-to-escalate) and drops the now- unsupportable "(documented)" tag on that table row. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Good catch — fixed in I double-checked against fleet telemetry to be sure: in |
1008covingtonlane
left a comment
There was a problem hiding this comment.
The reserve fault name is fixed in all three spots. It now reads InsufficientReserveCapacity without the Fault suffix, which matches what Get-HealthFault emits, and dropping the "documented" qualifier on that table row was a good call. Approving, thanks for the quick turnaround.
What
Follow-up to #300 addressing @Karl-WE's post-merge change request (relaying Patrick Lownds' field guidance): add capacity-escalation guidance with admin actions, and steer away from "pause VM" under capacity pressure.
Single-file change to
TSG/Storage/Troubleshoot-Storage-StoragePoolCapacityThreshold.md.Changes
System.Storage.Volume.CapacityThreshold.Warning = 80/.Critical = 90), not pool auto-actions. The pool raises only the configurable 70% thin-provisioning alert (PoolCapacityThresholdExceeded) and the reserve-capacity fault, and it goes read-only only on quorum loss (Incomplete) or administrator policy (Policy) — there is no automatic 80/90/95 pool ladder and no capacity-based read-only "block."Save(Save-VM/Stop-VM -Save/ the Save the virtual machine state automatic stop action) writes a saved-state file the size of the VM's memory onto its volume; a cluster-wide stop with the Save stop action can flood an already-full CSV. Set the automatic stop action to Shut down the guest OS; note a node drain is space-safe (it live-migrates). For Arc VMs, stop from Azure.Stop-VMguest shutdown (releases the VHDX handles, no saved-state file), withStop-VM -TurnOffas the fallback. Corrects thatSuspend-VMonly pauses the VM (memory stays in RAM and the disk handles stay open, so consolidation cannot proceed) and thatSaveis what writes the memory-sized file.Accuracy note
The requested field guidance framed S2D as automatically flagging pool operational status Warning at 80%, Critical/P2 at 90%, and read-only "block" (with graceful guest pause) at 95%. This was verified against Microsoft Learn (Storage Spaces health and operational states; thin provisioning), the Azure Local Health Service settings doc, and the product health-fault model:
This PR therefore captures the operational intent (escalation model + admin actions + the save-state hazard) with the accurate mechanism, so field engineers don't wait for an automatic pool block that won't come.