feat(userspace): shell runs programs (ls, cat) via spawn w/ terminal+storage+args page; ext4 holes read as zeros; storage re-attach same buffer
This commit is contained in:
@@ -106,9 +106,15 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
||||
let mut block_buf = [0u8; 4096];
|
||||
while done < to_read {
|
||||
let offset = file.offset + done;
|
||||
let phys_block = self.map_logical_block(&inode, (offset / bs) as u32)?;
|
||||
if !read_block(&mut self.device, phys_block, self.sb.sectors_per_block(), &mut block_buf) {
|
||||
return None;
|
||||
// A block no extent maps is a hole (mkfs leaves zero blocks
|
||||
// out): it reads as zeros.
|
||||
match self.map_logical_block(&inode, (offset / bs) as u32) {
|
||||
Some(phys_block) => {
|
||||
if !read_block(&mut self.device, phys_block, self.sb.sectors_per_block(), &mut block_buf) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
None => block_buf.fill(0),
|
||||
}
|
||||
let byte_in_block = offset % bs;
|
||||
let chunk = (to_read - done).min(bs - byte_in_block);
|
||||
|
||||
@@ -23,6 +23,8 @@ pub trait Buffers {
|
||||
struct Client {
|
||||
badge: usize,
|
||||
buf: &'static mut [u8],
|
||||
/// What maps `buf`, sent again when the same client attaches again.
|
||||
cap: Option<CapSlot>,
|
||||
}
|
||||
|
||||
pub struct StorageServer<F: FileSystem, B: Buffers> {
|
||||
@@ -77,9 +79,11 @@ impl<F: FileSystem, B: Buffers> StorageServer<F, B> {
|
||||
self.clients.iter_mut().flatten().find(|c| c.badge == badge)
|
||||
}
|
||||
|
||||
/// A client attaching again gets its buffer again: the programs a shell
|
||||
/// runs one after another share its badge.
|
||||
fn attach(&mut self, badge: usize) -> (StorageResponse, Option<CapSlot>) {
|
||||
if self.client(badge).is_some() {
|
||||
return (StorageResponse::Error, None);
|
||||
if let Some(c) = self.client(badge) {
|
||||
return (StorageResponse::Attached { size: c.buf.len() }, c.cap);
|
||||
}
|
||||
let Some(index) = self.clients.iter().position(Option::is_none) else {
|
||||
return (StorageResponse::Error, None);
|
||||
@@ -89,7 +93,7 @@ impl<F: FileSystem, B: Buffers> StorageServer<F, B> {
|
||||
};
|
||||
let size = buf.len();
|
||||
if let Some(slot) = self.clients.get_mut(index) {
|
||||
*slot = Some(Client { badge, buf });
|
||||
*slot = Some(Client { badge, buf, cap });
|
||||
}
|
||||
(StorageResponse::Attached { size }, cap)
|
||||
}
|
||||
|
||||
@@ -170,3 +170,16 @@ fn one_read_fills_the_buffer_across_blocks() {
|
||||
assert_eq!(fs.read(h, &mut buf), Some(total - 10_000));
|
||||
assert_eq!(fs.read(h, &mut buf), Some(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn holes_read_as_zeros() {
|
||||
let dir = scratch("sparse");
|
||||
// Data, then a zero block mkfs stores as a hole, then data again.
|
||||
let mut data = std::vec![b'x'; 4096];
|
||||
data.extend(std::vec![0u8; 4096]);
|
||||
data.extend(b"end");
|
||||
std::fs::write(dir.join("root/sparse.bin"), &data).unwrap();
|
||||
let Some(img) = mkfs(&dir, MKFS_FEATURES) else { return };
|
||||
let mut fs = Ext4::mount(FileDisk(img)).expect("mount");
|
||||
assert_eq!(read_all(&mut fs, b"sparse.bin"), data);
|
||||
}
|
||||
|
||||
@@ -67,10 +67,14 @@ fn nothing_works_before_attaching() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_client_attaches_once() {
|
||||
fn attaching_again_hands_back_the_same_buffer() {
|
||||
let mut s = server();
|
||||
Client::attach(&mut s, 0);
|
||||
assert_eq!(call(&mut s, 0, StorageRequest::Attach).0, StorageResponse::Error);
|
||||
let (first, cap) = call(&mut s, 0, StorageRequest::Attach);
|
||||
assert_eq!(call(&mut s, 0, StorageRequest::Attach), (first, cap));
|
||||
// Not a new client: the other seven places are still free.
|
||||
for badge in 1..8 {
|
||||
assert!(matches!(call(&mut s, badge, StorageRequest::Attach).0, StorageResponse::Attached { .. }));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user