Skip to content

Commit

Permalink
🚑 Fix for devices with a non-512-byte sector size
Browse files Browse the repository at this point in the history
  • Loading branch information
mmstick committed Apr 23, 2019
1 parent 3f51803 commit de78b39
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 58 deletions.
14 changes: 0 additions & 14 deletions crates/disk-ops/src/mklabel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::path::Path;

/// Writes a new partition table to the disk, clobbering it in the process.
pub fn mklabel<P: AsRef<Path>>(device_path: P, kind: PartitionTable) -> io::Result<()> {
let _ = zero(&device_path, 2047, 1);
let _ = wipefs(&device_path);

info!(
Expand Down Expand Up @@ -41,16 +40,3 @@ pub fn mklabel<P: AsRef<Path>>(device_path: P, kind: PartitionTable) -> io::Resu

Ok(())
}

/// Write sectors of zeroes to a block device
pub fn zero<P: AsRef<Path>>(device: P, sectors: u64, offset: u64) -> io::Result<()> {
let zeroed_sector = [0; 512];
File::open(device.as_ref())
.and_then(|mut file| {
if offset != 0 {
file.seek(SeekFrom::Start(512 * offset)).map(|_| ())?;
}

(0..sectors).map(|_| file.write(&zeroed_sector).map(|_| ())).collect()
})
}
10 changes: 6 additions & 4 deletions crates/disk-ops/src/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ pub struct PartitionChange {
pub start: u64,
/// The end sector that the partition will have.
pub end: u64,
/// Size of this partition's sectors.
pub sector_size: u64,
/// The file system that is currently on the partition.
pub filesystem: Option<FileSystem>,
/// A diff of flags which should be set on the partition.
Expand Down Expand Up @@ -301,8 +303,8 @@ where
// Each file system uses different units for specifying the size, and these
// units are sometimes written in non-standard and conflicting ways.
let size = match unit {
ResizeUnit::AbsoluteBytes => format!("{}", resize.absolute_sectors() * 512),
ResizeUnit::AbsoluteKibis => format!("{}ki", resize.absolute_sectors() / 2),
ResizeUnit::AbsoluteBytes => format!("{}", resize.absolute_sectors() * change.sector_size),
ResizeUnit::AbsoluteKibis => format!("{}ki", (resize.absolute_sectors() / 2) * (change.sector_size / 512)),
ResizeUnit::AbsoluteSectorsWithUnit => format!("{}s", resize.absolute_sectors()),
ResizeUnit::AbsoluteMebibyte => format!("{}M", resize.as_absolute_mebibyte()),
ResizeUnit::AbsoluteMegabyte => format!("{}M", resize.as_absolute_megabyte()),
Expand Down Expand Up @@ -345,7 +347,7 @@ where
let abs_sectors = resize.absolute_sectors();
resize.old.resize_to(abs_sectors); // TODO: NLL

move_partition(&change.device_path, resize.offset(), 512)
move_partition(&change.device_path, resize.offset(), change.sector_size)
.map_err(|why| io::Error::new(
why.kind(),
format!("failed to move partition at {}: {}", change.path.display(), why)
Expand Down Expand Up @@ -383,7 +385,7 @@ where
let abs_sectors = resize.absolute_sectors();
resize.old.resize_to(abs_sectors); // TODO: NLL

move_partition(&change.device_path, resize.offset(), 512)
move_partition(&change.device_path, resize.offset(), change.sector_size)
.map_err(|why| io::Error::new(
why.kind(),
format!("failed to move partition at {}: {}", change.path.display(), why)
Expand Down
16 changes: 11 additions & 5 deletions crates/disks/src/config/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub struct Disk {
pub mount_point: Option<PathBuf>,
/// The size of the disk in sectors.
pub size: u64,
/// The size of each sector
pub sector_size: u64,
/// The type of the device, such as SCSI.
pub device_type: String,
/// The partition table may be either **MSDOS** or **GPT**.
Expand All @@ -119,7 +121,7 @@ impl BlockDeviceExt for Disk {
}

impl SectorExt for Disk {
fn get_sector_size(&self) -> u64 { 512 }
fn get_sector_size(&self) -> u64 { self.sector_size }

fn get_sectors(&self) -> u64 { self.size }
}
Expand Down Expand Up @@ -173,6 +175,7 @@ impl Disk {
};

let size = device.length();
let sector_size = device.sector_size();
let device_type = format!("{:?}", device.type_());
let read_only = device.read_only();

Expand All @@ -197,6 +200,7 @@ impl Disk {
file_system: None,
serial,
size,
sector_size,
device_type,
read_only,
table_type,
Expand Down Expand Up @@ -436,6 +440,7 @@ impl Disk {
/// will be located at the provided `end` value, and checks whether or not that this will
/// be possible to do.
pub fn resize_partition(&mut self, partition: i32, mut end: u64) -> Result<u64, DiskError> {
let sector_size = self.get_sector_size();
let (backup, num, start);
{
let partition = self.get_partition_mut(partition)
Expand All @@ -450,7 +455,7 @@ impl Disk {

{
let length = end - partition.start_sector;
end -= length % (2 * 1024);
end -= length % (crate::sectors_normalize(2 * 1024, sector_size));
}

info!(
Expand All @@ -459,10 +464,10 @@ impl Disk {
end - partition.start_sector
);

assert_eq!(0, (end - partition.start_sector) % (2 * 1024));
assert_eq!(0, (end - partition.start_sector) % (crate::sectors_normalize(2 * 1024, sector_size)));

if end < partition.start_sector
|| end - partition.start_sector <= (10 * 1024 * 1024) / 512
|| end - partition.start_sector <= crate::sectors_normalize(10 * 1024 * 1024, sector_size) / sector_size
{
return Err(DiskError::new_partition_error(
partition.device_path.clone(),
Expand Down Expand Up @@ -540,7 +545,7 @@ impl Disk {
self.path().display(),
fs,
);
let sector_size = 512;
let sector_size = self.get_sector_size();
self.get_partition_mut(partition)
.ok_or(DiskError::PartitionNotFound { partition })
.and_then(|partition| {
Expand Down Expand Up @@ -750,6 +755,7 @@ impl Disk {
kind: new.part_type,
start: new.start_sector,
end: new.end_sector,
sector_size: self.get_sector_size(),
filesystem: source.filesystem,
flags: flags_diff(
&source.flags,
Expand Down
4 changes: 3 additions & 1 deletion crates/disks/src/config/disk_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub trait DiskExt: BlockDeviceExt + SectorExt + PartitionTableExt {
///
/// An error can occur if the partition will not fit onto the disk.
fn add_partition(&mut self, mut builder: PartitionBuilder) -> Result<(), DiskError> {
let sector_size = self.get_sector_size();

// Ensure that the values aren't already contained within an existing partition.
if !Self::LOGICAL && builder.part_type != PartitionType::Extended {
info!(
Expand Down Expand Up @@ -136,7 +138,7 @@ pub trait DiskExt: BlockDeviceExt + SectorExt + PartitionTableExt {
).partition_type(PartitionType::Extended);

self.push_partition(part.build());
builder.start_sector += 1_024_000 / 512 + 1;
builder.start_sector += 1_024_000 / sector_size + 1;
}

let fs = builder.filesystem;
Expand Down
17 changes: 11 additions & 6 deletions crates/disks/src/config/disks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ impl Disks {
partition: &mut PartitionInfo,
path: &Path,
enc: &LvmEncryption,
sector_size: u64,
) -> Result<LogicalDevice, DecryptionError> {
// Attempt to decrypt the device.
cryptsetup_open(path, &enc).map_err(|why| DecryptionError::Open {
Expand All @@ -480,7 +481,7 @@ impl Disks {
Some(Some(vg)) => {
// Set values in the device's partition.
partition.volume_group = Some((vg.clone(), Some(enc.clone())));
let mut luks = LogicalDevice::new(vg, Some(enc.clone()), partition.get_sectors(), 512, true);
let mut luks = LogicalDevice::new(vg, Some(enc.clone()), partition.get_sectors(), sector_size, true);
info!("settings luks_parent to {:?}", path);
luks.set_luks_parent(path.to_path_buf());

Expand All @@ -494,7 +495,7 @@ impl Disks {
pv,
Some(enc.clone()),
partition.get_sectors(),
512,
sector_size,
true
);

Expand All @@ -516,16 +517,18 @@ impl Disks {

// Attempt to find the device in the configuration.
for device in &mut self.physical {
let sector_size = device.get_sector_size();

// TODO: NLL
if let Some(partition) = device.get_file_system_mut() {
if partition.get_device_path() == path {
decrypt(partition, path, &enc)?;
decrypt(partition, path, &enc, sector_size)?;
}
}

for partition in device.file_system.as_mut().into_iter().chain(device.partitions.iter_mut()) {
if partition.get_device_path() == path {
new_device = Some(decrypt(partition, path, &enc)?);
new_device = Some(decrypt(partition, path, &enc, sector_size)?);
break
}
}
Expand Down Expand Up @@ -955,6 +958,8 @@ impl Disks {
}
};

let sector_size = device.get_sector_size();

if is_efi {
// Check if the EFI partition is on a GPT disk.
if device.get_partition_table() != Some(PartitionTable::Gpt) {
Expand Down Expand Up @@ -988,9 +993,9 @@ impl Disks {
}

// 256 MiB should be the minimal size of the ESP partition.
const REQUIRED_SECTORS: u64 = 524_288;
let required_sectors = crate::sectors_normalize(524_288, sector_size);

if boot.get_sectors() < REQUIRED_SECTORS {
if boot.get_sectors() < required_sectors {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"the ESP partition must be at least 256 MiB in size"
Expand Down
5 changes: 5 additions & 0 deletions crates/disks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ pub use bootloader::{Bootloader, FORCE_BOOTLOADER};
pub use self::config::*;
pub use self::error::{DecryptionError, DiskError, PartitionError, PartitionSizeError};
pub use libparted::PartitionFlag;

/// Normalize 512-byte sector counts to the given sector size
fn sectors_normalize(base_count: u64, sector_size: u64) -> u64 {
base_count / (sector_size / 512)
}
5 changes: 5 additions & 0 deletions ffi/distinst.vapi
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ namespace Distinst {
public int get_partition ();
public uint64 get_sectors_free ();
public uint64 get_sectors_total ();
public uint64 get_sector_size ();
}

/**
Expand Down Expand Up @@ -182,6 +183,10 @@ namespace Distinst {
* Gets the number of sectors that this option's device contains.
*/
public uint64 get_sectors ();
/**
* Gets the size of sectors on this device
*/
public uint64 get_sector_size ();
}

/**
Expand Down
26 changes: 24 additions & 2 deletions ffi/src/auto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub unsafe extern "C" fn distinst_alongside_option_get_sectors_free(
let option = &*(option as *const AlongsideOption);
match option.method {
AlongsideMethod::Shrink { sectors_free, .. } => sectors_free,
AlongsideMethod::Free(ref region) => region.size()
AlongsideMethod::Free(ref region, _) => region.size()
}
}

Expand All @@ -131,10 +131,20 @@ pub unsafe extern "C" fn distinst_alongside_option_get_sectors_total(
let option = &*(option as *const AlongsideOption);
match option.method {
AlongsideMethod::Shrink { sectors_total, .. } => sectors_total,
AlongsideMethod::Free(ref region) => region.size()
AlongsideMethod::Free(ref region, _) => region.size()
}
}

#[no_mangle]
pub unsafe extern "C" fn distinst_alongside_option_get_sector_size(
option: *const DistinstAlongsideOption,
) -> libc::uint64_t {
let option = &*(option as *const AlongsideOption);
match option.method {
AlongsideMethod::Shrink { sector_size, .. } => sector_size,
AlongsideMethod::Free(_, size) => size
}
}

#[repr(C)]
pub struct DistinstRefreshOption;
Expand Down Expand Up @@ -284,6 +294,18 @@ pub unsafe extern "C" fn distinst_erase_option_get_sectors(
option.sectors
}

#[no_mangle]
pub unsafe extern "C" fn distinst_erase_option_get_sector_size(
option: *const DistinstEraseOption,
) -> libc::uint64_t {
if null_check(option).is_err() {
return 0;
}

let option = &*(option as *const EraseOption);
option.sector_size
}

#[no_mangle]
pub unsafe extern "C" fn distinst_erase_option_is_rotational(
option: *const DistinstEraseOption,
Expand Down
13 changes: 7 additions & 6 deletions src/auto/options/alongside_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ pub enum AlongsideMethod {
partition: i32,
sectors_total: u64,
sectors_free: u64,
sector_size: u64,
path: PathBuf,
},
Free(Region)
Free(Region, u64)
}

#[derive(Debug)]
Expand All @@ -37,24 +38,24 @@ impl fmt::Display for AlongsideOption {
let device = self.device.display();

match self.method {
AlongsideMethod::Shrink { sectors_total, sectors_free, ref path, .. } => {
AlongsideMethod::Shrink { sectors_total, sectors_free, sector_size, ref path, .. } => {
write!(
f,
"alongside {:?} ({}) by shrinking {}: {} of {} MiB free",
os,
device,
path.display(),
sectors_free / 2048,
sectors_total / 2048
sectors_free / 2048 * (sector_size / 512),
sectors_total / 2048 * (sector_size / 512)
)
},
AlongsideMethod::Free(ref region) => {
AlongsideMethod::Free(ref region, ref sector_size) => {
write!(
f,
"alongside {:?} ({}) using free space: {} MiB free",
os,
device,
region.size() / 2048,
region.size() / 2048 * (*sector_size / 512),
)
}
}
Expand Down
Loading

0 comments on commit de78b39

Please sign in to comment.