From c4f3afa84ef231b52c620fa016247e9c49260125 Mon Sep 17 00:00:00 2001 From: Tony Asleson 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 --- bch_bindgen/src/bcachefs.rs | 4 ++++ src/commands/mount.rs | 37 +++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/bch_bindgen/src/bcachefs.rs b/bch_bindgen/src/bcachefs.rs index 837b0272b..7b8a03df7 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 03215fcda..5eb9aa58f 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>, device: &std::path::PathBuf, -) -> anyhow::Result> { +) -> anyhow::Result<(Option, 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,27 @@ fn devs_str_sbs_from_device( udev_info: &HashMap>, device: &std::path::PathBuf, ) -> anyhow::Result<(String, Vec)> { - let uuid = 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())) + let (uuid, sb_info) = get_uuid_for_dev_node(udev_info, device)?; + + 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())) + } } }