diff --git a/pkg/storaged/content-views.jsx b/pkg/storaged/content-views.jsx
index 23531db5c8e2..836d123f9355 100644
--- a/pkg/storaged/content-views.jsx
+++ b/pkg/storaged/content-views.jsx
@@ -24,6 +24,7 @@ import {
init_active_usage_processes
} from "./dialog.jsx";
import * as utils from "./utils.js";
+import { set_crypto_auto_option } from "./utils.js";
import React from "react";
import { Card, CardBody, CardHeader, CardTitle } from '@patternfly/react-core/dist/esm/components/Card/index.js';
@@ -38,13 +39,11 @@ import { ListingTable } from "cockpit-components-table.jsx";
import { ListingPanel } from 'cockpit-components-listing-panel.jsx';
import { StorageButton, StorageBarMenu, StorageMenuItem, StorageUsageBar } from "./storage-controls.jsx";
import * as PK from "packagekit.js";
-import {
- format_dialog, parse_options, extract_option, unparse_options
-} from "./format-dialog.jsx";
+import { format_dialog } from "./format-dialog.jsx";
import { job_progress_wrapper } from "./jobs-panel.jsx";
import { FilesystemTab, is_mounted, mounting_dialog, get_fstab_config } from "./fsys-tab.jsx";
-import { CryptoTab, edit_config } from "./crypto-tab.jsx";
+import { CryptoTab } from "./crypto-tab.jsx";
import { get_existing_passphrase, unlock_with_type } from "./crypto-keyslots.jsx";
import { BlockVolTab, PoolVolTab, VDOPoolTab } from "./lvol-tabs.jsx";
import { PartitionTab } from "./part-tab.jsx";
@@ -75,38 +74,6 @@ function next_default_logical_volume_name(client, vgroup, prefix) {
return name;
}
-export function set_crypto_options(block, readonly, auto, nofail, netdev) {
- return edit_config(block, (config, commit) => {
- const opts = config.options ? parse_options(utils.decode_filename(config.options.v)) : [];
- if (readonly !== null) {
- extract_option(opts, "readonly");
- if (readonly)
- opts.push("readonly");
- }
- if (auto !== null) {
- extract_option(opts, "noauto");
- if (!auto)
- opts.push("noauto");
- }
- if (nofail !== null) {
- extract_option(opts, "nofail");
- if (nofail)
- opts.push("nofail");
- }
- if (netdev !== null) {
- extract_option(opts, "_netdev");
- if (netdev)
- opts.push("_netdev");
- }
- config.options = { t: 'ay', v: utils.encode_filename(unparse_options(opts)) };
- return commit();
- });
-}
-
-export function set_crypto_auto_option(block, flag) {
- return set_crypto_options(block, null, flag, null, null);
-}
-
function create_tabs(client, target, options) {
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
diff --git a/pkg/storaged/crypto-keyslots.jsx b/pkg/storaged/crypto-keyslots.jsx
index f8e86f5f7d62..358ea47f6c84 100644
--- a/pkg/storaged/crypto-keyslots.jsx
+++ b/pkg/storaged/crypto-keyslots.jsx
@@ -39,11 +39,9 @@ import {
dialog_open,
SelectOneRadio, TextInput, PassInput, Skip
} from "./dialog.jsx";
-import { decode_filename, encode_filename, get_block_mntopts, block_name, for_each_async, get_children } from "./utils.js";
+import { decode_filename, encode_filename, get_block_mntopts, block_name, for_each_async, get_children, parse_options, unparse_options, edit_crypto_config } from "./utils.js";
import { fmt_to_fragments } from "utils.jsx";
import { StorageButton } from "./storage-controls.jsx";
-import { parse_options, unparse_options } from "./format-dialog.jsx";
-import { edit_config } from "./crypto-tab.jsx";
import clevis_luks_passphrase_sh from "./clevis-luks-passphrase.sh";
@@ -384,7 +382,7 @@ function ensure_crypto_option(steps, progress, client, block, option) {
const new_crypto_options = crypto_options.concat([option]);
progress(cockpit.format(_("Adding \"$0\" to encryption options"), option), null);
- return edit_config(block, (config, commit) => {
+ return edit_crypto_config(block, (config, commit) => {
config.options = { t: 'ay', v: encode_filename(unparse_options(new_crypto_options)) };
return commit();
});
diff --git a/pkg/storaged/crypto-tab.jsx b/pkg/storaged/crypto-tab.jsx
index e17eab66cce4..6b1aa9c0e004 100644
--- a/pkg/storaged/crypto-tab.jsx
+++ b/pkg/storaged/crypto-tab.jsx
@@ -21,8 +21,7 @@ import { DescriptionList, DescriptionListDescription, DescriptionListGroup, Desc
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import cockpit from "cockpit";
import { dialog_open, TextInput, PassInput } from "./dialog.jsx";
-import { encode_filename, decode_filename, block_name } from "./utils.js";
-import { parse_options, unparse_options, extract_option } from "./format-dialog.jsx";
+import { encode_filename, decode_filename, block_name, parse_options, unparse_options, extract_option, edit_crypto_config } from "./utils.js";
import { is_mounted } from "./fsys-tab.jsx";
import React from "react";
@@ -50,33 +49,6 @@ function parse_tag_mtime(tag) {
return null;
}
-export function edit_config(block, modify) {
- let old_config, new_config;
-
- function commit() {
- new_config[1]["track-parents"] = { t: 'b', v: true };
- if (old_config)
- return block.UpdateConfigurationItem(old_config, new_config, { });
- else
- return block.AddConfigurationItem(new_config, { });
- }
-
- return block.GetSecretConfiguration({}).then(
- function (items) {
- old_config = items.find(c => c[0] == "crypttab");
- new_config = ["crypttab", old_config ? Object.assign({ }, old_config[1]) : { }];
-
- // UDisks insists on always having a "passphrase-contents" field when
- // adding a crypttab entry, but doesn't include one itself when returning
- // an entry without a stored passphrase.
- //
- if (!new_config[1]['passphrase-contents'])
- new_config[1]['passphrase-contents'] = { t: 'ay', v: encode_filename("") };
-
- return modify(new_config[1], commit);
- });
-}
-
export class CryptoTab extends React.Component {
constructor() {
super();
@@ -141,7 +113,7 @@ export class CryptoTab extends React.Component {
this.monitor_slots(block);
function edit_stored_passphrase() {
- edit_config(block, function (config, commit) {
+ edit_crypto_config(block, function (config, commit) {
dialog_open({
Title: _("Stored passphrase"),
Fields: [
@@ -188,7 +160,7 @@ export class CryptoTab extends React.Component {
const content_block = client.blocks_cleartext[block.path];
const is_fsys = fsys_config || (content_block && content_block.IdUsage == "filesystem");
- edit_config(block, function (config, commit) {
+ edit_crypto_config(block, function (config, commit) {
dialog_open({
Title: _("Encryption options"),
Fields: [
diff --git a/pkg/storaged/dialog.jsx b/pkg/storaged/dialog.jsx
index 3bc707515d1c..2576a8dee4c8 100644
--- a/pkg/storaged/dialog.jsx
+++ b/pkg/storaged/dialog.jsx
@@ -1140,10 +1140,14 @@ const UsersPopover = ({ users }) => {
);
};
-export const TeardownMessage = (usage) => {
+export const TeardownMessage = (usage, expect_single_unmount) => {
if (usage.length == 0)
return null;
+ if (expect_single_unmount && usage.length == 1 &&
+ usage[0].usage == "mounted" && usage[0].location == expect_single_unmount)
+ return ;
+
const rows = [];
usage.forEach((use, index) => {
if (use.block) {
@@ -1178,7 +1182,7 @@ export const TeardownMessage = (usage) => {
);
};
-export function init_active_usage_processes(client, usage) {
+export function init_active_usage_processes(client, usage, expect_single_unmount) {
return {
title: _("Checking related processes"),
func: dlg => {
@@ -1191,7 +1195,7 @@ export function init_active_usage_processes(client, usage) {
} else
return Promise.resolve();
}).then(() => {
- dlg.set_attribute("Teardown", TeardownMessage(usage));
+ dlg.set_attribute("Teardown", TeardownMessage(usage, expect_single_unmount));
const usage_with_users = usage.filter(u => u.users);
const n_processes = usage_with_users.reduce((sum, u) => sum + u.users.filter(u => u.pid).length, 0);
const n_services = usage_with_users.reduce((sum, u) => sum + u.users.filter(u => u.unit).length, 0);
@@ -1207,6 +1211,9 @@ export function init_active_usage_processes(client, usage) {
}
export const StopProcessesMessage = ({ mount_point, users }) => {
+ if (!users || users.length == 0)
+ return null;
+
const process_rows = users.filter(u => u.pid).map(u => {
return {
columns: [
diff --git a/pkg/storaged/format-dialog.jsx b/pkg/storaged/format-dialog.jsx
index 79460661ec41..5b8802a0e086 100644
--- a/pkg/storaged/format-dialog.jsx
+++ b/pkg/storaged/format-dialog.jsx
@@ -19,6 +19,7 @@
import cockpit from "cockpit";
import * as utils from "./utils.js";
+import { edit_crypto_config, parse_options, unparse_options, extract_option } from "./utils.js";
import React from "react";
import { FormHelperText } from "@patternfly/react-core/dist/esm/components/Form/index.js";
@@ -33,35 +34,11 @@ import {
} from "./dialog.jsx";
import { get_fstab_config, is_valid_mount_point } from "./fsys-tab.jsx";
-import { edit_config } from "./crypto-tab.jsx";
import { init_existing_passphrase, unlock_with_type } from "./crypto-keyslots.jsx";
import { job_progress_wrapper } from "./jobs-panel.jsx";
const _ = cockpit.gettext;
-export function parse_options(options) {
- if (options)
- return (options.split(",")
- .map(function (s) { return s.trim() })
- .filter(function (s) { return s != "" }));
- else
- return [];
-}
-
-export function unparse_options(split) {
- return split.join(",");
-}
-
-export function extract_option(split, opt) {
- const index = split.indexOf(opt);
- if (index >= 0) {
- split.splice(index, 1);
- return true;
- } else {
- return false;
- }
-}
-
export function initial_tab_options(client, block, for_fstab) {
const options = { };
@@ -530,11 +507,11 @@ function format_dialog_internal(client, path, start, size, enable_dos_extended,
return block_ptable.CreatePartitionAndFormat(start, vals.size, "", "", { },
vals.type, options);
} else if (keep_keys) {
- return (edit_config(block,
- (config, commit) => {
- config.options = new_crypto_options;
- return commit();
- })
+ return (edit_crypto_config(block,
+ (config, commit) => {
+ config.options = new_crypto_options;
+ return commit();
+ })
.then(() => maybe_unlock())
.then(content_block => {
return content_block.Format(vals.type, options);
diff --git a/pkg/storaged/fsys-tab.jsx b/pkg/storaged/fsys-tab.jsx
index bc247d98fb4d..d0c96361514c 100644
--- a/pkg/storaged/fsys-tab.jsx
+++ b/pkg/storaged/fsys-tab.jsx
@@ -24,17 +24,14 @@ import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/ind
import cockpit from "cockpit";
import * as utils from "./utils.js";
+import { parse_options, unparse_options, extract_option, set_crypto_options, set_crypto_auto_option } from "./utils.js";
import {
dialog_open, TextInput, PassInput, CheckBoxes, SelectOne,
- StopProcessesMessage, stop_processes_danger_message
+ TeardownMessage, init_active_usage_processes
} from "./dialog.jsx";
import { StorageButton, StorageLink } from "./storage-controls.jsx";
-import {
- initial_tab_options, parse_options, unparse_options, extract_option,
- mount_explanation
-} from "./format-dialog.jsx";
-import { set_crypto_options, set_crypto_auto_option } from "./content-views.jsx";
+import { initial_tab_options, mount_explanation } from "./format-dialog.jsx";
import { init_existing_passphrase, unlock_with_type } from "./crypto-keyslots.jsx";
import client from "./client.js";
@@ -78,7 +75,7 @@ export function get_fstab_config(block, also_child_config) {
return [];
}
-export function find_blocks_for_mount_point(client, mount_point, self) {
+function find_blocks_for_mount_point(client, mount_point, self) {
const blocks = [];
function is_self(b) {
@@ -99,7 +96,7 @@ function nice_block_name(block) {
return utils.block_name(client.blocks[block.CryptoBackingDevice] || block);
}
-export function is_valid_mount_point(client, block, val) {
+export async function is_valid_mount_point(client, block, val, ignore_overmounting) {
if (val === "")
return _("Mount point cannot be empty");
@@ -107,6 +104,16 @@ export function is_valid_mount_point(client, block, val) {
if (other_blocks.length > 0)
return cockpit.format(_("Mount point is already used for $0"),
other_blocks.map(nice_block_name).join(", "));
+
+ if (!ignore_overmounting) {
+ const children = utils.find_children_for_mount_point(client, val, block);
+ if (Object.keys(children).length > 0)
+ return <>
+ {_("Filesystems are already mounted below this mountpoint.")}
+ {Object.keys(children).map(m =>
{cockpit.format("• $0 on $1", nice_block_name(children[m]), m)}
)}
+ {_("Please unmount them first.")}
+ >;
+ }
}
export function get_cryptobacking_noauto(client, block) {
@@ -182,7 +189,6 @@ export function mounting_dialog(client, block, mode, forced_options) {
const extra_options = unparse_options(split_options);
const is_filesystem_mounted = is_mounted(client, block);
- let mount_point_users = null;
function maybe_update_config(new_dir, new_opts, passphrase, passphrase_type) {
let new_config = null;
@@ -220,13 +226,6 @@ export function mounting_dialog(client, block, mode, forced_options) {
}
}
- function maybe_unmount() {
- if (block_fsys && block_fsys.MountPoints.indexOf(utils.encode_filename(old_dir)) >= 0)
- return client.unmount_at(old_dir, mount_point_users);
- else
- return Promise.resolve();
- }
-
function get_block_fsys() {
if (block_fsys)
return Promise.resolve(block_fsys);
@@ -296,7 +295,7 @@ export function mounting_dialog(client, block, mode, forced_options) {
// backs.
return (utils.reload_systemd()
- .then(maybe_unmount)
+ .then(() => utils.teardown_active_usage(client, usage))
.then(maybe_unlock)
.then(() => {
if (!old_config && new_config)
@@ -330,7 +329,8 @@ export function mounting_dialog(client, block, mode, forced_options) {
TextInput("mount_point", _("Mount point"),
{
value: old_dir,
- validate: val => is_valid_mount_point(client, block, val)
+ validate: val => is_valid_mount_point(client, block, val,
+ mode == "update" && !is_filesystem_mounted)
}),
CheckBoxes("mount_options", _("Mount options"),
{
@@ -378,17 +378,6 @@ export function mounting_dialog(client, block, mode, forced_options) {
]);
}
- let teardown = null;
- if (!is_filesystem_mounted && block_fsys && block_fsys.MountPoints.length > 0)
- teardown = (
- <>
- {teardown}
-
-
{cockpit.format(_("The filesystem is already mounted at $0. Proceeding will unmount it."),
- utils.decode_filename(block_fsys.MountPoints[0]))}
-
- >);
-
const mode_title = {
mount: _("Mount filesystem"),
unmount: _("Unmount filesystem $0"),
@@ -431,10 +420,13 @@ export function mounting_dialog(client, block, mode, forced_options) {
return Promise.resolve();
}
+ const usage = utils.get_active_usage(client, block.path);
+ console.log("USAGE", usage);
+
const dlg = dialog_open({
Title: cockpit.format(mode_title[mode], old_dir),
Fields: fields,
- Teardown: teardown,
+ Teardown: TeardownMessage(usage, old_dir),
update: function (dlg, vals, trigger) {
if (trigger == "at_boot")
dlg.set_options("at_boot", { explanation: mount_explanation[vals.at_boot] });
@@ -470,19 +462,7 @@ export function mounting_dialog(client, block, mode, forced_options) {
}
},
Inits: [
- {
- title: _("Checking related processes"),
- func: dlg => {
- return client.find_mount_users(old_dir, is_filesystem_mounted)
- .then(users => {
- mount_point_users = users;
- if (users.length > 0) {
- dlg.set_attribute("Teardown", );
- dlg.add_danger(stop_processes_danger_message(users));
- }
- });
- }
- },
+ init_active_usage_processes(client, usage, old_dir),
(block.IdUsage == "crypto" && mode == "mount")
? init_existing_passphrase(block, true, type => { passphrase_type = type })
: null
diff --git a/pkg/storaged/nfs-details.jsx b/pkg/storaged/nfs-details.jsx
index ecf247bb670c..15d082a6e801 100644
--- a/pkg/storaged/nfs-details.jsx
+++ b/pkg/storaged/nfs-details.jsx
@@ -26,10 +26,10 @@ import {
dialog_open, TextInput, ComboBox, CheckBoxes,
StopProcessesMessage, stop_processes_danger_message
} from "./dialog.jsx";
-import * as format from "./format-dialog.jsx";
import { StdDetailsLayout } from "./details.jsx";
import { StorageButton, StorageUsageBar } from "./storage-controls.jsx";
+import { parse_options, unparse_options, extract_option } from "./utils.js";
const _ = cockpit.gettext;
@@ -80,10 +80,10 @@ function get_exported_directories(server) {
export function nfs_fstab_dialog(client, entry) {
const mount_options = entry ? entry.fields[3] : "defaults";
- const split_options = format.parse_options(mount_options == "defaults" ? "" : mount_options);
- const opt_auto = !format.extract_option(split_options, "noauto");
- const opt_ro = format.extract_option(split_options, "ro");
- const extra_options = format.unparse_options(split_options);
+ const split_options = parse_options(mount_options == "defaults" ? "" : mount_options);
+ const opt_auto = !extract_option(split_options, "noauto");
+ const opt_ro = extract_option(split_options, "ro");
+ const extra_options = unparse_options(split_options);
function mounting_options(vals) {
let opts = [];
@@ -92,8 +92,8 @@ export function nfs_fstab_dialog(client, entry) {
if (vals.mount_options.ro)
opts.push("ro");
if (vals.mount_options.extra !== false)
- opts = opts.concat(format.parse_options(vals.mount_options.extra));
- return format.unparse_options(opts);
+ opts = opts.concat(parse_options(vals.mount_options.extra));
+ return unparse_options(opts);
}
function show(busy) {
diff --git a/pkg/storaged/utils.js b/pkg/storaged/utils.js
index b94b0a38730d..20971698b330 100644
--- a/pkg/storaged/utils.js
+++ b/pkg/storaged/utils.js
@@ -47,6 +47,88 @@ export function compare_versions(a, b) {
return a_ints.length - b_ints.length;
}
+export function parse_options(options) {
+ if (options)
+ return (options.split(",")
+ .map(function (s) { return s.trim() })
+ .filter(function (s) { return s != "" }));
+ else
+ return [];
+}
+
+export function unparse_options(split) {
+ return split.join(",");
+}
+
+export function extract_option(split, opt) {
+ const index = split.indexOf(opt);
+ if (index >= 0) {
+ split.splice(index, 1);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+export function edit_crypto_config(block, modify) {
+ let old_config, new_config;
+
+ function commit() {
+ new_config[1]["track-parents"] = { t: 'b', v: true };
+ if (old_config)
+ return block.UpdateConfigurationItem(old_config, new_config, { });
+ else
+ return block.AddConfigurationItem(new_config, { });
+ }
+
+ return block.GetSecretConfiguration({}).then(
+ function (items) {
+ old_config = items.find(c => c[0] == "crypttab");
+ new_config = ["crypttab", old_config ? Object.assign({ }, old_config[1]) : { }];
+
+ // UDisks insists on always having a "passphrase-contents" field when
+ // adding a crypttab entry, but doesn't include one itself when returning
+ // an entry without a stored passphrase.
+ //
+ if (!new_config[1]['passphrase-contents'])
+ new_config[1]['passphrase-contents'] = { t: 'ay', v: encode_filename("") };
+
+ return modify(new_config[1], commit);
+ });
+}
+
+export function set_crypto_options(block, readonly, auto, nofail, netdev) {
+ return edit_crypto_config(block, (config, commit) => {
+ const opts = config.options ? parse_options(decode_filename(config.options.v)) : [];
+ if (readonly !== null) {
+ extract_option(opts, "readonly");
+ if (readonly)
+ opts.push("readonly");
+ }
+ if (auto !== null) {
+ extract_option(opts, "noauto");
+ if (!auto)
+ opts.push("noauto");
+ }
+ if (nofail !== null) {
+ extract_option(opts, "nofail");
+ if (nofail)
+ opts.push("nofail");
+ }
+ if (netdev !== null) {
+ extract_option(opts, "_netdev");
+ if (netdev)
+ opts.push("_netdev");
+ }
+ config.options = { t: 'ay', v: encode_filename(unparse_options(opts)) };
+ return commit();
+ });
+}
+
+export function set_crypto_auto_option(block, flag) {
+ return set_crypto_options(block, null, flag, null, null);
+}
+
export let hostnamed = cockpit.dbus("org.freedesktop.hostname1").proxy();
// for unit tests
@@ -659,8 +741,34 @@ export function get_children(client, path) {
return children;
}
+export function find_children_for_mount_point(client, mount_point, self) {
+ const children = {};
+
+ function is_self(b) {
+ return self && (b == self || client.blocks[b.CryptoBackingDevice] == self);
+ }
+
+ for (const p in client.blocks) {
+ const b = client.blocks[p];
+ const fs = client.blocks_fsys[p];
+
+ if (is_self(b))
+ continue;
+
+ if (fs) {
+ for (const mp of fs.MountPoints) {
+ const mpd = decode_filename(mp);
+ if (mpd.length > mount_point.length && mpd.indexOf(mount_point) == 0 && mpd[mount_point.length] == "/")
+ children[mpd] = b;
+ }
+ }
+ }
+
+ return children;
+}
+
export function get_active_usage(client, path, top_action, child_action) {
- function get_usage(path, level) {
+ function get_usage(usage, path, level) {
const block = client.blocks[path];
const fsys = client.blocks_fsys[path];
const mdraid = block && client.mdraids[block.MDRaidMember];
@@ -670,7 +778,7 @@ export function get_active_usage(client, path, top_action, child_action) {
const stratis_blockdev = block && client.blocks_stratis_blockdev[path];
const stratis_pool = stratis_blockdev && client.stratis_pools[stratis_blockdev.Pool];
- const usage = flatten(get_children_for_teardown(client, path).map(p => get_usage(p, level + 1)));
+ get_children_for_teardown(client, path).map(p => get_usage(usage, p, level + 1));
function get_actions(teardown_action) {
const actions = [];
@@ -682,16 +790,34 @@ export function get_active_usage(client, path, top_action, child_action) {
return actions;
}
+ function enter_unmount(block, location, is_top) {
+ for (const u of usage) {
+ if (u.usage == 'mounted' && u.location == location) {
+ if (is_top) {
+ u.actions = get_actions(_("unmount"));
+ u.set_noauto = false;
+ }
+ return;
+ }
+ }
+ usage.push({
+ level,
+ block,
+ usage: 'mounted',
+ location,
+ set_noauto: !is_top,
+ actions: is_top ? get_actions(_("unmount")) : [_("unmount")],
+ blocking: false
+ });
+ }
+
if (fsys && fsys.MountPoints.length > 0) {
fsys.MountPoints.forEach(mp => {
- usage.push({
- level,
- usage: 'mounted',
- block,
- location: decode_filename(mp),
- actions: get_actions(_("unmount")),
- blocking: false,
- });
+ const mpd = decode_filename(mp);
+ const children = find_children_for_mount_point(client, mpd, null);
+ for (const c in children)
+ enter_unmount(children[c], c, false);
+ enter_unmount(block, mpd, true);
});
} else if (mdraid) {
const active_state = mdraid.ActiveDevices.find(as => as[0] == block.path);
@@ -746,7 +872,8 @@ export function get_active_usage(client, path, top_action, child_action) {
return usage;
}
- let usage = get_usage(path, 0);
+ let usage = [];
+ get_usage(usage, path, 0);
if (usage.length == 1 && usage[0].level == 0 && usage[0].usage == "none")
usage = [];
@@ -757,6 +884,37 @@ export function get_active_usage(client, path, top_action, child_action) {
return usage;
}
+async function set_fsys_noauto(client, block, mount_point) {
+ for (const conf of block.Configuration) {
+ if (conf[0] == "fstab" &&
+ decode_filename(conf[1].dir.v) == mount_point) {
+ const options = parse_options(get_block_mntopts(conf[1]));
+ if (options.indexOf("noauto") >= 0)
+ continue;
+ options.push("noauto");
+ const new_conf = [
+ "fstab",
+ Object.assign({ }, conf[1],
+ {
+ opts: {
+ t: 'ay',
+ v: encode_filename(unparse_options(options))
+ }
+ })
+ ];
+ await block.UpdateConfigurationItem(conf, new_conf, { });
+ }
+ }
+
+ const crypto_backing = client.blocks[block.CryptoBackingDevice];
+ if (crypto_backing) {
+ const crypto_backing_crypto = client.blocks_crypto[crypto_backing.path];
+ await set_crypto_auto_option(crypto_backing, false);
+ if (crypto_backing_crypto)
+ await crypto_backing_crypto.Lock({});
+ }
+}
+
export function teardown_active_usage(client, usage) {
// The code below is complicated by the fact that the last
// physical volume of a volume group can not be removed
@@ -767,10 +925,12 @@ export function teardown_active_usage(client, usage) {
// physical volumes here, and it is easiest to catch this
// condition upfront by reshuffling the data structures.
- function unmount(mounteds) {
- return Promise.all(mounteds.map(m => {
- return client.unmount_at(m.location, m.users);
- }));
+ async function unmount(mounteds) {
+ for (const m of mounteds) {
+ await client.unmount_at(m.location, m.users);
+ if (m.set_noauto)
+ await set_fsys_noauto(client, m.block, m.location);
+ }
}
function mdraid_remove(members) {
diff --git a/test/reference b/test/reference
index b0a214b926e8..444adbab6864 160000
--- a/test/reference
+++ b/test/reference
@@ -1 +1 @@
-Subproject commit b0a214b926e86a52b8cf3ad9a5681511fc03fca6
+Subproject commit 444adbab6864a348695889d5bb294566691ffab7