summaryrefslogtreecommitdiffstats
path: root/rsnix/src/fat.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsnix/src/fat.rs41
1 files changed, 33 insertions, 8 deletions
diff --git a/rsnix/src/fat.rs b/rsnix/src/fat.rs
index b7e0da1..03b9550 100644
--- a/rsnix/src/fat.rs
+++ b/rsnix/src/fat.rs
@@ -62,6 +62,26 @@ fn active_vol() -> &'static mut usize {
62 unsafe { &mut *core::ptr::addr_of_mut!(ACTIVE_VOL) } 62 unsafe { &mut *core::ptr::addr_of_mut!(ACTIVE_VOL) }
63} 63}
64 64
65/// Re-entrant disk lock: serializes filesystem/disk access across tasks.
66/// Multiple terminals may touch the disk concurrently, so every fat/fs
67/// operation that touches the shared volume state, the FAT cache, or the
68/// VFS must hold this. Re-entrant (the preemption-depth counter), so an
69/// `fs` op can call a `fat` op without deadlocking.
70pub(crate) struct DiskGuard;
71
72impl DiskGuard {
73 pub(crate) fn acquire() -> Self {
74 crate::sched::lock();
75 DiskGuard
76 }
77}
78
79impl Drop for DiskGuard {
80 fn drop(&mut self) {
81 crate::sched::unlock();
82 }
83}
84
65pub fn volume_count() -> usize { 85pub fn volume_count() -> usize {
66 vols().len() 86 vols().len()
67} 87}
@@ -89,9 +109,10 @@ pub fn crash_vol() -> Option<usize> {
89 } 109 }
90 for vol in 0..n { 110 for vol in 0..n {
91 if let Some(label) = volume_label(vol) 111 if let Some(label) = volume_label(vol)
92 && label.eq_ignore_ascii_case("CRASHLOG") { 112 && label.eq_ignore_ascii_case("CRASHLOG")
93 return Some(vol); 113 {
94 } 114 return Some(vol);
115 }
95 } 116 }
96 Some(0) 117 Some(0)
97} 118}
@@ -102,6 +123,7 @@ pub fn crash_vol() -> Option<usize> {
102/// removed, so VFS disk handles keep their indices. Returns 123/// removed, so VFS disk handles keep their indices. Returns
103/// (mounted, unmounted). 124/// (mounted, unmounted).
104pub fn rescan() -> (usize, usize) { 125pub fn rescan() -> (usize, usize) {
126 let _lock = DiskGuard::acquire();
105 let disks = crate::ahci::disk_count(); 127 let disks = crate::ahci::disk_count();
106 let mut mounted = 0usize; 128 let mut mounted = 0usize;
107 let mut unmounted = 0usize; 129 let mut unmounted = 0usize;
@@ -256,11 +278,7 @@ fn is_eoc(c: u32) -> bool {
256 278
257fn next_cluster(c: u32) -> Result<u32, ()> { 279fn next_cluster(c: u32) -> Result<u32, ()> {
258 let n = read_fat_entry(c); 280 let n = read_fat_entry(c);
259 if is_eoc(n) { 281 if is_eoc(n) { Err(()) } else { Ok(n) }
260 Err(())
261 } else {
262 Ok(n)
263 }
264} 282}
265 283
266/// Allocate a fresh cluster: mark it EOC in the FAT and zero its data. 284/// Allocate a fresh cluster: mark it EOC in the FAT and zero its data.
@@ -532,6 +550,7 @@ fn scan_dir(dir_cluster: u32) -> Result<Vec<DirItem>, ()> {
532 550
533/// Public listing: no `.` / `..`. 551/// Public listing: no `.` / `..`.
534pub fn list_dir(vol: usize, dir_cluster: u32) -> Result<Vec<Entry>, ()> { 552pub fn list_dir(vol: usize, dir_cluster: u32) -> Result<Vec<Entry>, ()> {
553 let _lock = DiskGuard::acquire();
535 select_vol(vol)?; 554 select_vol(vol)?;
536 Ok(scan_dir(dir_cluster)? 555 Ok(scan_dir(dir_cluster)?
537 .into_iter() 556 .into_iter()
@@ -558,6 +577,7 @@ fn find_item(parent_dir_cluster: u32, name: &str) -> Result<DirItem, ()> {
558 577
559/// Find an entry by name (case-insensitive). 578/// Find an entry by name (case-insensitive).
560pub fn find(vol: usize, parent_dir_cluster: u32, name: &str) -> Result<Entry, ()> { 579pub fn find(vol: usize, parent_dir_cluster: u32, name: &str) -> Result<Entry, ()> {
580 let _lock = DiskGuard::acquire();
561 select_vol(vol)?; 581 select_vol(vol)?;
562 find_item(parent_dir_cluster, name).map(|i| Entry { 582 find_item(parent_dir_cluster, name).map(|i| Entry {
563 name: i.name, 583 name: i.name,
@@ -576,6 +596,7 @@ pub fn read_file(
576 buf: &mut [u8], 596 buf: &mut [u8],
577 pos: u64, 597 pos: u64,
578) -> Result<usize, ()> { 598) -> Result<usize, ()> {
599 let _lock = DiskGuard::acquire();
579 select_vol(vol)?; 600 select_vol(vol)?;
580 if buf.is_empty() { 601 if buf.is_empty() {
581 return Ok(0); 602 return Ok(0);
@@ -622,6 +643,7 @@ pub fn write_file(
622 buf: &[u8], 643 buf: &[u8],
623 pos: u64, 644 pos: u64,
624) -> Result<usize, ()> { 645) -> Result<usize, ()> {
646 let _lock = DiskGuard::acquire();
625 select_vol(vol)?; 647 select_vol(vol)?;
626 if buf.is_empty() { 648 if buf.is_empty() {
627 return Ok(0); 649 return Ok(0);
@@ -685,6 +707,7 @@ pub fn write_file(
685} 707}
686 708
687pub fn set_len(vol: usize, parent_dir_cluster: u32, name: &str, len: u64) -> Result<(), ()> { 709pub fn set_len(vol: usize, parent_dir_cluster: u32, name: &str, len: u64) -> Result<(), ()> {
710 let _lock = DiskGuard::acquire();
688 select_vol(vol)?; 711 select_vol(vol)?;
689 let it = find_item(parent_dir_cluster, name)?; 712 let it = find_item(parent_dir_cluster, name)?;
690 if it.attr & 0x10 != 0 { 713 if it.attr & 0x10 != 0 {
@@ -1009,6 +1032,7 @@ fn add_dir_entry(parent: u32, name: &str, is_dir: bool, cluster: u32) -> Result<
1009} 1032}
1010 1033
1011pub fn create(vol: usize, parent_dir_cluster: u32, name: &str, is_dir: bool) -> Result<(), ()> { 1034pub fn create(vol: usize, parent_dir_cluster: u32, name: &str, is_dir: bool) -> Result<(), ()> {
1035 let _lock = DiskGuard::acquire();
1012 select_vol(vol)?; 1036 select_vol(vol)?;
1013 if find(vol, parent_dir_cluster, name).is_ok() { 1037 if find(vol, parent_dir_cluster, name).is_ok() {
1014 return Err(()); 1038 return Err(());
@@ -1048,6 +1072,7 @@ pub fn create(vol: usize, parent_dir_cluster: u32, name: &str, is_dir: bool) ->
1048} 1072}
1049 1073
1050pub fn remove(vol: usize, parent_dir_cluster: u32, name: &str) -> Result<(), ()> { 1074pub fn remove(vol: usize, parent_dir_cluster: u32, name: &str) -> Result<(), ()> {
1075 let _lock = DiskGuard::acquire();
1051 select_vol(vol)?; 1076 select_vol(vol)?;
1052 let it = find_item(parent_dir_cluster, name)?; 1077 let it = find_item(parent_dir_cluster, name)?;
1053 if it.attr & 0x10 != 0 { 1078 if it.attr & 0x10 != 0 {