summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Asleson <tasleson@redhat.com>2024-02-26 16:07:54 -0600
committerKent Overstreet <kent.overstreet@linux.dev>2024-03-20 17:02:35 -0400
commit89b322abb3450bd689ed50d7f55178887941ddfe (patch)
treecb2137c55ff97c66d3da58faf25851a381c06514
parentc28af3c0ccdc62eb7b92e78b0aaebde394e34cb1 (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.rs48
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 {