From e747de93aeedcf5bd4bfd6878d237de05f12c86e Mon Sep 17 00:00:00 2001 From: mulhern Date: Tue, 28 Nov 2023 14:49:15 -0500 Subject: [PATCH] Check the mkfs.xfs version Signed-off-by: mulhern --- src/engine/strat_engine/cmd.rs | 73 ++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/src/engine/strat_engine/cmd.rs b/src/engine/strat_engine/cmd.rs index 112f6ebced7..98b605d3239 100644 --- a/src/engine/strat_engine/cmd.rs +++ b/src/engine/strat_engine/cmd.rs @@ -232,9 +232,74 @@ fn get_clevis_executable(name: &str) -> StratisResult { } } +// Return the mkfs.xfs version reported by the "-V" option as a string. +fn get_mkfs_xfs_version() -> StratisResult { + let mut command = Command::new(get_executable(MKFS_XFS).as_os_str()) + .arg("-V") + .stdout(Stdio::piped()) + .spawn()?; + command.wait()?; + + let mut output = String::new(); + let is_ok = command.wait()?.code() == Some(0); + command + .stdout + .ok_or_else(|| { + StratisError::Msg("Could not read string value from xfs.mkfs output".to_string()) + })? + .read_to_string(&mut output)?; + + if is_ok { + output + .trim() + .strip_prefix("mkfs.xfs version ") + .ok_or_else(|| { + StratisError::Msg("Could not parse version string from mkfs.xfs output".to_string()) + }) + .map(|v| v.to_string()) + } else { + Err(StratisError::Msg( + "\"mkfs.xfs -V\" returned an error".to_string(), + )) + } +} + /// Create a filesystem on devnode. If uuid specified, set the UUID of the /// filesystem on creation. pub fn create_fs(devnode: &Path, uuid: Option) -> StratisResult<()> { + // If the version can not be obtained, which is unlikely, assume that the + // version of mkfs.xfs is new enough to use the nrext64 option. This will + // become more and more true with time. If the version is not high enough, + // this will be obvious when the command-line invocation fails. + // The check only verifies that the major number is greater than 5, because + // before that time, the larger extent counter size was not used by default, + // so, for earlier versions, it is unnecessary to turn it off explicitly. + let use_nrext64_option = match get_mkfs_xfs_version().and_then(|v| { + v.split('.') + .next() + .ok_or_else(|| { + StratisError::Msg( + "Unable to parse major version number from version string".to_string(), + ) + }) + .and_then(|n| { + n.parse::() + .map_err(|_| { + StratisError::Msg( + "Unable to parse major version number from major version string" + .to_string(), + ) + }) + .map(|r| r > 5u64) + }) + }) { + Ok(val) => val, + Err(err) => { + warn!("Unable to read version of mkfs.xfs: {err}; guessing that mkfs.xfs version is high enough to support nrext64 option"); + true + } + }; + let mut command = Command::new(get_executable(MKFS_XFS).as_os_str()); command.arg("-f"); command.arg("-q"); @@ -248,10 +313,12 @@ pub fn create_fs(devnode: &Path, uuid: Option) -> StratisResult<()> // Use smaller size extent counters. Note that the size of the extent // counters can be increased using an xfs_repair command, although this can // be a costly operation. If a filesystem is created with the larger size - // extent counters, which is the default for mkfs.xfs >= 6.5.0, then it + // extent counters, which is the default for mkfs.xfs >= 6.0.0, then it // will be unmountable on kernels which do not support the larger size. - command.arg("-i"); - command.arg("nrext64=0"); + if use_nrext64_option { + command.arg("-i"); + command.arg("nrext64=0"); + } execute_cmd(&mut command) }