Skip to main content
RunBook Academy

CephCIX · Disaster RecoveryDisaster Recovery

Classifying a failure by what it costs

Advanced⏱ ~18 minceph

What you'll learn

  • Distinguish degraded from inactive from lost
  • Determine which state a cluster is in
  • Match the response to the state
  • Communicate the state accurately

Prerequisites

None — start here.

Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18

Not yet marked complete on this device.

Why this matters in production

Treating an inactive cluster as a degraded one wastes the window in which data is still recoverable, and treating degraded as lost causes unnecessary restores.

The three states

StateMeaningData
Degradedfewer copies than desired, still servingintact
Inactivesome PGs cannot serve I/Ointact but unavailable
Lostsome PGs have no surviving copygone unless restored
ceph -s
ceph pg stat
ceph health detail
  data:
    pgs:     3812 active+clean
             184  active+undersized+degraded      ← degraded
             12   down                            ← inactive
             2    incomplete                      ← possibly lost

Determining the state

ceph pg dump_stuck inactive
ceph pg dump_stuck stale
ceph pg dump_stuck undersized
# which PGs cannot serve, and why
ceph health detail | grep -E 'PG_AVAILABILITY|PG_DEGRADED|OSD_DOWN'
# for a specific PG, what it needs
# PG id from the dump_stuck output above:
PGID=3.1f

ceph pg "$PGID" query | python3 -c '
import sys,json
d = json.load(sys.stdin)
print("state:", d.get("state"))
rp = d.get("recovery_state", [])
for s in rp[:2]:
    print("-", s.get("name"))
    b = s.get("blocked", "")
    if b: print("  blocked:", b[:200])'
Query outputMeans
peering_blocked_by naming down OSDsthose OSDs must return
might_have_unfounddata may exist on an OSD that is down
unfound objects listedcopies are genuinely missing
incompleteinsufficient history to peer
# PG id from the dump_stuck output above:
PGID=3.1f

ceph pg "$PGID" list_unfound | head -20

Matching the response

StateResponse
Degradedlet recovery run; do not intervene beyond capacity checks
Inactive, OSDs recoverablebring those OSDs back; peering resumes
Inactive, OSDs unrecoverableassess might_have_unfound before any destructive step
Unfound objectsattempt OSD recovery first; mark_unfound_lost is last
Lostrestore from backup
# never the first action
# ceph pg <pgid> mark_unfound_lost revert|delete
`mark_unfound_lost` tells the cluster to stop waiting for data that may
still exist on a down OSD. Running it while any OSD that might hold a
copy is recoverable discards data that was not lost.
# which down OSDs might hold the missing copies
# PG id from the dump_stuck output above:
PGID=3.1f

ceph pg "$PGID" query | python3 -c '
import sys,json
d = json.load(sys.stdin)
for s in d.get("recovery_state", []):
    m = s.get("might_have_unfound")
    if m:
        for e in m: print("osd:", e.get("osd"), "status:", e.get("status"))'

Communicating accurately

SayNot
“Reduced redundancy; data intact and serving”“we lost disks”
“Some volumes unavailable; data intact, recovering access”“data loss”
“Assessing whether N objects are recoverable”“we may have lost data” — until assessed
“N objects confirmed unrecoverable; restoring from backup”vague reassurance
The distinction between unavailable and lost is the one stakeholders
most need and least often receive.

Quiz

Knowledge check · 4 questions

  1. Q1. What distinguishes an inactive PG from one with lost data?

  2. Q2. Running `mark_unfound_lost` while an OSD listed in `might_have_unfound` is still recoverable destroys data that was never lost.

  3. Q3. Classify a cluster failure.

    A rack has lost power. `ceph -s` shows 200 PGs degraded, 15 down, and 3 with unfound objects. The rack's hosts may be recoverable.

  4. Q4. What should stakeholders be told during a degraded-but-serving incident?

Passing score: 75%. Answers are checked in this browser.

Production discipline

Read ceph pg query and its might_have_unfound list before any destructive step — mark_unfound_lost discards objects that a recoverable OSD may still hold. Communicate “unavailable” and “lost” as the different things they are.

Cross-course references

  • Kubernetes: a pod that is Pending is not a pod that failed
  • Linux: uncertainty and evidence require different responses