Die Platte ist voll, du vergrößerst die raw-Disk am Proxmox-Host, alles läuft sauber durch — und dann weigert sich der Online-Resize des Dateisystems mit Permission denied. Kein Platzproblem mehr, sondern ein Flag, das noch von einem lange vergangenen I/O-Fehler übrig war.

Das Problem

Zabbix meldete /mnt/nextcloud auf 100 % voll — konkret 536 MB frei. Der Expand-Weg war klar: die raw-Platte am Host wächst, das Dateisystem im Container wird danach nachgezogen. Der erste Teil lief:

pct resize 113 mp0 +50G

Ergebnis: die raw-Platte hatte jetzt 450 GB statt 400 GB. Der zweite Teil, der Online-Resize des Dateisystems im laufenden Container, brach ab:

resize2fs: Permission denied

Statt der erwarteten Vergrößerung: Permission denied. Platz war da, aber resize2fs durfte ihn nicht benutzen.

Die Diagnose

Der Online-Resize war schon der Hinweis — statt zu wachsen, verweigert resize2fs. Warum, steht wörtlich im Kernel-Log:

dmesg | tail

Expected Bad:

EXT4-fs (loop0): errors in filesystem so online resizing not allowed

Der Kernel sagt es wörtlich: Solange Fehler im Dateisystem vermerkt sind, ist Online-Resize gesperrt. Kein Bug, keine Rechtefrage — eine bewusste Verweigerung.

Was genau im Dateisystem steht, zeigt sich verlässlich erst auf der abgehängten Platte (siehe Lösung): statt clean steht dort clean with errors. Ein e2fsck am laufenden, noch gemounteten Container wäre nur ein unverbindlicher Blick — die belastbare Aussage kommt offline.

Die Ursache

Das Perfide: Der Kernel unterscheidet nicht zwischen „jetzt kaputt" und „war mal kaputt". Das Dateisystem war früher nach einem I/O-Fehler read-only gelaufen, und dabei setzt ext4 das EXT4_ERROR_FS-Flag. Dieses Flag bleibt gesetzt — auch nachdem der eigentliche Fehler längst vorbei ist. Der Kernel demotet das Dateisystem in den Fehlerzustand und lässt es dort stehen.

Deshalb passt das Symptom so schlecht zusammen:

  • resize2fs sagt Permission denied — aber es ist keine Rechtefrage.
  • Die Platte hat physisch Platz — aber das Dateisystem darf ihn nicht annehmen.
  • e2fsck -fn sagt „clean" — aber mit dem Zusatz „with errors".

Permission denied schickt dich erst in die falsche Richtung: Rechte, Mount-Optionen, SELinux. Tatsächlich ist es ein stale Flag aus einem alten I/O-Fehler. Online ist das Flag nicht wegzubekommen — der einzige Weg führt über ein echtes Offline-Filesystem-Check.

Die Lösung

Der Online-Weg ist versperrt, also offline. Wichtig: Die Platte ist eine raw-Datei auf einer CIFS-Freigabe, die der Host per Loop-Device einbindet. Der Container muss wirklich gestoppt werden — und die Freigabe muss vorher hart gemountet sein, sonst kann ein CIFS-Hänger mitten im schreibenden e2fsck das Dateisystem beschädigen.

# 1. Nextcloud in den Wartungsmodus, Stack stoppen
occ maintenance:mode --on
cd /home/icke/nextcloud && docker compose stop && sync

# 2. Container stoppen — löst das Loop-Device
pct stop 113
pct status 113        # status: stopped
losetup -a            # kein Loop mehr auf vm-113-disk-0.raw

# 3. CIFS-Freigabe zusätzlich hart mounten
#    (den bestehenden soft-Mount NICHT umhängen — der wird geteilt)
mkdir -p /mnt/sb-hard
mount -t cifs //<storagebox>/backup /mnt/sb-hard \
  -o hard,vers=3.0,credentials=/root/.smbcredentials,uid=0,gid=0
echo 3 > /proc/sys/vm/drop_caches

# 4. Loop-Device selbst anlegen — NICHT blind /dev/loop0 annehmen
LOOP=$(losetup -f --show /mnt/sb-hard/images/113/vm-113-disk-0.raw)
echo "LOOP=$LOOP"
blockdev --getsize64 "$LOOP"
tune2fs -l "$LOOP" | grep -iE "state|Block count"

# 5. Read-only-Check
e2fsck -fn -C 0 "$LOOP" | tee /root/fsck-113-dry.log
echo "DRY_RC=${PIPESTATUS[0]}"   # nur bei 0 oder 1 weitermachen

Expected (Check): clean with errors statt nur clean — der Zusatz ist der ganze Fall.

# 6. Anker-Backup, dann reparierender Lauf
df -h /root                                        # genug Platz für den 6,3-GB-Anker?
e2image "$LOOP" /root/nc-meta-$(date +%F-%H%M).e2i
e2fsck -fy -C 0 "$LOOP" | tee /root/fsck-113-fix.log
echo "FIX_RC=${PIPESTATUS[0]}"                     # 0/1 OK — 4 oder 8 → STOPP, nicht resizen
tune2fs -l "$LOOP" | grep state                    # muss "clean" OHNE "with errors" sein

# 7. Jetzt resizen (der Schritt, der online verweigert wurde)
resize2fs "$LOOP"
e2fsck -fy "$LOOP"

# 8. Aufräumen und zurück
losetup -d "$LOOP"
umount /mnt/sb-hard
pct start 113
# Nextcloud wieder live
cd /home/icke/nextcloud && docker compose start
sleep 8
occ maintenance:mode --off
occ status
df -h /mnt/nextcloud

Ergebnis: 442 GB belegt / 48 GB frei (89 %), HTTP 200, Dateisystem clean.

Warum kein /dev/loop0: Nach pct stop gibt es kein Loop-Device mehr — oder /dev/loop0 gehört plötzlich zu einer ganz anderen Platte. Ein e2fsck -fy /dev/loop0 würde dann schreibend ein fremdes Dateisystem reparieren. Deshalb wird das Device mit losetup -f --show neu erzeugt und über die Variable $LOOP angesprochen.

Wichtig: Die CIFS-Freigabe hart mounten (hard, nicht soft). Ein soft-Mount kann bei einem Hänger mitten in schreibenden Metadaten-Operationen abreißen und genau das Dateisystem beschädigen, das du gerade reparieren willst. Und nie host-seitig offline resizen, solange der Container-Mount noch live ist.

Lessons Learned

  • clean with errors ist nicht clean. Genau dieser Zusatz ist der ganze Fall. Wer nur auf „clean" schaut, übersieht den Fehlerzustand und sucht weiter an der falschen Stelle.
  • Permission denied bei resize2fs ist selten eine Rechtefrage. Wenn dmesg errors in filesystem so online resizing not allowed sagt, ist die Ursache im Dateisystem, nicht beim User oder den Mount-Optionen.
  • Ein stale EXT4_ERROR_FS-Flag blockiert Online-Resize dauerhaft. Es bleibt nach einem alten I/O-Fehler stehen, bis ein Offline-e2fsck -f ihn entfernt.
  • Offline heißt wirklich offline. Die Loop-Platte im Host-Kernel verlangt pct stop — ein „offline" Check bei laufendem Container prüft nichts Echtes.
  • /dev/loop0 ist kein stabiler Name. Nach pct stop per losetup -f --show <raw> neu erzeugen und über die Variable $LOOP arbeiten — sonst repariert e2fsck -fy im Zweifel ein fremdes Dateisystem.
  • CIFS vor dem Check hart mounten. Ein soft-Mount kann mitten im schreibenden e2fsck abreißen und das Dateisystem beschädigen. Die Freigabe gehört mit hard gemountet (den geteilten soft-Mount nicht umhängen).
  • e2fsck-Returncode 4 oder 8 heißt STOPP. Nicht resizen, erst das Dateisystem in Ordnung bringen — notfalls den Anker zurückholen.
  • e2image-Anker vor e2fsck -fy. Die 6,3 GB Metadaten-Kopie kostet wenig und ist die Rückversicherung, bevor ein reparierender Lauf schreibend eingreift — vorher df -h /root prüfen.
  • Erst die Vergrößerung, dann das volle Dateisystem. Die raw-Platte wächst sofort, das Dateisystem zieht erst nach — und kann genau dabei von einem alten Fehlerzustand ausgebremst werden.

Checkliste

  • Bei resize2fs: Permission denied das Kernel-Log (dmesg) auf errors in filesystem so online resizing not allowed geprüft
  • Nextcloud in den Wartungsmodus gesetzt und den Stack gestoppt, bevor der Container gestoppt wird
  • Container wirklich gestoppt (pct stop) — die Loop-Platte hängt im Host-Kernel, nicht im Container
  • CIFS-Freigabe vor dem Check hart gemountet (nicht soft, geteilten Mount nicht umhängen)
  • Loop-Device per losetup -f --show <raw> neu erzeugt und $LOOP verwendet — /dev/loop0 nicht blind angenommen
  • Offline-Check zeigt „clean with errors" statt „clean" (der entscheidende Zusatz)
  • e2fsck -fn-Returncode 0 oder 1 — sonst STOPP, nicht resizen
  • Vor e2fsck -fy: df -h /root geprüft und einen e2image-Anker geschrieben
  • e2fsck -fy-Returncode 0/1; bei 4 oder 8 STOPP und nicht resizen
  • Nach dem Offline-Lauf den Resize erneut ausgeführt und das Ergebnis (belegt/frei/HTTP-Status) live verifiziert
  • Loop abgebaut (losetup -d), Freigabe unmountet, Container und Stack wieder hoch, Wartungsmodus aus
  • Nie host-seitig offline resizen, solange der Container-Mount live ist