From 3d63b901c6217a0ea7f169f5e4c66ca1d4ea1088 Mon Sep 17 00:00:00 2001 From: Tony Asleson <tasleson@redhat.com> Date: Wed, 1 May 2024 15:48:57 -0500 Subject: [PATCH] Handle mount with FS with 1 device If the user passes a single device node during the mount and we have no information for it in the udev db, we read up the super block. When we do this, if the FS only has 1 block device we will simply go ahead and do the mount instead of walking all the block devices and reading up super blocks looking for devices with a matching FS UUID. Signed-off-by: Tony Asleson <tasleson@redhat.com> --- bch_bindgen/src/bcachefs.rs | 4 ++++ src/commands/mount.rs | 34 +++++++++++++++++++++++++--------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/bch_bindgen/src/bcachefs.rs b/bch_bindgen/src/bcachefs.rs index 837b0272..7b8a03df 100644 --- a/bch_bindgen/src/bcachefs.rs +++ b/bch_bindgen/src/bcachefs.rs @@ -59,6 +59,10 @@ impl bch_sb { uuid::Uuid::from_bytes(self.user_uuid.b) } + pub fn number_of_devices(&self) -> u8 { + self.nr_devices + } + /// Get the nonce used to encrypt the superblock pub fn nonce(&self) -> nonce { use byteorder::{LittleEndian, ReadBytesExt}; diff --git a/src/commands/mount.rs b/src/commands/mount.rs index 03215fcd..c6e0a37d 100644 --- a/src/commands/mount.rs +++ b/src/commands/mount.rs @@ -208,7 +208,7 @@ fn get_devices_by_uuid( fn get_uuid_for_dev_node( udev_bcachefs: &HashMap<String, Vec<String>>, device: &std::path::PathBuf, -) -> anyhow::Result<Option<Uuid>> { +) -> anyhow::Result<(Option<Uuid>, Option<(PathBuf, bch_sb_handle)>)> { let canonical = fs::canonicalize(device)?; if !udev_bcachefs.is_empty() { @@ -216,12 +216,14 @@ fn get_uuid_for_dev_node( if udev_bcachefs.contains_key(&dev_node_str) && udev_bcachefs[&dev_node_str].len() == 1 { let uuid_str = udev_bcachefs[&dev_node_str][0].clone(); - return Ok(Some(Uuid::parse_str(&uuid_str)?)); + return Ok((Some(Uuid::parse_str(&uuid_str)?), None)); } } else { - return read_super_silent(&canonical).map_or(Ok(None), |sb| Ok(Some(sb.sb().uuid()))); + return read_super_silent(&canonical).map_or(Ok((None, None)), |sb| { + Ok((Some(sb.sb().uuid()), Some((canonical, sb)))) + }); } - Ok(None) + Ok((None, None)) } /// Mount a bcachefs filesystem by its UUID. @@ -289,12 +291,26 @@ fn devs_str_sbs_from_device( udev_info: &HashMap<String, Vec<String>>, device: &std::path::PathBuf, ) -> anyhow::Result<(String, Vec<bch_sb_handle>)> { - let uuid = get_uuid_for_dev_node(udev_info, device)?; + let (uuid, sb_info) = get_uuid_for_dev_node(udev_info, device)?; - if let Some(bcache_fs_uuid) = uuid { - devs_str_sbs_from_uuid(udev_info, bcache_fs_uuid.to_string()) - } else { - Ok((String::new(), Vec::new())) + match (uuid, sb_info) { + (Some(uuid), Some((path, sb))) => { + // If we have a super block, it implies we aren't using udev db. If we only need + // 1 device to mount, we'll simply return it as we're done, else we'll use the uuid + // to walk through all the block devices. + debug!( + "number of devices in this FS = {}", + sb.sb().number_of_devices() + ); + if sb.sb().number_of_devices() == 1 { + let dev = path.into_os_string().into_string().unwrap(); + Ok((dev, vec![sb])) + } else { + devs_str_sbs_from_uuid(udev_info, uuid.to_string()) + } + } + (Some(uuid), None) => devs_str_sbs_from_uuid(udev_info, uuid.to_string()), + _ => Ok((String::new(), Vec::new())), } }