Skip to content

Commit 0841cef

Browse files
committed
storage: Detect partition tables in unsupported places
These likely belong to virtual machines and we shouldn't touch them. See https://bugzilla.redhat.com/show_bug.cgi?id=2364699
1 parent 82e2ded commit 0841cef

File tree

8 files changed

+85
-47
lines changed

8 files changed

+85
-47
lines changed

pkg/storaged/block/create-pages.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ import { make_btrfs_filesystem_card } from "../btrfs/filesystem.jsx";
3838
import { make_btrfs_subvolume_pages } from "../btrfs/subvolume.jsx";
3939

4040
import { new_page } from "../pages.jsx";
41+
import { register_available_block_space } from "../utils";
4142

4243
/* CARD must have page_name, page_location, and page_size set.
4344
*/
4445

45-
export function make_block_page(parent, block, card) {
46+
export function make_block_page(parent, block, card, options) {
4647
let is_crypto = block.IdUsage == 'crypto';
4748
let content_block = is_crypto ? client.blocks_cleartext[block.path] : block;
4849
const fstab_config = get_fstab_config(content_block || block, true);
@@ -62,7 +63,7 @@ export function make_block_page(parent, block, card) {
6263
const single_device_volume = block_btrfs_blockdev && block_btrfs_blockdev.data.num_devices === 1;
6364

6465
if (client.blocks_ptable[block.path]) {
65-
make_partition_table_page(parent, block, card);
66+
make_partition_table_page(parent, block, card, options && options.partitionable);
6667
return;
6768
}
6869

@@ -114,6 +115,8 @@ export function make_block_page(parent, block, card) {
114115
(content_block.IdUsage == "other" && content_block.IdType == "swap")) {
115116
card = make_swap_card(card, block, content_block);
116117
} else if (client.blocks_available[content_block.path]) {
118+
if (!block.HintIgnore)
119+
register_available_block_space(client, content_block);
117120
card = make_unformatted_data_card(card, block, content_block);
118121
} else {
119122
card = make_unrecognized_data_card(card, block, content_block);

pkg/storaged/block/other.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function make_other_page(parent, block) {
4949
actions: partitionable_block_actions(block),
5050
});
5151

52-
make_block_page(parent, block, other_card);
52+
make_block_page(parent, block, other_card, { partitionable: true });
5353
}
5454

5555
const OtherCard = ({ card, block }) => {

pkg/storaged/drive/drive.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export function make_drive_page(parent, drive) {
105105
}
106106

107107
if (block.Size > 0) {
108-
make_block_page(parent, block, card);
108+
make_block_page(parent, block, card, { partitionable: true });
109109
} else {
110110
new_page(parent, card);
111111
}

pkg/storaged/mdraid/mdraid.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export function make_mdraid_page(parent, mdraid) {
247247
if (!block) {
248248
new_page(parent, mdraid_card);
249249
} else
250-
make_block_page(parent, block, mdraid_card);
250+
make_block_page(parent, block, mdraid_card, { partitionable: true });
251251
}
252252

253253
const MDRaidCard = ({ card, mdraid, block }) => {

pkg/storaged/pages.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ import { Spinner } from "@patternfly/react-core/dist/esm/components/Spinner/inde
3939
import { DescriptionListDescription, DescriptionListGroup, DescriptionListTerm } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";
4040
import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
4141

42-
import { decode_filename, block_short_name, fmt_size } from "./utils.js";
42+
import {
43+
decode_filename, block_short_name, fmt_size,
44+
reset_available_spaces
45+
} from "./utils.js";
4346
import { StorageButton, StorageBarMenu, StorageMenuItem, StorageSize } from "./storage-controls.jsx";
4447
import { MultipathAlert } from "./multipath.jsx";
4548
import { JobsPanel } from "./jobs-panel.jsx";
@@ -142,6 +145,7 @@ export const PAGE_CATEGORY_NETWORK = 3;
142145
export function reset_pages() {
143146
pages = new Map();
144147
crossrefs = new Map();
148+
reset_available_spaces();
145149
}
146150

147151
function name_from_card(card) {

pkg/storaged/partitions/partition-table.jsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ import cockpit from "cockpit";
2121
import React from "react";
2222
import client from "../client";
2323

24-
import { get_partitions } from "../utils.js";
24+
import { Alert } from "@patternfly/react-core/dist/esm/components/Alert/index.js";
25+
26+
import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";
27+
28+
import { get_partitions, register_available_free_space } from "../utils.js";
2529
import { StorageCard, ChildrenTable, new_page, new_card } from "../pages.jsx";
2630
import { format_dialog } from "../block/format-dialog.jsx";
2731
import { make_block_page } from "../block/create-pages.jsx";
@@ -68,9 +72,10 @@ function make_partition_pages(parent, block) {
6872
let p;
6973
for (i = 0; i < partitions.length; i++) {
7074
p = partitions[i];
71-
if (p.type == 'free')
75+
if (p.type == 'free') {
76+
register_available_free_space(client, block, p);
7277
make_free_space_page(parent, p.start, p.size, enable_dos_extended);
73-
else if (p.type == 'container')
78+
} else if (p.type == 'container')
7479
make_extended_partition_page(parent, p);
7580
else {
7681
const card = make_partition_card(null, p.block);
@@ -83,20 +88,21 @@ function make_partition_pages(parent, block) {
8388
block_ptable.Type == 'dos');
8489
}
8590

86-
export function make_partition_table_page(parent, block, next_card) {
91+
export function make_partition_table_page(parent, block, next_card, partitionable) {
8792
const block_ptable = client.blocks_ptable[block.path];
8893

8994
const parts_card = new_card({
9095
title: (block_ptable.Type
9196
? cockpit.format(_("$0 partitions"), block_ptable.Type.toLocaleUpperCase())
9297
: _("Partitions")),
9398
next: next_card,
94-
component: PartitionsCard,
99+
component: partitionable ? PartitionsCard : UnexpectedPartitionsCard,
95100
props: { },
96101
});
97102

98103
const p = new_page(parent, parts_card, { sorted: false });
99-
make_partition_pages(p, block);
104+
if (partitionable)
105+
make_partition_pages(p, block);
100106
}
101107

102108
const PartitionsCard = ({ card }) => {
@@ -109,3 +115,15 @@ const PartitionsCard = ({ card }) => {
109115
</StorageCard>
110116
);
111117
};
118+
119+
const UnexpectedPartitionsCard = ({ card }) => {
120+
return (
121+
<StorageCard card={card}>
122+
<CardBody>
123+
<Alert isInline isPlain variant="info" title={_("Unexpected partitions")}>
124+
<p>{_("Partitions are not supported on this block device. If it is used as a disk for a virtual machine, the partitions must be managed by the operating system inside the virtual machine.")}</p>
125+
</Alert>
126+
</CardBody>
127+
</StorageCard>
128+
);
129+
};

pkg/storaged/utils.js

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -511,44 +511,32 @@ export function is_available_block(client, block, honor_ignore_hint) {
511511
!should_ignore(client, block.path));
512512
}
513513

514-
export function get_available_spaces(client) {
515-
function make(path) {
516-
const block = client.blocks[path];
517-
const parts = get_block_link_parts(client, path);
518-
const text = cockpit.format(parts.format, parts.link);
519-
return { type: 'block', block, size: block.Size, desc: text };
520-
}
514+
let available_spaces = [];
521515

522-
const spaces = Object.keys(client.blocks).filter(p => is_available_block(client, client.blocks[p], true))
523-
.sort(make_block_path_cmp(client))
524-
.map(make);
525-
526-
function add_free_spaces(block) {
527-
const parts = get_partitions(client, block);
528-
let i;
529-
let p;
530-
let link_parts;
531-
let text;
532-
for (i in parts) {
533-
p = parts[i];
534-
if (p.type == 'free') {
535-
link_parts = get_block_link_parts(client, block.path);
536-
text = cockpit.format(link_parts.format, link_parts.link);
537-
spaces.push({
538-
type: 'free',
539-
block,
540-
start: p.start,
541-
size: p.size,
542-
desc: cockpit.format(_("unpartitioned space on $0"), text)
543-
});
544-
}
545-
}
546-
}
516+
export function get_available_spaces() {
517+
return available_spaces.sort((a, b) => block_cmp(a.block, b.block));
518+
}
519+
520+
export function reset_available_spaces() {
521+
available_spaces = [];
522+
}
547523

548-
for (const p in client.blocks_ptable)
549-
add_free_spaces(client.blocks[p]);
524+
export function register_available_block_space(client, block) {
525+
const parts = get_block_link_parts(client, block.path);
526+
const text = cockpit.format(parts.format, parts.link);
527+
available_spaces.push({ type: 'block', block, size: block.Size, desc: text });
528+
}
550529

551-
return spaces;
530+
export function register_available_free_space(client, block, partition) {
531+
const link_parts = get_block_link_parts(client, block.path);
532+
const text = cockpit.format(link_parts.format, link_parts.link);
533+
available_spaces.push({
534+
type: 'free',
535+
block,
536+
start: partition.start,
537+
size: partition.size,
538+
desc: cockpit.format(_("unpartitioned space on $0"), text)
539+
});
552540
}
553541

554542
export function prepare_available_spaces(client, spcs) {

test/verify/check-storage-lvm2

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,31 @@ class TestStorageLvm2(storagelib.StorageCase):
844844
b.wait_in_text(self.card_desc("LVM2 logical volume", "Physical volumes"), bn(disk))
845845
b.wait_in_text(self.card_desc("LVM2 logical volume", "Physical volumes"), bn(disk2))
846846

847+
def testUnsupportedPartitions(self):
848+
b = self.browser
849+
m = self.machine
850+
851+
self.login_and_go("/storage")
852+
853+
dev_1 = self.add_ram_disk(100)
854+
m.execute(f"vgcreate vgroup0 {dev_1}")
855+
self.addCleanupVG("vgroup0")
856+
m.execute("lvcreate vgroup0 -n lvol0 -l100%FREE")
857+
m.execute("parted /dev/vgroup0/lvol0 -s mktable gpt mkpart primary ext2 1M 50M")
858+
self.addCleanup(m.execute, "parted /dev/vgroup0/lvol0 -s mktable gpt; wipefs -a /dev/vgroup0/lvol0")
859+
860+
b.wait_text(self.card_row_col("Storage", row_name="lvol0", col_index=3), "GPT partitions")
861+
self.click_card_row("Storage", name="lvol0")
862+
b.wait_in_text(self.card("GPT partitions"), "Partitions are not supported on this block device.")
863+
864+
# Neither the partition nor the free space should be offered
865+
# for creating new things.
866+
867+
b.click(self.card_parent_link())
868+
b.click(self.card_parent_link())
869+
self.click_devices_dropdown("Create LVM2 volume group")
870+
b.wait_in_text("#dialog", "No disks are available")
871+
847872

848873
class TestStorageLvm2Destructive(storagelib.StorageCase):
849874

0 commit comments

Comments
 (0)