diff options
author | Tony Asleson <tasleson@redhat.com> | 2024-02-26 16:07:54 -0600 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-03-20 17:02:35 -0400 |
commit | 89b322abb3450bd689ed50d7f55178887941ddfe (patch) | |
tree | cb2137c55ff97c66d3da58faf25851a381c06514 | |
parent | c28af3c0ccdc62eb7b92e78b0aaebde394e34cb1 (diff) |
mount: Handle multi-device with 1 device node
Instead of requiring the user to supply all the device nodes for a
multi-device FS, allow them to specifiy 1 of them. We then fetch
the UUID for the FS and then find all the disks on the system that
match this UUID.
This allows me to bring up a bcachefs FS in /etc/fstab by using a
UUID. This works because it appears the mount command looks up
the UUID, finds an entry in /dev/disk/by-uuid and then passes that
found device node to mount.bcachefs which fails with
`insufficient_devices_to_start` as bcachefs is expecting a list of
devices with a ":" between them. This behavior is preserved if a
user specifies a list of all the needed device nodes to bring up
the FS.
Signed-off-by: Tony Asleson <tasleson@redhat.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | src/commands/cmd_mount.rs | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/src/commands/cmd_mount.rs b/src/commands/cmd_mount.rs index 4f9cc9fa..53a20217 100644 --- a/src/commands/cmd_mount.rs +++ b/src/commands/cmd_mount.rs @@ -123,6 +123,24 @@ fn get_devices_by_uuid(uuid: Uuid) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle Ok(devs) } +fn get_uuid_for_dev_node(device: &std::path::PathBuf) -> anyhow::Result<Option<Uuid>> { + let mut udev = udev::Enumerator::new()?; + udev.match_subsystem("block")?; + + for dev in udev.scan_devices()?.into_iter() { + if let Some(devnode) = dev.devnode() { + if devnode == device { + let devnode_owned = devnode.to_owned(); + let sb_result = read_super_silent(&devnode_owned); + if let Ok(sb) = sb_result { + return Ok(Some(sb.sb().uuid())); + } + } + } + } + Ok(None) +} + /// Mount a bcachefs filesystem by its UUID. #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -183,6 +201,16 @@ fn devs_str_sbs_from_uuid(uuid: String) -> anyhow::Result<(String, Vec<bch_sb_ha } +fn devs_str_sbs_from_device(device: &std::path::PathBuf) -> anyhow::Result<(String, Vec<bch_sb_handle>)> { + let uuid = get_uuid_for_dev_node(device)?; + + if let Some(bcache_fs_uuid) = uuid { + devs_str_sbs_from_uuid(bcache_fs_uuid.to_string()) + } else { + Ok((String::new(), Vec::new())) + } +} + fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> { let (devices, block_devices_to_mount) = if opt.dev.starts_with("UUID=") { let uuid = opt.dev.replacen("UUID=", "", 1); @@ -191,14 +219,22 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> { let uuid = opt.dev.replacen("OLD_BLKID_UUID=", "", 1); devs_str_sbs_from_uuid(uuid)? } else { - let mut block_devices_to_mount = Vec::new(); + // If the device string contains ":" we will assume the user knows the entire list. + // If they supply a single device it could be either the FS only has 1 device or it's + // only 1 of a number of devices which are part of the FS. This appears to be the case + // when we get called during fstab mount processing and the fstab specifies a UUID. + if opt.dev.contains(":") { + let mut block_devices_to_mount = Vec::new(); + + for dev in opt.dev.split(':') { + let dev = PathBuf::from(dev); + block_devices_to_mount.push(read_super_silent(&dev)?); + } - for dev in opt.dev.split(':') { - let dev = PathBuf::from(dev); - block_devices_to_mount.push(read_super_silent(&dev)?); + (opt.dev, block_devices_to_mount) + } else { + devs_str_sbs_from_device(&PathBuf::from(opt.dev))? } - - (opt.dev, block_devices_to_mount) }; if block_devices_to_mount.len() == 0 { |