mirror of
https://github.com/democratic-csi/democratic-csi.git
synced 2026-10-18 05:43:02 +02:00
fix(controller-zfs): unmount before destroy so deletes work on LXC hosts
DeleteVolume destroys with `zfs destroy -r -f -p`. The -f forces the unmount, which issues umount2(MNT_FORCE). LXC's default seccomp profile rejects that syscall (`reject_force_umount` in common.seccomp), so on a ZFS server running inside an LXC container every delete of a mounted dataset fails with: cannot unmount '/<parent>/pvc-...': unmount failed and never recovers -- the PV stays Released and the dataset is stranded. The retry in DeleteVolume does not help: its retryCondition only matches "dataset is busy"/"target is busy", not this error. A plain, non-forced unmount is permitted inside such containers, so unmount explicitly before destroying. The unmount is best-effort: zvols and already-unmounted datasets have nothing to unmount, and any real problem still surfaces from the destroy that follows. Refs #570 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsfbAFDXVKULBv26HxPEHF
This commit is contained in:
co-authored by
Claude Opus 5
parent
3974268272
commit
954d6e8223
@@ -1471,6 +1471,20 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||
// NOTE: -f does NOT allow deletes if dependent filesets exist
|
||||
// NOTE: -R will recursively delete items + dependent filesets
|
||||
// delete dataset
|
||||
// Unmount explicitly before destroying. `zfs destroy -f` forces the
|
||||
// unmount via umount2(MNT_FORCE), which LXC's default seccomp profile
|
||||
// rejects (`reject_force_umount`), so on a containerised ZFS host every
|
||||
// delete of a mounted dataset fails with "cannot unmount ... unmount
|
||||
// failed" and never recovers. A plain unmount is permitted there.
|
||||
//
|
||||
// Best-effort: a dataset that is a zvol, already unmounted, or absent has
|
||||
// nothing to unmount, and any real problem still surfaces from destroy.
|
||||
try {
|
||||
await zb.zfs.unmount(datasetName, { idempotent: true });
|
||||
} catch (err) {
|
||||
// fall through to destroy, which reports the actionable error
|
||||
}
|
||||
|
||||
try {
|
||||
await GeneralUtils.retry(
|
||||
12,
|
||||
|
||||
@@ -1445,6 +1445,53 @@ class Zetabyte {
|
||||
* @param {*} dataset
|
||||
* @param {*} property
|
||||
*/
|
||||
/**
|
||||
* zfs unmount [-f] filesystem|mountpoint
|
||||
*
|
||||
* Deliberately does NOT support -f. A forced unmount issues
|
||||
* umount2(MNT_FORCE), which LXC's default seccomp profile rejects
|
||||
* (`reject_force_umount`), so it fails with EPERM on containerised ZFS
|
||||
* hosts. A plain unmount is permitted there and is sufficient.
|
||||
*
|
||||
* @param {*} dataset
|
||||
* @param {*} options
|
||||
*/
|
||||
unmount: function (dataset, options = {}) {
|
||||
if (!(arguments.length >= 1)) throw Error("Invalid arguments");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const idempotent =
|
||||
"idempotent" in options
|
||||
? options.idempotent
|
||||
: "idempotent" in zb.options
|
||||
? zb.options.idempotent
|
||||
: false;
|
||||
|
||||
let args = [];
|
||||
args.push("unmount");
|
||||
args.push(dataset);
|
||||
|
||||
zb.exec(
|
||||
zb.options.paths.zfs,
|
||||
args,
|
||||
{ timeout: zb.options.timeout },
|
||||
function (error, stdout, stderr) {
|
||||
if (
|
||||
error &&
|
||||
!(
|
||||
idempotent &&
|
||||
(stderr.includes("not currently mounted") ||
|
||||
stderr.includes("not a mountpoint") ||
|
||||
stderr.includes("dataset does not exist"))
|
||||
)
|
||||
)
|
||||
return reject(zb.helpers.zfsError(error, stderr));
|
||||
return resolve(stdout);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
inherit: function (dataset, property) {
|
||||
if (arguments.length != 2) throw Error("Invalid arguments");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user