Skip to main content
RunBook Academy

CephXXII · PG InvestigationPG Investigation

Reading a single PG with pg query

Advanced⏱ ~18 mincephjq

What you'll learn

  • Run pg query and navigate its output structure
  • Locate the recovery_state section and read the current state
  • Identify blocked_by and peer information
  • Extract the specific fact that explains a stall

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

ceph -s tells you a PG is unhappy. ceph pg query tells you why. It is a large JSON document and the instinct is to skim it, but almost every stuck-PG investigation ends at one of four fields, and knowing where they are turns a twenty-minute read into a thirty-second one.

Running it

ceph pg 7.3d query > /tmp/pg-7.3d.json
jq 'keys' /tmp/pg-7.3d.json

The query goes to the PG’s primary OSD. If the primary is down, the query blocks or fails — which is itself a diagnosis.

The four fields that matter

state — the same string ceph -s shows, at the top level.

jq -r '.state' /tmp/pg-7.3d.json
# active+undersized+degraded

recovery_state — an array of state-machine states, most recent first, each with an enter_time. This is where you learn how long the PG has been where it is.

jq -r '.recovery_state[] | "\(.name)  \(.enter_time)"' /tmp/pg-7.3d.json
# Started/Primary/Active/Degraded  2026-08-18T02:14:07
# Started/Primary/Active           2026-08-18T02:14:07
# Started                          2026-08-18T02:13:55

A PG whose innermost state was entered four hours ago is stuck. One entered forty seconds ago is working.

blocked_by — a list of OSD ids the PG is waiting on. When it is non-empty, your investigation is over; go look at those OSDs.

jq -r '.recovery_state[] | select(.blocked_by) | .blocked_by[]' /tmp/pg-7.3d.json

peer_info — one entry per peer, each with that peer’s view of the PG’s version and log. Divergent last_update values across peers explain why peering has not completed.

A worked read

jq -r '{state, up: .up, acting: .acting,
        newest: .info.stats.last_update,
        inner: .recovery_state[0].name,
        since: .recovery_state[0].enter_time}' /tmp/pg-7.3d.json
{
  "state": "peering",
  "up": [12, 47, 83],
  "acting": [12, 47, 83],
  "newest": "41207'8823914",
  "inner": "Started/Primary/Peering/GetInfo",
  "since": "2026-08-18T01:58:12"
}

GetInfo means the primary is waiting for peers to report their PG info and has been for over an hour. That is not peering; that is a peer that is not answering.

Quiz

Knowledge check · 4 questions

  1. Q1. `ceph pg 7.3d query` hangs and never returns. What does this most directly indicate?

  2. Q2. The enter_time on the innermost recovery_state entry tells you how long the PG has been in its current substate.

  3. Q3. Work a stuck PG from ceph -s to a specific cause.

    `ceph -s` reports `1 pg peering` for the last 40 minutes. Client I/O to one RBD image is hung. The cluster otherwise reads HEALTH_WARN with no OSDs down.

  4. Q4. You query the same PG three times a minute apart and see recovery_state[0].enter_time change each time, always recent. What is happening?

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

Production discipline

Capture pg query output to a file at the moment you find a problem, before you change anything. The state machine moves, and an intervention that fixes the symptom destroys the evidence. A saved JSON document is what lets you explain afterwards what was actually wrong, and it is the single most useful attachment on a Ceph support case.

Cross-course references

  • Kubernetes: kubectl describe pod events serve the same role — a timestamped state history rather than a status word
  • Linux: reading enter_time deltas is the same technique as reading process state durations from /proc