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

Btrfs subvolume creation #19849

Merged
merged 2 commits into from
Jan 22, 2024
Merged

Conversation

jelly
Copy link
Member

@jelly jelly commented Jan 16, 2024

Support creating and optionally mounting subvolumes. Subvolumes can only be created when any parent in the tree is mounted.

image

image

@jelly jelly added the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Jan 16, 2024
@jelly jelly removed the no-test For doc/workflow changes, or experiments which don't need a full CI run, label Jan 17, 2024
@jelly jelly marked this pull request as ready for review January 17, 2024 12:18
@jelly jelly force-pushed the btrfs-subvolume-creation branch 2 times, most recently from d9be999 to 0fd0594 Compare January 18, 2024 15:41
pkg/storaged/btrfs/subvolume.jsx Outdated Show resolved Hide resolved
pkg/storaged/btrfs/subvolume.jsx Outdated Show resolved Hide resolved
pkg/storaged/btrfs/subvolume.jsx Outdated Show resolved Hide resolved
if (!mounted && subvol.id == 5)
create_excuse = _("Subvolume needs to be mounted");
if (mounted && opt_ro)
create_excuse = _("Subvolume needs to be mounted rw");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not say "rw" but "Subvolume needs to be writable".

Also, I think creation is possible if one of the parents is mounted rw, and get_mount_point_in_parent takes that into account.

So what about this:

if (!mount_point_in_parent) {
      if (!mounted)
        create_excuse = _("Subvolume needs to be mounted");
    if (!mounted && subvol.id == 5)
        create_excuse = _("Subvolume needs to be mounted");
    if (mounted && opt_ro)
        create_excuse = _("Subvolume needs to be mounted writable");
}

Thus, we only talk to the user in terms of the current subvolume and never about parents.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I don't think this is true. mount_point_in_parent returns the mount_point for the current parent and doesn't become true. It breaks the current test_case for mounted && opt_ro.

/dev/sda on /run/ro type btrfs (ro,relatime,seclabel,ssd,space_cache=v2,subvolid=264,subvol=/ro)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It breaks the current test_case

There is a test case where we expect that creation inside the subvolume "ro" (mounted at "/run/ro") should be disabled, but with my proposed changes, it is enabled. Right?

This happens because the root subvol is still mounted read-write at "/run/butter" and creation of subvolumes of "ro" can be done inside the mount point "/run/butter/ro".

(I think, I'll check this now.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my "PROPOSAL" commit.

if (name.length > 255)
return _("Name cannot be longer than 255 characters.");
if (name.includes('/'))
return cockpit.format(_("Name cannot contain the character '/'."));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about subvolumes in directories? Should we allow those to be created in Cockpit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we don't offer listing directories so how would a user be able to create such?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By giving a name like "dir/dir/subvol" when creating a new one, maybe. Cockpit would do the necessary "mkdir -p".

But I agree that this might be confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we could but I honestly found this a bit confusing:

btrfs subvolume create -p foo/bar/ding
ID 264 gen 145 parent 256 top level 256 path root/root/foo/bar/ding

So foo/bar are just normal directories. Not super obvious if you ask me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, btrfs itself has a -p option, neat! But, yeah, no strong opinions here.

pkg/storaged/btrfs/subvolume.jsx Outdated Show resolved Hide resolved
pkg/storaged/btrfs/subvolume.jsx Outdated Show resolved Hide resolved
@jelly jelly force-pushed the btrfs-subvolume-creation branch 2 times, most recently from 68fa567 to 8d2067d Compare January 19, 2024 10:49
@jelly jelly requested a review from mvollmer January 19, 2024 10:49
"Subvolume needs to be mounted")
b.click(self.dropdown_toggle(root_sel))

self.click_dropdown(self.card_row("Storage", name=label) + " + tr", "Mount")
Copy link
Member

@mvollmer mvollmer Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is self.click_card_dropdown which probably works here and is cleaner.

@mvollmer mvollmer self-requested a review January 19, 2024 13:37
Copy link
Member

@mvollmer mvollmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the PROPOSAL commit.

Allow a user to create a new subvolume if the parent subvolume is
mounted or any of it's parent subvolumes is mounted.

We don't use btrfs's CreateSubvolume as it uses the first mount point
from the block device, so with multiple subvol's mounted it is not
possible to predict / influence on what mount point it will be created.
Comment on lines +78 to +79
if (!mount_now || vals.at_boot == "never") {
mount_options.push("noauto");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 2 added lines are not executed by any test. Details

if (vals.mount_options.ro)
mount_options.push("ro");
if (vals.at_boot == "never")
mount_options.push("x-cockpit-never-auto");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

if (vals.at_boot == "never")
mount_options.push("x-cockpit-never-auto");
if (vals.at_boot == "nofail")
mount_options.push("nofail");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

if (vals.at_boot == "nofail")
mount_options.push("nofail");
if (vals.at_boot == "netdev")
mount_options.push("_netdev");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

if (vals.at_boot == "netdev")
mount_options.push("_netdev");

const name = (subvol.pathname == "/" ? vals.name : subvol.pathname + "/" + vals.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

const name = (subvol.pathname == "/" ? vals.name : subvol.pathname + "/" + vals.name);
mount_options.push("subvol=" + name);
if (vals.mount_options.extra)
mount_options.push(vals.mount_options.extra);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details


let mount_point = vals.mount_point;
if (mount_point[0] != "/")
mount_point = "/" + mount_point;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

{
dir: { t: 'ay', v: encode_filename(mount_point) },
type: { t: 'ay', v: encode_filename("btrfs") },
opts: { t: 'ay', v: encode_filename(mount_options.join(",") || "defaults") },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

if (mount_now) {
return client.mount_at(block, mount_point);
} else
return Promise.resolve();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

]
}),
mount_options(false, false),
at_boot_input(client.in_anaconda_mode() ? "local" : "nofail"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added line is not executed by any test. Details

Copy link
Member

@mvollmer mvollmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@jelly jelly merged commit ad5d2a5 into cockpit-project:main Jan 22, 2024
92 of 93 checks passed
@jelly jelly deleted the btrfs-subvolume-creation branch January 22, 2024 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants