From 39bd8cedaccde54781fc107d2fb61c994a3701c4 Mon Sep 17 00:00:00 2001
From: pigeonmoelleux <pigeonmoelleux@crans.org>
Date: Sat, 20 May 2023 22:18:24 +0200
Subject: [PATCH] fix: some devices could be found several times

---
 src/fs/ext2/inode.rs         | 22 +++++++++++-----------
 src/kernel/device/ata.rs     |  4 ++++
 src/kernel/device/mod.rs     | 26 +++++++++++++++++++++++---
 src/kernel/device/storage.rs |  8 ++++++++
 4 files changed, 46 insertions(+), 14 deletions(-)

diff --git a/src/fs/ext2/inode.rs b/src/fs/ext2/inode.rs
index 4673a65..073d348 100644
--- a/src/fs/ext2/inode.rs
+++ b/src/fs/ext2/inode.rs
@@ -182,36 +182,36 @@ bitflags! {
     /// Inode Flags
     pub struct Flags: u32 {
         /// Secure deletion (not used)
-        const SECURE_DELETION                       =   0x00000001;
+        const SECURE_DELETION                       =   0x0000_0001;
 
         /// Keep a copy of data when deleted (not used)
-        const DELETION_KEEP_DATA_COPY               =   0x00000002;
+        const DELETION_KEEP_DATA_COPY               =   0x0000_0002;
 
         /// File compression (not used)
-        const FILE_COMPRESSION                      =   0x00000004;
+        const FILE_COMPRESSION                      =   0x0000_0004;
 
         /// Synchronous updates—new data is written immediately to disk
-        const SYNCHRONOUS_UPDATES                   =   0x00000008;
+        const SYNCHRONOUS_UPDATES                   =   0x0000_0008;
 
         /// Immutable file (content cannot be changed)
-        const IMMUTABLE_FILE                        =   0x00000010;
+        const IMMUTABLE_FILE                        =   0x0000_0010;
 
         /// Append only
-        const APPEND_ONLY                           =   0x00000020;
+        const APPEND_ONLY                           =   0x0000_0020;
 
         /// File is not included in `dump` command
-        const DUMP_EXCLUDED                         =   0x00000040;
+        const DUMP_EXCLUDED                         =   0x0000_0040;
 
         /// Last accessed time should not updated
-        const LAST_ACCESSED_TIME_UPDATE_DISABLE     =   0x00000080;
+        const LAST_ACCESSED_TIME_UPDATE_DISABLE     =   0x0000_0080;
 
         /// Hash indexed directory
-        const HASHED_INDEXED_DIR                    =   0x00010000;
+        const HASHED_INDEXED_DIR                    =   0x0001_0000;
 
         /// AFS directory
-        const AFS_DIR                               =   0x00020000;
+        const AFS_DIR                               =   0x0002_0000;
 
         /// Journal file data
-        const JOURNAL_FILE_DATA                     =   0x000400000;
+        const JOURNAL_FILE_DATA                     =   0x0004_0000;
     }
 }
diff --git a/src/kernel/device/ata.rs b/src/kernel/device/ata.rs
index 9ed8312..1088fc8 100644
--- a/src/kernel/device/ata.rs
+++ b/src/kernel/device/ata.rs
@@ -1176,6 +1176,10 @@ impl Device for Drive {
             self.identify_data.user_addressable_sectors as usize
         }
     }
+
+    fn uuid(&self) -> [u8; 20] {
+        self.identify_data.serial_number
+    }
 }
 
 impl Drive {
diff --git a/src/kernel/device/mod.rs b/src/kernel/device/mod.rs
index b5238fd..082fb9e 100644
--- a/src/kernel/device/mod.rs
+++ b/src/kernel/device/mod.rs
@@ -1,13 +1,15 @@
 //! Device interface
 
+use alloc::collections::BTreeMap;
 use alloc::sync::Arc;
 use alloc::vec::Vec;
 
 use conquer_once::spin::OnceCell;
-use log::info;
+use log::{info, warn};
 use spin::Mutex;
 
-use crate::kernel::device::ata::IdeController;
+use self::ata::IdeController;
+use self::storage::Uuid;
 
 #[allow(clippy::same_name_method)]
 mod ata;
@@ -26,13 +28,31 @@ pub fn init() {
     info!("{} devices found during PCI scan", devices.len());
 
     let storage_controllers = STORAGE_CONTROLLERS.get_or_init(|| {
+        let mut controllers = BTreeMap::<Vec<Uuid>, Arc<Mutex<dyn storage::Controller + Send>>>::new();
+
+        // To ensure each storage controller is only found once
         devices
             .values()
             .flatten()
             .filter_map(|device| {
                 Some(Arc::new(Mutex::new(IdeController::new(device)?)) as Arc<Mutex<dyn storage::Controller + Send>>)
             })
-            .collect::<Vec<Arc<Mutex<dyn storage::Controller + Send>>>>()
+            .for_each(|controller| {
+                let uuids = controller.lock().devices().iter().map(|device| device.lock().uuid()).collect();
+                if let Some(controller) = controllers.insert(uuids, controller) {
+                    warn!(
+                        "The storage device controller {:?} has been found several times",
+                        controller
+                            .lock()
+                            .devices()
+                            .iter()
+                            .map(|device| device.lock().uuid())
+                            .collect::<Vec<Uuid>>()
+                    );
+                }
+            });
+
+        controllers.into_values().collect()
     });
 
     info!(
diff --git a/src/kernel/device/storage.rs b/src/kernel/device/storage.rs
index 4f138a4..95029ed 100644
--- a/src/kernel/device/storage.rs
+++ b/src/kernel/device/storage.rs
@@ -7,10 +7,18 @@ use spin::Mutex;
 
 use super::block::Manipulation;
 
+/// Type alias representing a device UUID
+pub type Uuid = [u8; 20];
+
 /// Represents storage devices such as hard drive, SSDs, etc.
 pub trait Device: Manipulation {
     /// Returns the size of the device in blocks
     fn size_in_blocks(&self) -> usize;
+
+    /// Returns a unique identifier for the device
+    ///
+    /// This allows to be sure a same device will not be found several times.
+    fn uuid(&self) -> Uuid;
 }
 
 /// Represents a storage controller
-- 
GitLab