Storage service creates a duplicate raids row in local-storage.db after unclean shutdown - pool appears twice as read-only/obsolete (RAID6 healthy)

Aperta
#601 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
55/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
shell, sqlite

Direzione di ricerca

Inizia da route/raid.go intorno alla riga 452 e segui la scansione GetRaids all'avvio e le scritture nella tabella raids di local-storage.db. Riproduci la scansione durante il riassemblaggio dell'array md, quindi verifica che un uuid esistente venga riconciliato invece di essere duplicato e che status non sia mai vuoto. Conferma il risultato controllando il database e il pannello Storage dopo un arresto non pulito.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Storage service creates a duplicate raids row in local-storage.db after unclean shutdown — pool appears twice as read-only/obsolete although the RAID6 array is healthy

Summary

After every unclean shutdown (power cut), zimaos-local-storage inserts a
second row for the same RAID pool into /DATA/.casaos/db/local-storage.db
(table raids): identical uuid and mount_point, but empty status.
The web UI then renders the pool twice, and the ghost copy shows as
read-only / obsolete — even though the underlying md array and btrfs
mount are completely healthy (rw, all disks up).

Deleting the duplicate row and restarting zimaos-local-storage.service
fixes the UI immediately. The bug returns on the next unclean shutdown.

Verified on ZimaOS 1.7.1-beta2, x86_64.

Environment

  • ZimaOS 1.7.1-beta2 (x86_64)
  • Pool ZeroByte: /dev/md0, RAID6, 4 disks, btrfs — the affected one
  • Pool JBOD: /dev/md1, RAID0, 2 disks, btrfs — never affected
  • The affected pool uses the md write-intent bitmap (visible in /proc/mdstat)
  • Trigger: unclean shutdown / power loss, then boot

Steps to reproduce

  1. Have a RAID6 pool (btrfs) mounted.
  2. Cut power / unclean shutdown while the pool is mounted.
  3. Boot the machine.
  4. Open the Storage panel → the pool appears twice; the extra entry shows
    a read-only / obsolete state. The Files UI also lists the pool twice.
  5. Inspect the DB:
SELECT id,name,uuid,mount_point,status FROM raids ORDER BY id;

Actual state captured right after the 2026-09-16 power cut
(2026-09-17, before manual cleanup):

id  name      uuid                                  mount_point       status
2   JBOD      0a26d655:7aa36efc:2a76863a:f32e0bd0   /media/JBOD       ok
3   ZeroByte  aea3561d:5822a58b:4d32ccfa:e27970d4   /media/ZeroByte   ok
4   ZeroByte  aea3561d:5822a58b:4d32ccfa:e27970d4   /media/ZeroByte   (empty)

Duplicate check:

uuid                                  c
aea3561d:5822a58b:4d32ccfa:e27970d4   2

Note the second row: same uuid, same mount_point, empty status.

Expected behavior

On the boot-time storage scan, the service should reconcile pools by
uuid
: update the existing row (and recompute its real status) instead of
blind-inserting a second row for a pool that is already registered. A pool
reappearing after an unclean shutdown must never duplicate in raids.

Actual behavior

  • A second raids row is inserted for the same uuid → UI shows the pool
    twice and falls back to a defensive "read-only" presentation for the ghost.
  • The filesystem is NOT read-only at any point: mount shows
    /dev/md0 on /media/ZeroByte type btrfs (rw,...), /proc/mdstat shows
    [4/4] [UUUU]. Only the DB row is wrong.

Why it only affects the RAID6 pool (analysis)

The RAID0 pool (md1) assembles instantly and never enters a non-clean
state (no parity, no bitmap, no resync). The RAID6 pool (md0) does:
after a power cut it assembles "non-clean" and replays its write-intent
bitmap. Kernel log from the affected boot (2026-09-16 22:15):

Sep 16 22:15:33 kernel: md/raid:md127: raid level 6 active with 4 out of 4 devices
Sep 16 22:15:33 kernel: md127: detected capacity change from 0 to 7813529600
Sep 16 22:15:40 kernel: md127: detected capacity change from 7813529600 to 0
Sep 16 22:15:40 kernel: md: md127 stopped.
Sep 16 22:15:40 kernel: md: md0 stopped.
Sep 16 22:15:41 kernel: md/raid:md0: raid level 6 active with 4 out of 4 devices
Sep 16 22:15:41 kernel: md0: detected capacity change from 0 to 7813529600

The array is assembled as md127, stopped, and re-assembled as md0
within ~8 seconds. If the storage service's boot scan runs inside that
window, the pool briefly disappears / reappears with a different md node
name — plausibly the moment it treats the existing pool as a new one and
inserts the duplicate row.

Supporting service log (GetRaids failing to read df after boot):

Sep 16 22:24:21 zimaos-local-storage[1995]: error  error when getting df info
  {"error": "exit status 1", "func": "route.(*LocalStorage).GetRaids.func5",
   "file": ".../route/raid.go", "line": 452}

Historical evidence: the local-storage.db.preclean.* backups taken before
each manual fix (Sep 10 and Sep 17 incidents) always contain exactly one
JBOD row (status ok)
and the ZeroByte duplicate only in the snapshots
taken after an unclean shutdown
. In the Sep 10 incident, both ZeroByte
rows had an empty status.

Workaround that works (for users, until this is fixed)

# 1) Backup
sudo cp /DATA/.casaos/db/local-storage.db \
  /DATA/.casaos/db/local-storage.db.preclean.$(date +%s)

# 2) Delete duplicate rows (keep the oldest per uuid) and fix empty status
sudo sqlite3 /DATA/.casaos/db/local-storage.db \
  "DELETE FROM raids WHERE id NOT IN (SELECT MIN(id) FROM raids GROUP BY uuid);
   UPDATE raids SET status='ok' WHERE status IS NULL OR status='';"

# 3) Restart the service that owns this DB (NOT the whole CasaOS stack)
sudo systemctl restart zimaos-local-storage.service

Reload the web UI ~10 s later: duplicate entry and the read-only label are
gone.

Things that do not work (don't waste time like I did):

  • sudo systemctl restart casaos.service — unit does not exist
  • sudo systemctl restart zimaos.service — restarts everything, same rows
  • UI "Restart CasaOS" — restarts the frontend, the daemon re-reads the same DB
  • btrfs property set /media/<pool> ro false — the FS was never read-only

Suggested fix directions

  1. On the boot scan, upsert by uuid (e.g. INSERT ... ON CONFLICT(uuid) DO UPDATE) instead of inserting; or delete-then-insert keyed by uuid.
  2. Delay the initial storage scan until md arrays are fully assembled and
    stable (e.g. systemd ordering after mdadm/btrfs mounts, or re-check that
    the pool still exists before inserting).
  3. Never persist an empty status: compute it from the real md state at
    insert time.
  4. Consider a migration adding UNIQUE(uuid, mount_point) on raids so the
    duplicate state becomes impossible.

Happy to provide more logs or DB dumps if useful.

Lingua principale
Shell
Stelle
3.1k
Fork
130
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di IceWhaleTech/ZimaOS

Tutte le issue di IceWhaleTech/ZimaOS

Issue simili

Altre issue su Shell/Bash

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.