summaryrefslogtreecommitdiffstats
path: root/rsnix/src/fat.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsnix/src/fat.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/rsnix/src/fat.rs b/rsnix/src/fat.rs
index 335a160..ef75aa9 100644
--- a/rsnix/src/fat.rs
+++ b/rsnix/src/fat.rs
@@ -36,6 +36,7 @@ pub struct Entry {
36struct Volume { 36struct Volume {
37 disk: usize, // AHCI disk index this volume was mounted from 37 disk: usize, // AHCI disk index this volume was mounted from
38 uid: String, // unique mount name: "LABEL-XXXXXXXX" 38 uid: String, // unique mount name: "LABEL-XXXXXXXX"
39 mounted: bool, // still backed by a present disk (false = tombstoned)
39 sectors_per_cluster: u8, 40 sectors_per_cluster: u8,
40 reserved: u16, 41 reserved: u16,
41 fat_size: u32, // sectors per FAT 42 fat_size: u32, // sectors per FAT
@@ -65,6 +66,69 @@ pub fn volume_count() -> usize {
65 vols().len() 66 vols().len()
66} 67}
67 68
69/// Is volume `vol` currently mounted (its disk present and FAT cached)?
70pub fn is_mounted(vol: usize) -> bool {
71 vols().get(vol).map(|v| v.mounted).unwrap_or(false)
72}
73
74/// Re-scan after a disk arrival/removal: unmount volumes whose disk left,
75/// mount every disk that has no mounted volume (which also re-tries
76/// mounts that failed at boot). Volume slots are tombstoned, never
77/// removed, so VFS disk handles keep their indices. Returns
78/// (mounted, unmounted).
79pub fn rescan() -> (usize, usize) {
80 let disks = crate::ahci::disk_count();
81 let mut mounted = 0usize;
82 let mut unmounted = 0usize;
83 // Unmount volumes whose disk is gone.
84 for i in 0..vols().len() {
85 if vols()[i].mounted && !crate::ahci::is_up(vols()[i].disk) {
86 vols()[i].mounted = false;
87 crate::serial_println!("fat: unmounted \"{}\"", vols()[i].uid);
88 unmounted += 1;
89 }
90 }
91 // Mount every disk that has no mounted volume.
92 for d in 0..disks {
93 if !crate::ahci::select(d) {
94 continue;
95 }
96 if vols().iter().any(|v| v.mounted && v.disk == d) {
97 continue;
98 }
99 if let Some(volume) = try_mount(d) {
100 let uid = volume.uid.clone();
101 let vol = match vols().iter().position(|v| !v.mounted && v.disk == d) {
102 // Reuse the disk's own tombstoned slot (indices stay stable).
103 Some(slot) => {
104 vols()[slot] = volume;
105 slot
106 }
107 None => {
108 vols().push(volume);
109 vols().len() - 1
110 }
111 };
112 if select_vol(vol).is_ok() {
113 fsinfo_recount();
114 }
115 let count = list_dir(vol, root_cluster(vol))
116 .map(|es| es.len())
117 .unwrap_or(0);
118 crate::serial_println!(
119 "fat: mounted \"{}\" at /disk/{} ({} clusters, {} B/cluster, root: {} entries)",
120 uid,
121 uid,
122 v().cluster_count,
123 cluster_size(),
124 count
125 );
126 mounted += 1;
127 }
128 }
129 (mounted, unmounted)
130}
131
68/// Unique mount name of volume `vol` ("RSDOS-5BD1E55F"). 132/// Unique mount name of volume `vol` ("RSDOS-5BD1E55F").
69pub fn uid(vol: usize) -> &'static str { 133pub fn uid(vol: usize) -> &'static str {
70 vols().get(vol).map(|v| v.uid.as_str()).unwrap_or("") 134 vols().get(vol).map(|v| v.uid.as_str()).unwrap_or("")
@@ -1099,11 +1163,12 @@ fn try_mount(d: usize) -> Option<Volume> {
1099 if label.is_empty() { 1163 if label.is_empty() {
1100 label = String::from("DISK"); 1164 label = String::from("DISK");
1101 } 1165 }
1102 // Deduplicate against already-mounted volumes (e.g. cloned images). 1166 // Deduplicate against already-MOUNTED volumes (e.g. cloned images).
1167 // Tombstoned slots are skipped so a re-plugged disk keeps its name.
1103 let mut uid = alloc::format!("{}-{:08X}", label, serial); 1168 let mut uid = alloc::format!("{}-{:08X}", label, serial);
1104 let mut n = 2u32; 1169 let mut n = 2u32;
1105 loop { 1170 loop {
1106 let taken = vols().iter().any(|v| v.uid == uid); 1171 let taken = vols().iter().any(|v| v.mounted && v.uid == uid);
1107 if !taken { 1172 if !taken {
1108 break; 1173 break;
1109 } 1174 }
@@ -1113,6 +1178,7 @@ fn try_mount(d: usize) -> Option<Volume> {
1113 Some(Volume { 1178 Some(Volume {
1114 disk: d, 1179 disk: d,
1115 uid, 1180 uid,
1181 mounted: true,
1116 sectors_per_cluster: spc, 1182 sectors_per_cluster: spc,
1117 reserved, 1183 reserved,
1118 fat_size, 1184 fat_size,