From c4fabc7c801491019263523df3c9078cca99bb6e Mon Sep 17 00:00:00 2001 From: Nikita Dubrovskii Date: Wed, 2 Jun 2021 14:27:42 +0200 Subject: [PATCH] s390: add support for virtio dasds This is a fix for https://bugzilla.redhat.com/show_bug.cgi?id=1960485 Signed-off-by: Nikita Dubrovskii --- src/blockdev.rs | 30 ++++++++++++++++++++++++++++-- src/cmdline.rs | 2 +- src/install.rs | 6 +++--- src/s390x/dasd.rs | 15 +++++++++++---- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/blockdev.rs b/src/blockdev.rs index 90c6bee..df8e10a 100644 --- a/src/blockdev.rs +++ b/src/blockdev.rs @@ -970,10 +970,36 @@ pub fn detect_formatted_sector_size(buf: &[u8]) -> Option { } /// Checks if underlying device is IBM DASD disk -pub fn is_dasd(device: &str) -> Result { +pub fn is_dasd(device: &str, fd: Option<&mut File>) -> Result { let target = canonicalize(device).with_context(|| format!("getting absolute path to {}", device))?; - Ok(target.to_string_lossy().starts_with("/dev/dasd")) + if target.to_string_lossy().starts_with("/dev/dasd") { + return Ok(true); + } + let read_magic = |device: &str, disk: &mut File| -> Result<[u8; 4]> { + let offset = disk + .seek(SeekFrom::Current(0)) + .with_context(|| format!("saving offset {}", device))?; + disk.seek(SeekFrom::Start(8194)) + .with_context(|| format!("seeking {}", device))?; + let mut lbl = [0u8; 4]; + disk.read_exact(&mut lbl) + .with_context(|| format!("reading label {}", device))?; + disk.seek(SeekFrom::Start(offset)) + .with_context(|| format!("restoring offset {}", device))?; + Ok(lbl) + }; + if target.to_string_lossy().starts_with("/dev/vd") { + let cdl_magic = [0xd3, 0xf1, 0xe5, 0xd6]; + let lbl = if let Some(t) = fd { + read_magic(device, t)? + } else { + let mut disk = File::open(device).with_context(|| format!("opening {}", device))?; + read_magic(device, &mut disk)? + }; + return Ok(cdl_magic == lbl); + } + Ok(false) } // create unsafe ioctl wrappers diff --git a/src/cmdline.rs b/src/cmdline.rs index db3d1d0..53b8179 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -853,7 +853,7 @@ fn parse_install(matches: &ArgMatches) -> Result { // it changes to the recommended 4096 // https://bugzilla.redhat.com/show_bug.cgi?id=1905159 #[allow(clippy::match_bool, clippy::match_single_binding)] - let sector_size = match is_dasd(&device) + let sector_size = match is_dasd(&device, None) .with_context(|| format!("checking whether {} is an IBM DASD disk", device))? { #[cfg(target_arch = "s390x")] diff --git a/src/install.rs b/src/install.rs index baa3880..20d1f41 100644 --- a/src/install.rs +++ b/src/install.rs @@ -47,7 +47,7 @@ pub fn install(config: &InstallConfig) -> Result<()> { #[cfg(target_arch = "s390x")] { - if is_dasd(&config.device)? { + if is_dasd(&config.device, None)? { if !config.save_partitions.is_empty() { // The user requested partition saving, but SavedPartitions // doesn't understand DASD VTOCs and won't find any partitions @@ -156,7 +156,7 @@ fn write_disk( // copy the image #[allow(clippy::match_bool, clippy::match_single_binding)] - let image_copy = match is_dasd(&config.device)? { + let image_copy = match is_dasd(&config.device, Some(dest))? { #[cfg(target_arch = "s390x")] true => s390x::image_copy_s390x, _ => image_copy_default, @@ -527,7 +527,7 @@ fn reset_partition_table( ) -> Result<()> { eprintln!("Resetting partition table"); - if is_dasd(&config.device)? { + if is_dasd(&config.device, Some(dest))? { // Don't write out a GPT, since the backup GPT may overwrite // something we're not allowed to touch. Just clear the first MiB // of disk. diff --git a/src/s390x/dasd.rs b/src/s390x/dasd.rs index 7145071..b7dea78 100644 --- a/src/s390x/dasd.rs +++ b/src/s390x/dasd.rs @@ -35,13 +35,15 @@ pub(crate) struct Range { pub length: u64, } -/// There are 2 types of DASD devices: +/// There are 3 types of DASD devices: /// - ECKD (Extended Count Key Data) - is regular DASD of type 3390 /// - FBA (Fixed Block Access) - is used for emulated device that represents a real SCSI device +/// - Virt - ECKD on LPAR/zKVM as virtio-device /// Only ECKD disks require `dasdfmt, fdasd` linux tools to be configured. enum DasdType { Eckd, Fba, + Virt, } fn get_dasd_type>(device: P) -> Result { @@ -53,6 +55,9 @@ fn get_dasd_type>(device: P) -> Result { .with_context(|| format!("getting name of {}", device.display()))? .to_string_lossy() .to_string(); + if device.starts_with("vd") { + return Ok(DasdType::Virt); + } let devtype_path = format!("/sys/class/block/{}/device/devtype", device); let devtype_str = std::fs::read_to_string(&devtype_path) .with_context(|| format!("reading {}", devtype_path))?; @@ -66,7 +71,7 @@ fn get_dasd_type>(device: P) -> Result { pub fn prepare_dasd(dasd: &str) -> Result<()> { match get_dasd_type(dasd)? { DasdType::Eckd => eckd_prepare(dasd), - DasdType::Fba => Ok(()), + DasdType::Fba | DasdType::Virt => Ok(()), } } @@ -75,7 +80,7 @@ pub fn prepare_dasd(dasd: &str) -> Result<()> { pub fn dasd_try_get_sector_size(dasd: &str) -> Result> { match get_dasd_type(dasd)? { DasdType::Eckd => eckd_try_get_sector_size(dasd), - DasdType::Fba => Ok(None), + DasdType::Fba | DasdType::Virt => Ok(None), } } @@ -87,8 +92,10 @@ pub fn image_copy_s390x( _saved: Option<&SavedPartitions>, ) -> Result<()> { let ranges = match get_dasd_type(dest_path)? { - DasdType::Eckd => eckd_make_partitions(&dest_path.to_string_lossy(), dest_file, first_mb)?, DasdType::Fba => fba_make_partitions(&dest_path.to_string_lossy(), dest_file, first_mb)?, + DasdType::Eckd | DasdType::Virt => { + eckd_make_partitions(&dest_path.to_string_lossy(), dest_file, first_mb)? + } }; // copy each partition -- 2.31.1