Skip to content

Commit

Permalink
Merge pull request #13184 from roosterfish/fix_lxd_recover
Browse files Browse the repository at this point in the history
Storage: Recover BTRFS pools `source` to block device UUID to align with creation process
  • Loading branch information
tomponline authored Mar 21, 2024
2 parents 01f0097 + 6aaafed commit 463e835
Showing 1 changed file with 26 additions and 8 deletions.
34 changes: 26 additions & 8 deletions lxd/storage/drivers/driver_btrfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,27 @@ func (d *btrfs) FillConfig() error {
d.config["size"] = ""
}

// Store the provided source as we are likely to be mangling it.
d.config["volatile.initial_source"] = d.config["source"]

// Set the block device's UUID in case it already has one.
// This allows to recover the pools configuration without actually
// creating the storage pool.
// Downstream functions should use `volatile.initial_source` to ensure
// they are using the path instead of the volume's UUID.
if shared.IsBlockdevPath(d.config["source"]) {
devUUID, err := fsUUID(d.config["source"])
if err == nil {
d.config["source"] = devUUID
}
}

return nil
}

// Create is called during pool creation and is effectively using an empty driver struct.
// WARNING: The Create() function cannot rely on any of the struct attributes being set.
func (d *btrfs) Create() error {
// Store the provided source as we are likely to be mangling it.
d.config["volatile.initial_source"] = d.config["source"]

revert := revert.New()
defer revert.Fail()

Expand Down Expand Up @@ -165,30 +177,36 @@ func (d *btrfs) Create() error {
if err != nil {
return fmt.Errorf("Failed to format sparse file: %w", err)
}
} else if shared.IsBlockdevPath(d.config["source"]) {
} else if shared.IsBlockdevPath(d.config["volatile.initial_source"]) {
// Make sure to use the block volumes `volatile.initial_source` here
// as an earlier call to the drivers FillConfig() might have set
// the `source` property to the block volumes UUID in case it's not empty.

// Wipe if requested.
if shared.IsTrue(d.config["source.wipe"]) {
err := wipeBlockHeaders(d.config["source"])
err := wipeBlockHeaders(d.config["volatile.initial_source"])
if err != nil {
return fmt.Errorf("Failed to wipe headers from disk %q: %w", d.config["source"], err)
return fmt.Errorf("Failed to wipe headers from disk %q: %w", d.config["volatile.initial_source"], err)
}

d.config["source.wipe"] = ""
}

// Format the block device.
_, err := makeFSType(d.config["source"], "btrfs", &mkfsOptions{Label: d.name})
_, err := makeFSType(d.config["volatile.initial_source"], "btrfs", &mkfsOptions{Label: d.name})
if err != nil {
return fmt.Errorf("Failed to format block device: %w", err)
}

// Record the UUID as the source.
devUUID, err := fsUUID(d.config["source"])
devUUID, err := fsUUID(d.config["volatile.initial_source"])
if err != nil {
return err
}

// Confirm that the symlink is appearing (give it 10s).
// In case of timeout it falls back to using the volume's path
// instead of its UUID.
if tryExists(fmt.Sprintf("/dev/disk/by-uuid/%s", devUUID)) {
// Override the config to use the UUID.
d.config["source"] = devUUID
Expand Down

0 comments on commit 463e835

Please sign in to comment.