Skip to content

Commit

Permalink
storage: Improve handling of LUKS backed btrfs
Browse files Browse the repository at this point in the history
Single-device btrfs volumes now behave like other filesystems:
Unmounting all subvolumes will automatically lock the LUKS device, and
mounting the first subvolume will automatically unlock it.

Options in /etc/crypttab are now maintained correctly for btrfs
volumes with multiple subvolumes. For example, the LUKS device is only
"noauto" when all of the subvolumes are also "noauto", and it is
readonly exactly when all of the subvolumes are readonly.

Cockpit can't unfortunately always know whether a locked LUKS device
is part of a single-device or multi-device btrfs volume.  (Because
UDisks2 only tracks one parent of a fstab entry, we would need to fix
that.) We assume that they are single-device volumes (because they are
more common, probably) and let the user mount their subvolumes
directly.

If the assumption turns out to have been wrong, the mount operation is
cleanly aborted.
  • Loading branch information
mvollmer committed Mar 27, 2024
1 parent 2729c66 commit 027e1f6
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 178 deletions.
17 changes: 13 additions & 4 deletions pkg/storaged/block/create-pages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ import { make_swap_card } from "../swap/swap.jsx";
import { make_encryption_card } from "../crypto/encryption.jsx";
import { make_btrfs_device_card } from "../btrfs/device.jsx";
import { make_btrfs_filesystem_card } from "../btrfs/filesystem.jsx";
import { make_btrfs_subvolume_pages } from "../btrfs/subvolume.jsx";
import { make_btrfs_subvolume_pages, make_btrfs_subvolume_pages_from_child_config } from "../btrfs/subvolume.jsx";
import { is_multi_device_btrfs_volume } from "../btrfs/utils.jsx";

import { new_page } from "../pages.jsx";

Expand All @@ -59,7 +60,7 @@ export function make_block_page(parent, block, card) {
(fstab_config[2].indexOf("subvol=") >= 0 || fstab_config[2].indexOf("subvolid=") >= 0));

const block_btrfs_blockdev = content_block && client.blocks_fsys_btrfs[content_block.path];
const single_device_volume = block_btrfs_blockdev && block_btrfs_blockdev.data.num_devices === 1;
const single_device_volume = !is_multi_device_btrfs_volume(content_block || block);

if (client.blocks_ptable[block.path]) {
make_partition_table_page(parent, block, card);
Expand All @@ -85,8 +86,14 @@ export function make_block_page(parent, block, card) {
// can not happen unless there is a bug in the code above.
console.error("Assertion failure: is_crypto == false");
}
if (fstab_config.length > 0 && !is_btrfs) {
card = make_filesystem_card(card, block, null, fstab_config);
if (fstab_config.length > 0) {
if (is_btrfs) {
if (single_device_volume)
card = make_btrfs_filesystem_card(card, block, null);
else
card = make_locked_encrypted_data_card(card, block);
} else
card = make_filesystem_card(card, block, null, fstab_config);
} else {
card = make_locked_encrypted_data_card(card, block);
}
Expand Down Expand Up @@ -124,6 +131,8 @@ export function make_block_page(parent, block, card) {
const page = new_page(parent, card);
if (block_btrfs_blockdev && single_device_volume)
make_btrfs_subvolume_pages(page, block_btrfs_blockdev);
else if (!content_block && is_btrfs && single_device_volume)
make_btrfs_subvolume_pages_from_child_config(page, block);
return page;
}
}
27 changes: 16 additions & 11 deletions pkg/storaged/btrfs/filesystem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import { DescriptionList } from "@patternfly/react-core/dist/esm/components/Desc
import {
new_card, ChildrenTable, StorageCard, StorageDescription
} from "../pages.jsx";
import { format_dialog } from "../block/format-dialog.jsx";
import { StorageUsageBar, StorageLink } from "../storage-controls.jsx";
import { btrfs_device_usage, btrfs_is_volume_mounted } from "./utils.jsx";
import { btrfs_device_actions } from "./device.jsx";
import { rename_dialog } from "./volume.jsx";

const _ = cockpit.gettext;
Expand All @@ -43,17 +43,18 @@ export function make_btrfs_filesystem_card(next, backing_block, content_block) {
return new_card({
title: _("btrfs filesystem"),
next,
actions: btrfs_device_actions(backing_block, content_block),
actions: [
{ title: _("Format"), action: () => format_dialog(client, backing_block.path), danger: true },
],
component: BtrfsFilesystemCard,
props: { backing_block, content_block },
});
}

const BtrfsFilesystemCard = ({ card, backing_block, content_block }) => {
const block_btrfs = client.blocks_fsys_btrfs[content_block.path];
const block_btrfs = content_block && client.blocks_fsys_btrfs[content_block.path];
const uuid = block_btrfs && block_btrfs.data.uuid;
const label = block_btrfs && block_btrfs.data.label;
const use = btrfs_device_usage(client, uuid, block_btrfs.path);

// Changing the label is only supported when the device is not mounted
// otherwise we will get btrfs filesystem error ERROR: device /dev/vda5 is
Expand All @@ -66,18 +67,22 @@ const BtrfsFilesystemCard = ({ card, backing_block, content_block }) => {
<StorageCard card={card}>
<CardBody>
<DescriptionList className="pf-m-horizontal-on-sm">
{ block_btrfs &&
<StorageDescription title={_("Label")}
value={label}
action={
<StorageLink onClick={() => rename_dialog(block_btrfs, label)}
excuse={is_mounted ? _("Btrfs volume is mounted") : null}>
{_("edit")}
</StorageLink>}
value={label}
action={
<StorageLink onClick={() => rename_dialog(block_btrfs, label)}
excuse={is_mounted ? _("Btrfs volume is mounted") : null}>
{_("edit")}
</StorageLink>}
/>
}
{ content_block &&
<StorageDescription title={_("UUID")} value={content_block.IdUUID} />
}
{ block_btrfs &&
<StorageDescription title={_("Usage")}>
<StorageUsageBar key="s" stats={use} />
<StorageUsageBar key="s" stats={btrfs_device_usage(client, uuid, block_btrfs.path)} />
</StorageDescription>
}
</DescriptionList>
Expand Down

0 comments on commit 027e1f6

Please sign in to comment.