Merge pull request #571 from addisonj/fix/unmount-before-destroy

fix(controller-zfs): unmount before destroy so deletes work on LXC hosts
This commit is contained in:
Travis Glenn Hansen
2026-10-03 09:19:57 -06:00
committed by GitHub
2 changed files with 61 additions and 0 deletions
+14
View File
@@ -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,
+47
View File
@@ -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");