1 use std
::collections
::HashSet
;
3 use crate::options
::{BtrfsRaidLevel, Disk, ZfsRaidLevel}
;
4 use crate::setup
::BootType
;
6 /// Checks a list of disks for duplicate entries, using their index as key.
10 /// * `disks` - A list of disks to check for duplicates.
11 pub fn check_for_duplicate_disks(disks
: &[Disk
]) -> Result
<(), &Disk
> {
12 let mut set
= HashSet
::new();
15 if !set
.insert(&disk
.index
) {
23 /// Simple wrapper which returns an descriptive error if the list of disks is too short.
27 /// * `disks` - A list of disks to check the lenght of.
28 /// * `min` - Minimum number of disks
29 pub fn check_raid_min_disks(disks
: &[Disk
], min
: usize) -> Result
<(), String
> {
30 if disks
.len() < min
{
31 Err(format
!("Need at least {min} disks"))
37 /// Checks all disks for legacy BIOS boot compatibility and reports an error as appropriate. 4Kn
38 /// disks are generally broken with legacy BIOS and cannot be booted from.
42 /// * `runinfo` - `RuntimeInfo` instance of currently running system
43 /// * `disks` - List of disks designated as bootdisk targets.
44 pub fn check_disks_4kn_legacy_boot(boot_type
: BootType
, disks
: &[Disk
]) -> Result
<(), &str> {
45 let is_blocksize_4096
= |disk
: &Disk
| disk
.block_size
.map(|s
| s
== 4096).unwrap_or(false);
47 if boot_type
== BootType
::Bios
&& disks
.iter().any(is_blocksize_4096
) {
48 return Err("Booting from 4Kn drive in legacy BIOS mode is not supported.");
54 /// Checks whether a user-supplied ZFS RAID setup is valid or not, such as disk sizes andminimum
59 /// * `level` - The targeted ZFS RAID level by the user.
60 /// * `disks` - List of disks designated as RAID targets.
61 pub fn check_zfs_raid_config(level
: ZfsRaidLevel
, disks
: &[Disk
]) -> Result
<(), String
> {
62 // See also Proxmox/Install.pm:get_zfs_raid_setup()
64 let check_mirror_size
= |disk1
: &Disk
, disk2
: &Disk
| {
65 if (disk1
.size
- disk2
.size
).abs() > disk1
.size
/ 10. {
67 "Mirrored disks must have same size:\n\n * {disk1}\n * {disk2}"
75 ZfsRaidLevel
::Raid0
=> check_raid_min_disks(disks
, 1)?
,
76 ZfsRaidLevel
::Raid1
=> {
77 check_raid_min_disks(disks
, 2)?
;
79 check_mirror_size(&disks
[0], disk
)?
;
82 ZfsRaidLevel
::Raid10
=> {
83 check_raid_min_disks(disks
, 4)?
;
85 if disks
.len() % 2 != 0 {
87 "Needs an even number of disks, currently selected: {}",
92 // Pairs need to have the same size
93 for i
in (0..disks
.len()).step_by(2) {
94 check_mirror_size(&disks
[i
], &disks
[i
+ 1])?
;
97 // For RAID-Z: minimum disks number is level + 2
98 ZfsRaidLevel
::RaidZ
=> {
99 check_raid_min_disks(disks
, 3)?
;
101 check_mirror_size(&disks
[0], disk
)?
;
104 ZfsRaidLevel
::RaidZ2
=> {
105 check_raid_min_disks(disks
, 4)?
;
107 check_mirror_size(&disks
[0], disk
)?
;
110 ZfsRaidLevel
::RaidZ3
=> {
111 check_raid_min_disks(disks
, 5)?
;
113 check_mirror_size(&disks
[0], disk
)?
;
121 /// Checks whether a user-supplied Btrfs RAID setup is valid or not, such as minimum
126 /// * `level` - The targeted Btrfs RAID level by the user.
127 /// * `disks` - List of disks designated as RAID targets.
128 pub fn check_btrfs_raid_config(level
: BtrfsRaidLevel
, disks
: &[Disk
]) -> Result
<(), String
> {
129 // See also Proxmox/Install.pm:get_btrfs_raid_setup()
132 BtrfsRaidLevel
::Raid0
=> check_raid_min_disks(disks
, 1)?
,
133 BtrfsRaidLevel
::Raid1
=> check_raid_min_disks(disks
, 2)?
,
134 BtrfsRaidLevel
::Raid10
=> check_raid_min_disks(disks
, 4)?
,
144 fn dummy_disk(index
: usize) -> Disk
{
146 index
: index
.to_string(),
147 path
: format
!("/dev/dummy{index}"),
148 model
: Some("Dummy disk".to_owned()),
149 size
: 1024. * 1024. * 1024. * 8.,
150 block_size
: Some(512),
154 fn dummy_disks(num
: usize) -> Vec
<Disk
> {
155 (0..num
).map(dummy_disk
).collect()
159 fn duplicate_disks() {
160 assert
!(check_for_duplicate_disks(&dummy_disks(2)).is_ok());
162 check_for_duplicate_disks(&[
174 fn raid_min_disks() {
175 let disks
= dummy_disks(10);
177 assert
!(check_raid_min_disks(&disks
[..1], 2).is_err());
178 assert
!(check_raid_min_disks(&disks
[..1], 1).is_ok());
179 assert
!(check_raid_min_disks(&disks
, 1).is_ok());
183 fn bios_boot_compat_4kn() {
185 let mut disks
= dummy_disks(10);
186 disks
[i
].block_size
= Some(4096);
188 // Must fail if /any/ of the disks are 4Kn
189 assert
!(check_disks_4kn_legacy_boot(BootType
::Bios
, &disks
).is_err());
190 // For UEFI, we allow it for every configuration
191 assert
!(check_disks_4kn_legacy_boot(BootType
::Efi
, &disks
).is_ok());
197 let disks
= dummy_disks(10);
199 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &[]).is_err());
200 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &disks
[..1]).is_ok());
201 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid0
, &disks
).is_ok());
203 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &[]).is_err());
204 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
[..1]).is_err());
205 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
[..2]).is_ok());
206 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid1
, &disks
).is_ok());
208 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &[]).is_err());
209 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
[..3]).is_err());
210 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
[..4]).is_ok());
211 assert
!(check_btrfs_raid_config(BtrfsRaidLevel
::Raid10
, &disks
).is_ok());
216 let disks
= dummy_disks(10);
218 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid0
, &[]).is_err());
219 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid0
, &disks
[..1]).is_ok());
220 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid0
, &disks
).is_ok());
222 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid1
, &[]).is_err());
223 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid1
, &disks
[..2]).is_ok());
224 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid1
, &disks
).is_ok());
226 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid10
, &[]).is_err());
227 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid10
, &dummy_disks(4)).is_ok());
228 assert
!(check_zfs_raid_config(ZfsRaidLevel
::Raid10
, &disks
).is_ok());
230 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ
, &[]).is_err());
231 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ
, &disks
[..2]).is_err());
232 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ
, &disks
[..3]).is_ok());
233 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ
, &disks
).is_ok());
235 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ2
, &[]).is_err());
236 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ2
, &disks
[..3]).is_err());
237 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ2
, &disks
[..4]).is_ok());
238 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ2
, &disks
).is_ok());
240 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ3
, &[]).is_err());
241 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ3
, &disks
[..4]).is_err());
242 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ3
, &disks
[..5]).is_ok());
243 assert
!(check_zfs_raid_config(ZfsRaidLevel
::RaidZ3
, &disks
).is_ok());