summaryrefslogtreecommitdiffstats
path: root/rsnix/src
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src')
-rw-r--r--rsnix/src/fat.rs41
-rw-r--r--rsnix/src/fs.rs13
2 files changed, 44 insertions, 10 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 {
diff --git a/rsnix/src/fs.rs b/rsnix/src/fs.rs
index 24d8fcd..3585c00 100644
--- a/rsnix/src/fs.rs
+++ b/rsnix/src/fs.rs
@@ -203,6 +203,7 @@ pub fn init() -> (usize, usize) {
203/// its backing info), and tombstone nodes whose volume was unmounted. 203/// its backing info), and tombstone nodes whose volume was unmounted.
204/// Returns (added, removed) node ops. 204/// Returns (added, removed) node ops.
205pub fn rescan_disks() -> (usize, usize) { 205pub fn rescan_disks() -> (usize, usize) {
206 let _lock = crate::fat::DiskGuard::acquire();
206 let mut added = 0usize; 207 let mut added = 0usize;
207 let mut removed = 0usize; 208 let mut removed = 0usize;
208 let disk_dir = match lookup(0, "disk") { 209 let disk_dir = match lookup(0, "disk") {
@@ -428,6 +429,7 @@ pub fn read(h: usize, buf: &mut [u8], pos: u64) -> Result<usize, ()> {
428} 429}
429 430
430pub fn write(h: usize, buf: &[u8], pos: u64) -> Result<usize, ()> { 431pub fn write(h: usize, buf: &[u8], pos: u64) -> Result<usize, ()> {
432 let _lock = crate::fat::DiskGuard::acquire();
431 match &mut nodes()[h].data { 433 match &mut nodes()[h].data {
432 NodeData::Regular(v) => { 434 NodeData::Regular(v) => {
433 let p = pos as usize; 435 let p = pos as usize;
@@ -533,7 +535,10 @@ pub fn write_crash_log(lines: &[&str]) {
533 let mut tb = [0u8; 48]; 535 let mut tb = [0u8; 48];
534 let tn = { 536 let tn = {
535 let mut w = crate::strbuf::FmtBuf::new(&mut tb); 537 let mut w = crate::strbuf::FmtBuf::new(&mut tb);
536 let _ = core::fmt::write(&mut w, core::format_args!("crashlog: vol {} ({})\r\n", vol, label)); 538 let _ = core::fmt::write(
539 &mut w,
540 core::format_args!("crashlog: vol {} ({})\r\n", vol, label),
541 );
537 w.len() 542 w.len()
538 }; 543 };
539 crate::serial::write_raw(core::str::from_utf8(&tb[..tn]).unwrap_or("?")); 544 crate::serial::write_raw(core::str::from_utf8(&tb[..tn]).unwrap_or("?"));
@@ -555,7 +560,9 @@ pub fn write_crash_log(lines: &[&str]) {
555} 560}
556 561
557/// Truncate/resize a regular file. 562/// Truncate/resize a regular file.
558pub fn set_len(h: usize, len: u64) -> Result<(), ()> { match &mut nodes()[h].data { 563pub fn set_len(h: usize, len: u64) -> Result<(), ()> {
564 let _lock = crate::fat::DiskGuard::acquire();
565 match &mut nodes()[h].data {
559 NodeData::Regular(v) => { 566 NodeData::Regular(v) => {
560 v.resize(len as usize, 0); 567 v.resize(len as usize, 0);
561 Ok(()) 568 Ok(())
@@ -567,6 +574,7 @@ pub fn set_len(h: usize, len: u64) -> Result<(), ()> { match &mut nodes()[h].
567 574
568/// Create a Regular or Dir child. Fails if the name exists or is invalid. 575/// Create a Regular or Dir child. Fails if the name exists or is invalid.
569pub fn create(parent: usize, name: &str, kind: FileType) -> Result<usize, ()> { 576pub fn create(parent: usize, name: &str, kind: FileType) -> Result<usize, ()> {
577 let _lock = crate::fat::DiskGuard::acquire();
570 if name.is_empty() || name.contains('/') || kind == FileType::Char { 578 if name.is_empty() || name.contains('/') || kind == FileType::Char {
571 return Err(()); 579 return Err(());
572 } 580 }
@@ -608,6 +616,7 @@ pub fn create(parent: usize, name: &str, kind: FileType) -> Result<usize, ()> {
608 616
609/// Remove a regular file or an empty directory (tombstone). 617/// Remove a regular file or an empty directory (tombstone).
610pub fn remove(h: usize) -> Result<(), ()> { 618pub fn remove(h: usize) -> Result<(), ()> {
619 let _lock = crate::fat::DiskGuard::acquire();
611 // Disk nodes: delete through the FAT volume (dirs must be empty). 620 // Disk nodes: delete through the FAT volume (dirs must be empty).
612 if let NodeData::Disk(i) = &nodes()[h].data { 621 if let NodeData::Disk(i) = &nodes()[h].data {
613 if i.name.is_empty() { 622 if i.name.is_empty() {