Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

storage: Tell people that big mdraids really should have a bitmap #18979

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions pkg/storaged/mdraid-details.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import * as utils from "./utils.js";
import { StdDetailsLayout } from "./details.jsx";
import { SidePanel } from "./side-panel.jsx";
import { Block } from "./content-views.jsx";
import { StorageButton, StorageOnOff } from "./storage-controls.jsx";
import { StorageButton } from "./storage-controls.jsx";
import {
dialog_open, SelectSpaces, BlockingMessage, TeardownMessage,
init_active_usage_processes
Expand Down Expand Up @@ -180,23 +180,6 @@ export class MDRaidDetails extends React.Component {
if (mdraid.ChunkSize > 0)
level += ", " + cockpit.format(_("$0 chunk size"), utils.fmt_size(mdraid.ChunkSize));

function toggle_bitmap(val) {
return mdraid.SetBitmapLocation(utils.encode_filename(val ? 'internal' : 'none'), {});
}

let bitmap = null;
if (mdraid.BitmapLocation) {
const value = utils.decode_filename(mdraid.BitmapLocation) != "none";
bitmap = (
<DescriptionListGroup>
<DescriptionListTerm>{_("storage", "Bitmap")}</DescriptionListTerm>
<DescriptionListDescription>
<StorageOnOff state={value} aria-label={_("Toggle bitmap")} onChange={toggle_bitmap} />
</DescriptionListDescription>
</DescriptionListGroup>
);
}

let degraded_message = null;
if (mdraid.Degraded > 0) {
const text = cockpit.format(
Expand All @@ -208,6 +191,24 @@ export class MDRaidDetails extends React.Component {
);
}

function fix_bitmap() {
return mdraid.SetBitmapLocation(utils.encode_filename("internal"), { });
}

let bitmap_message = null;
if (mdraid.Level != "raid0" &&
client.mdraids_members[mdraid.path].some(m => m.Size > 100 * 1024 * 1024 * 1024) &&
mdraid.BitmapLocation && utils.decode_filename(mdraid.BitmapLocation) == "none") {
bitmap_message = (
<Alert isInline variant="warning"
title={_("This RAID array has no write-intent bitmap. Such a bitmap can reduce sychronization times significantly.")}>
<div className="storage_alert_action_buttons">
<StorageButton onClick={fix_bitmap}>{_("Add a bitmap")}</StorageButton>
</div>
</Alert>
);
}

/* Older versions of Udisks/storaged don't have a Running property */
let running = mdraid.Running;
if (running === undefined)
Expand Down Expand Up @@ -338,9 +339,6 @@ export class MDRaidDetails extends React.Component {
<DescriptionListTerm>{_("storage", "RAID level")}</DescriptionListTerm>
<DescriptionListDescription>{ level }</DescriptionListDescription>
</DescriptionListGroup>

{ bitmap }

<DescriptionListGroup>
<DescriptionListTerm>{_("storage", "State")}</DescriptionListTerm>
<DescriptionListDescription>{ running ? _("Running") : _("Not running") }</DescriptionListDescription>
Expand All @@ -355,7 +353,7 @@ export class MDRaidDetails extends React.Component {
const content = <Block client={this.props.client} block={block} />;

return <StdDetailsLayout client={this.props.client}
alerts={[degraded_message]}
alerts={[degraded_message, bitmap_message]}
header={ header }
sidebar={ sidebar }
content={ content }
Expand Down
13 changes: 9 additions & 4 deletions test/common/storagelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,22 @@ def add_loopback_disk(self, size=50, name=None):

The disk gets removed automatically when the test ends. This is safe for @nondestructive tests.

Unlike add_ram_disk(), this can be called multiple times, and is less size constrained.
However, loopback devices look quite special to the OS, so they are not a very good
simulation of a "real" disk.
Unlike add_ram_disk(), this can be called multiple times, and
is less size constrained. The backing file starts out sparse,
so this can be used to create massive block devices, as long
as you are careful to not actually use much of it.

However, loopback devices look quite special to the OS, so
they are not a very good simulation of a "real" disk.

Return the device name.

"""
# HACK: https://bugzilla.redhat.com/show_bug.cgi?id=1969408
# It would be nicer to remove $F immediately after the call to
# losetup, but that will break some versions of lvm2.
dev = self.machine.execute("F=$(mktemp /var/tmp/loop.XXXX); "
"dd if=/dev/zero of=$F bs=1000000 count=%s; "
"truncate --size=%sMB $F; "
"losetup --show %s $F" % (size, name if name else "--find")).strip()
# If this device had partions in its last incarnation on this
# machine, they might come back for unknown reasons, in a
Expand Down
38 changes: 38 additions & 0 deletions test/verify/check-storage-mdraid
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,44 @@ class TestStorageMdRaid(storagelib.StorageCase):
# The last disk can not be removed
b.wait_visible('#detail-sidebar .sidepanel-row:contains(DISK2) button:disabled')

def testBitmap(self):
m = self.machine
b = self.browser

self.login_and_go("/storage")

# Make two huge block devices, so that we can make a array
# that is beyond the threshold where Cockpit and mdadm start
# to worry about bitmaps. The backing files are sparse, so
# this is okay as long nobody actually writes a lot to these
# devices.

dev1 = self.add_loopback_disk(110000)
dev2 = self.add_loopback_disk(110000)

# We need to use "--assume-clean" so that mdraid doesn't try
# to write 110GB to one of the devices during synchronization.

m.execute(f"mdadm --create md0 --level=1 --assume-clean --run --raid-devices=2 {dev1} {dev2}")
m.execute("udevadm trigger")

b.wait_in_text("#devices", "md0")
b.click('#devices .sidepanel-row:contains("md")')
b.wait_visible('#storage-detail')

self.wait_states({dev1: "In sync",
dev2: "In sync"})

b.wait_not_present('.pf-v5-c-alert:contains("This RAID array has no write-intent bitmap")')

# Remove the bitmap, Cockpit should complain and let us put it back.

m.execute("mdadm --grow --bitmap=none /dev/md/md0; udevadm trigger /dev/md/md0")

b.wait_visible('.pf-v5-c-alert:contains("This RAID array has no write-intent bitmap")')
b.click('button:contains("Add a bitmap")')
b.wait_not_present('.pf-v5-c-alert:contains("This RAID array has no write-intent bitmap")')


if __name__ == '__main__':
testlib.test_main()