Skip to content

Commit

Permalink
WIP - unformatted data
Browse files Browse the repository at this point in the history
  • Loading branch information
mvollmer committed Oct 26, 2023
1 parent 7dc3ab9 commit 246149f
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 49 deletions.
7 changes: 7 additions & 0 deletions pkg/storaged/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,13 @@ function update_indices() {
}
}

client.blocks_available = { };
for (path in client.blocks) {
block = client.blocks[path];
if (utils.is_available_block(client, block))
client.blocks_available[path] = true;
}

client.path_jobs = { };
function enter_job(job) {
if (!job.Objects || !job.Objects.length)
Expand Down
45 changes: 41 additions & 4 deletions pkg/storaged/containers/lvm2-logical-volume.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ import { SCard } from "../utils/card.jsx";
import { SDesc } from "../utils/desc.jsx";
import { check_unused_space, get_resize_info, grow_dialog, shrink_dialog } from "../resize.jsx";
import { new_container, navigate_to_new_page_location, ActionButtons } from "../pages.jsx";
import { fmt_size } from "../utils.js";
import { fmt_size, get_active_usage, teardown_active_usage, reload_systemd } from "../utils.js";
import { lvm2_delete_logical_volume_dialog, lvm2_create_snapshot_action } from "../pages/lvm2-volume-group.jsx";
import {
dialog_open, TextInput, SelectSpaces,
dialog_open, TextInput, SelectSpaces, BlockingMessage, TeardownMessage,
init_active_usage_processes
} from "../dialog.jsx";

import { StructureDescription } from "../lvol-tabs.jsx"; // XXX
Expand Down Expand Up @@ -94,6 +95,35 @@ function repair(lvol) {
});
}

function deactivate(lvol, block) {
const vgroup = client.vgroups[lvol.VolumeGroup];
const usage = get_active_usage(client, block.path, _("deactivate"));

if (usage.Blocking) {
dialog_open({
Title: cockpit.format(_("$0 is in use"), lvol.Name),
Body: BlockingMessage(usage)
});
return;
}

dialog_open({
Title: cockpit.format(_("Deactivate logical volume $0/$1?"), vgroup.Name, lvol.Name),
Teardown: TeardownMessage(usage),
Action: {
Title: _("Deactivate"),
action: async function () {
await teardown_active_usage(client, usage);
await lvol.Deactivate({ });
await reload_systemd();
}
},
Inits: [
init_active_usage_processes(client, usage)
]
});
}

export function make_lvm2_logical_volume_container(parent, vgroup, lvol, block) {
const unused_space_warning = check_unused_space(block.path);
const unused_space = !!unused_space_warning;
Expand Down Expand Up @@ -138,10 +168,17 @@ export function make_lvm2_logical_volume_container(parent, vgroup, lvol, block)
action: () => grow_dialog(client, lvol, info),
excuse: grow_excuse,
}),
{ title: _("Deactivate"), action: () => lvol.Deactivate({}) },
{
title: _("Deactivate"),
action: () => deactivate(lvol, block),
},
lvm2_create_snapshot_action(lvol),
repair_action,
{ title: _("Delete"), action: () => lvm2_delete_logical_volume_dialog(lvol, cont.page), danger: true },
{
title: _("Delete"),
action: () => lvm2_delete_logical_volume_dialog(lvol, cont.page),
danger: !client.blocks_available[block.path],
},
],
});
return cont;
Expand Down
2 changes: 1 addition & 1 deletion pkg/storaged/containers/partition.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function make_partition_container(parent, block) {
{
title: _("Delete"),
action: () => delete_partition(block, cont.page),
danger: true
danger: !client.blocks_available[block.path],
},
],
});
Expand Down
3 changes: 3 additions & 0 deletions pkg/storaged/create-pages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { format_dialog } from "./format-dialog.jsx";

import { make_overview_page } from "./pages/overview.jsx";
import { make_unrecognized_data_page } from "./pages/unrecognized-data.jsx";
import { make_unformatted_data_page } from "./pages/unformatted-data.jsx";
import { make_locked_encrypted_data_page } from "./pages/locked-encrypted-data.jsx";
import { make_filesystem_page } from "./pages/filesystem.jsx";
import { make_lvm2_physical_volume_page } from "./pages/lvm2-physical-volume.jsx";
Expand Down Expand Up @@ -157,6 +158,8 @@ export function make_block_page(parent, block, container) {
make_mdraid_disk_page(parent, block, content_block, container);
} else if (block_swap || (content_block && content_block.IdUsage == "other" && content_block.IdType == "swap")) {
make_swap_page(parent, block, content_block, container);
} else if (client.blocks_available[content_block.path]) {
make_unformatted_data_page(parent, block, content_block, container);
} else {
make_unrecognized_data_page(parent, block, content_block, container);
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/storaged/pages/drive.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export function make_drive_page(parent, drive) {
? {
title: _("Create partition table"),
action: () => format_disk(client, block),
danger: false, // XXX - mark as dangerous when not "unrecognized data"
danger: !client.blocks_available[block.path],
excuse: block.ReadOnly ? _("Device is read-only") : null,
tag: "content"
}
Expand Down
76 changes: 76 additions & 0 deletions pkg/storaged/pages/unformatted-data.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* This file is part of Cockpit.
*
* Copyright (C) 2023 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/

import cockpit from "cockpit";
import React from "react";
import client from "../client";

import { CardBody } from "@patternfly/react-core/dist/esm/components/Card/index.js";
import { Stack, StackItem } from "@patternfly/react-core/dist/esm/layouts/Stack/index.js";
import { DescriptionList } from "@patternfly/react-core/dist/esm/components/DescriptionList/index.js";

import {
ParentPageLink, PageContainerStackItems,
new_page, block_location, ActionButtons, page_type,
} from "../pages.jsx";
import { SCard } from "../utils/card.jsx";
import { SDesc } from "../utils/desc.jsx";
import { format_dialog } from "../format-dialog.jsx";
import { block_name, fmt_size } from "../utils.js";
import { std_lock_action } from "../actions.jsx";

const _ = cockpit.gettext;

export function make_unformatted_data_page(parent, backing_block, content_block, container) {
new_page({
location: [block_location(backing_block)],
parent,
container,
name: block_name(backing_block),
columns: [
_("Unformatted data"),
null,
fmt_size(backing_block.Size)
],
component: UnformattedDataPage,
props: { backing_block, content_block },
actions: [
std_lock_action(backing_block, content_block),
{ title: _("Format"), action: () => format_dialog(client, backing_block.path) },
]
});
}

export const UnformattedDataPage = ({ page, backing_block, content_block }) => {
return (
<Stack hasGutter>
<StackItem>
<SCard title={page_type(page)} actions={<ActionButtons page={page} />}>
<CardBody>
<DescriptionList className="pf-m-horizontal-on-sm">
<SDesc title={_("Stored on")}>
<ParentPageLink page={page} />
</SDesc>
</DescriptionList>
</CardBody>
</SCard>
</StackItem>
<PageContainerStackItems page={page} />
</Stack>);
};
10 changes: 10 additions & 0 deletions pkg/storaged/resize.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ function lvol_or_part_and_fsys_resize(client, lvol_or_part, size, offline, passp
return Promise.reject(_("Stratis blockdevs can not be made smaller")); // not-covered: safety check
else
return Promise.resolve();
} else if (client.blocks_available[block.path]) {
// Growing or shrinking unformatted data, nothing to do
return Promise.resolve();
} else if (size < orig_size) {
// This shouldn't happen. But if it does, continuing is harmful, so we throw an error.
return Promise.reject(_("Unrecognized data can not be made smaller here.")); // not-covered: safety check
Expand Down Expand Up @@ -276,6 +279,13 @@ export function get_resize_info(client, block, to_fit) {
grow_needs_unmount: false
};
shrink_excuse = _("VDO backing devices can not be made smaller");
} else if (client.blocks_available[block.path]) {
info = {
can_shrink: true,
can_grow: true,
shrink_needs_unmount: false,
grow_needs_unmount: false,
};
} else {
info = {
can_shrink: false,
Expand Down
85 changes: 42 additions & 43 deletions pkg/storaged/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,64 +451,63 @@ export function get_partitions(client, block) {
return process_level(0, 0, block.Size);
}

export function get_available_spaces(client) {
function is_free(path) {
const block = client.blocks[path];
const block_ptable = client.blocks_ptable[path];
const block_part = client.blocks_part[path];
const block_pvol = client.blocks_pvol[path];

function has_fs_label() {
if (!block.IdUsage)
return false;
// Devices with a LVM2_member label need to actually be
// associated with a volume group.
if (block.IdType == 'LVM2_member' && (!block_pvol || !client.vgroups[block_pvol.VolumeGroup]))
return false;
return true;
}
export function is_available_block(client, block) {
const block_ptable = client.blocks_ptable[block.path];
const block_part = client.blocks_part[block.path];
const block_pvol = client.blocks_pvol[block.path];

function is_mpath_member() {
if (!client.drives[block.Drive])
return false;
if (!client.drives_block[block.Drive]) {
// Broken multipath drive
return true;
}
const members = client.drives_multipath_blocks[block.Drive];
for (let i = 0; i < members.length; i++) {
if (members[i] == block)
return true;
}
function has_fs_label() {
if (!block.IdUsage)
return false;
}
// Devices with a LVM2_member label need to actually be
// associated with a volume group.
if (block.IdType == 'LVM2_member' && (!block_pvol || !client.vgroups[block_pvol.VolumeGroup]))
return false;
return true;
}

function is_vdo_backing_dev() {
return !!client.legacy_vdo_overlay.find_by_backing_block(block);
function is_mpath_member() {
if (!client.drives[block.Drive])
return false;
if (!client.drives_block[block.Drive]) {
// Broken multipath drive
return true;
}

function is_swap() {
return !!block && client.blocks_swap[path];
const members = client.drives_multipath_blocks[block.Drive];
for (let i = 0; i < members.length; i++) {
if (members[i] == block)
return true;
}
return false;
}

return (!block.HintIgnore &&
block.Size > 0 &&
!has_fs_label() &&
!is_mpath_member() &&
!is_vdo_backing_dev() &&
!is_swap() &&
!block_ptable &&
!(block_part && block_part.IsContainer));
function is_vdo_backing_dev() {
return !!client.legacy_vdo_overlay.find_by_backing_block(block);
}

function is_swap() {
return !!block && client.blocks_swap[block.path];
}

return (!block.HintIgnore &&
block.Size > 0 &&
!has_fs_label() &&
!is_mpath_member() &&
!is_vdo_backing_dev() &&
!is_swap() &&
!block_ptable &&
!(block_part && block_part.IsContainer));
}

export function get_available_spaces(client) {
function make(path) {
const block = client.blocks[path];
const parts = get_block_link_parts(client, path);
const text = cockpit.format(parts.format, parts.link);
return { type: 'block', block, size: block.Size, desc: text };
}

const spaces = Object.keys(client.blocks).filter(is_free)
const spaces = Object.keys(client.blocks).filter(p => is_available_block(client, client.blocks[p]))
.sort(make_block_path_cmp(client))
.map(make);

Expand Down

0 comments on commit 246149f

Please sign in to comment.