Skip to content

Commit

Permalink
Merge pull request #1362 from ancorgs/swap_reuse
Browse files Browse the repository at this point in the history
Add internal setting to configure swap reusing in GuidedProposal
  • Loading branch information
ancorgs committed Oct 20, 2023
2 parents c7d9c4a + dbfbca9 commit 70f4fa7
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 12 deletions.
8 changes: 8 additions & 0 deletions package/yast2-storage-ng.changes
@@ -1,3 +1,11 @@
-------------------------------------------------------------------
Thu Oct 19 14:46:45 UTC 2023 - Ancor Gonzalez Sosa <ancor@suse.com>

- GuidedProposal: new internal setting to control how existing
swap partitions are reused. Relevant for Agama and related to
bsc#1175535 and bsc#1215639.
- 5.0.3

-------------------------------------------------------------------
Wed Oct 11 08:41:15 UTC 2023 - Ancor Gonzalez Sosa <ancor@suse.com>

Expand Down
2 changes: 1 addition & 1 deletion package/yast2-storage-ng.spec
Expand Up @@ -16,7 +16,7 @@
#

Name: yast2-storage-ng
Version: 5.0.2
Version: 5.0.3
Release: 0
Summary: YaST2 - Storage Configuration
License: GPL-2.0-only OR GPL-3.0-only
Expand Down
25 changes: 22 additions & 3 deletions src/lib/y2storage/proposal/devices_planner.rb
Expand Up @@ -93,21 +93,40 @@ def planned_boot_devices(planned_devices)
# @param required_size [DiskSize]
# @return [Partition]
def reusable_swap(required_size)
return nil if settings.use_lvm || settings.use_encryption
return nil unless try_to_reuse_swap?

partitions = available_swap_partitions
partitions.select! { |part| part.size >= required_size }
partitions.select! { |part| can_be_reused?(part, required_size) }
# Use #name in case of #size tie to provide stable sorting
partitions.min_by { |part| [part.size, part.name] }
end

# Returns all avaiable swap partitions
# Returns all available and acceptable swap partitions
#
# @return [Array<Partition>]
def available_swap_partitions
devicegraph.partitions.select(&:swap?)
end

# Whether it makes sense to try to reuse existing swap partitions
#
# @return [Boolean]
def try_to_reuse_swap?
!settings.use_lvm && !settings.use_encryption && settings.swap_reuse != :none
end

# Whether it is acceptable to reuse the given swap partition
#
# @param partition [Partition]
# @param required_size [DiskSize]
# @return [Boolean]
def can_be_reused?(partition, required_size)
return false if partition.size < required_size
return true unless settings.swap_reuse == :candidate

settings.candidate_devices.include?(partition.partitionable.name)
end

# Delete shadowed subvolumes from each planned device
# @param planned_devices [Array<Planned::Device>] devices that have been planned
def remove_shadowed_subvolumes(planned_devices)
Expand Down
10 changes: 10 additions & 0 deletions src/lib/y2storage/proposal_settings.rb
Expand Up @@ -62,6 +62,15 @@ class ProposalSettings
# available candidate devices.
attr_accessor :multidisk_first

# Criteria to use if it is possible to reuse an existing swap partition
#
# * :any reuse a suitable swap partition from any disk, default historical behavior of YaST
# * :none do not reuse existing swap partitions
# * :candidate reuse a suitable partition only if it is located in a candidate disk
#
# @return [:any, :none, :candidate]
attr_accessor :swap_reuse

# Device name of the disk in which '/' must be placed.
#
# If it's set to nil and {#allocate_volume_mode} is :auto, the proposal will try
Expand Down Expand Up @@ -388,6 +397,7 @@ def root_volume
other_delete_mode: :ondemand,
resize_windows: true,
separate_vgs: false,
swap_reuse: :any,
volumes: [],
windows_delete_mode: :ondemand
}
Expand Down
15 changes: 7 additions & 8 deletions test/data/devicegraphs/autoyast_drive_examples.yml
Expand Up @@ -40,9 +40,9 @@
- partition:
size: 1 GiB
name: /dev/dasdb1
id: swap
file_system: swap
mount_point: swap
label: swap
label: swap_dasdb

- partition:
size: 6 GiB
Expand Down Expand Up @@ -73,8 +73,7 @@
name: /dev/sdc2
id: swap
file_system: swap
mount_point: swap
label: swap
label: swap_sdc

- partition:
size: 20 GiB
Expand Down Expand Up @@ -162,7 +161,7 @@
type: logical
id: swap
file_system: swap
mount_point: swap
label: swap_sdd

- partition:
size: 10 GiB
Expand Down Expand Up @@ -215,6 +214,7 @@
type: logical
id: swap
file_system: swap
label: swap_sdf

- partition:
size: 10 GiB
Expand Down Expand Up @@ -265,8 +265,7 @@
name: /dev/sdaa2
id: swap
file_system: swap
mount_point: swap
label: swap
label: swap_sdaa

- partition:
size: 20 GiB
Expand Down Expand Up @@ -328,7 +327,7 @@
name: /dev/sdh3
id: swap
file_system: swap
mount_point: swap
label: swap_sdh

# Btrfs with default_subvolume set to ""
- disk:
Expand Down
147 changes: 147 additions & 0 deletions test/y2storage/proposal_swap_reuse_test.rb
@@ -0,0 +1,147 @@
#!/usr/bin/env rspec
# Copyright (c) [2023] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program 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 General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.

require_relative "spec_helper"
require "storage"
require "y2storage"
require_relative "#{TEST_PATH}/support/proposal_examples"
require_relative "#{TEST_PATH}/support/proposal_context"

describe Y2Storage::GuidedProposal do
describe "#propose in a system with pre-existing swap partitions" do
subject(:proposal) { described_class.new(settings: settings) }

include_context "proposal"
let(:architecture) { :x86 }
let(:settings_format) { :ng }
let(:control_file_content) do
{ "partitioning" => { "volumes" => volumes } }
end

let(:scenario) { "autoyast_drive_examples" }

let(:volumes) { [root_vol, swap_vol] }
let(:root_vol) do
{ "mount_point" => "/", "fs_type" => "xfs", "min_size" => "5 GiB", "max_size" => "30 GiB" }
end
let(:swap_vol) do
{ "mount_point" => "swap", "fs_type" => "swap", "min_size" => "500 MiB", "max_size" => "2 GiB" }
end

RSpec.shared_examples "reuse best swap" do
it "reuses the pre-existing swap with more suitable size" do
proposal.propose
dasdb1 = proposal.devices.find_by_name("/dev/dasdb1")
expect(dasdb1.exists_in_probed?).to eq true
expect(dasdb1).to have_attributes(
# This proves is mounted as swap
filesystem_mountpoint: "swap",
# This proves is not re-formatted
filesystem_label: "swap_dasdb",
size: Y2Storage::DiskSize.GiB(1)
)
end
end

RSpec.shared_examples "new swap" do
it "creates a new swap partition" do
proposal.propose
swap = proposal.devices.partitions.find { |p| p.filesystem&.mount_path == "swap" }
expect(swap.exists_in_probed?).to eq false
# All preexisting partitions have some label
expect(swap.filesystem.label).to be_empty
end
end

before { settings.candidate_devices = [candidate] }

context "when swap_reuse is set to :any" do
before { settings.swap_reuse = :any }

context "and there is no swap in the candidate devices" do
let(:candidate) { "/dev/sda" }

include_examples "reuse best swap"
end

context "and there is a swap device (not the best regarding size) in the candidate devices" do
let(:candidate) { "/dev/sdc" }

include_examples "reuse best swap"
end

context "and the best swap device in the candidate devices" do
let(:candidate) { "/dev/dasdb" }

include_examples "reuse best swap"
end
end

context "when swap_reuse is set to :none" do
before { settings.swap_reuse = :none }

context "and there is no swap in the candidate devices" do
let(:candidate) { "/dev/sda" }

include_examples "new swap"
end

context "and there is a swap device (not the biggest one) in the candidate devices" do
let(:candidate) { "/dev/sdc" }

include_examples "new swap"
end

context "and the biggest swap device in the candidate devices" do
let(:candidate) { "/dev/dasdb" }

include_examples "new swap"
end
end

context "when swap_reuse is set to :candidate" do
before { settings.swap_reuse = :candidate }

context "and there is no swap in the candidate devices" do
let(:candidate) { "/dev/sda" }

include_examples "new swap"
end

context "and there is a swap device (not the biggest one) in the candidate devices" do
let(:candidate) { "/dev/sdc" }

it "reuses the swap partition from the candidate devices" do
proposal.propose
swap = proposal.devices.partitions.find { |p| p.filesystem&.mount_path == "swap" }
expect(swap.exists_in_probed?).to eq true
expect(swap.name).to eq "/dev/sdc2"
expect(swap.filesystem.label).to eq "swap_sdc"
end
end

context "and the biggest swap device in the candidate devices" do
let(:candidate) { "/dev/dasdb" }

include_examples "reuse best swap"
end
end
end
end

0 comments on commit 70f4fa7

Please sign in to comment.