Skip to content

Commit c1966f2

Browse files
committed
ch7
1 parent 5cdadd1 commit c1966f2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2029
-821
lines changed

easy-fs-fuse/src/main.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fn easy_fs_pack() -> std::io::Result<()> {
7272
Ok(fname)
7373
})
7474
.collect::<std::io::Result<Vec<_>>>()?;
75+
println!("easy-fs-use >>>>");
7576
for app in apps {
7677
// load built app only from host file system
7778
let path = opt.target.join(&app);
@@ -82,16 +83,16 @@ fn easy_fs_pack() -> std::io::Result<()> {
8283
let mut host_file = File::open(path)?;
8384
let mut all_data = Vec::new();
8485
host_file.read_to_end(&mut all_data)?;
86+
println!(
87+
"easy-fs-fuse: + {app} {}B {}KB",
88+
all_data.len(),
89+
all_data.len() / 1024
90+
);
8591
// create a file in easy-fs
8692
let inode = root_inode.create(&app).unwrap();
8793
// write data to easy-fs
8894
inode.write_at(0, &all_data);
8995
}
90-
// list apps
91-
println!("easy-fs-use >>>>");
92-
for app in root_inode.ls() {
93-
println!("easy-fs-use: + {}", app);
94-
}
9596
println!("easy-fs-use <<<<");
9697
Ok(())
9798
}
@@ -192,7 +193,13 @@ mod tests {
192193
if depth == 0 {
193194
println!("{}", name);
194195
} else {
195-
println!("+-- {}", name);
196+
println!(
197+
"+-- {} f:{} {}B {}KB",
198+
name,
199+
inode.is_file(),
200+
inode.get_size(),
201+
inode.get_size() / 1024
202+
);
196203
}
197204
for f in inode.ls() {
198205
// skip "." and ".."

easy-fs/src/efs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use spin::Mutex;
33

44
use crate::{
55
bitmap::Bitmap,
6-
block_cache::get_block_cache,
6+
block_cache::{block_cache_sync_all, get_block_cache},
77
block_dev::BlockDevice,
88
layout::{DiskInode, DiskInodeType, SuperBlock},
99
vfs::Inode,
@@ -91,6 +91,7 @@ impl EasyFileSystem {
9191
root_inode.initialize(DiskInodeType::Directory);
9292
root_inode.initialize_dir(0, 0, || efs.alloc_data(), &block_device);
9393
});
94+
block_cache_sync_all();
9495

9596
Arc::new(Mutex::new(efs))
9697
}

easy-fs/src/vfs.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,14 @@ impl Inode {
274274
/// Write data to current inode
275275
pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize {
276276
let mut fs = self.fs.lock();
277-
self.modify_disk_inode(|disk_inode| {
277+
let size = self.modify_disk_inode(|disk_inode| {
278278
assert!(disk_inode.is_file());
279279
// extend first
280280
self.increase_size((offset + buf.len()) as u32, disk_inode, &mut fs);
281281
disk_inode.write_at(offset, buf, &self.block_device)
282-
})
282+
});
283+
block_cache_sync_all(); // MUST sync here to avoid data lost
284+
size
283285
}
284286

285287
/// Get inode id

os/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ OBJCOPY := rust-objcopy --binary-architecture=riscv64
2929
DISASM ?= -x
3030

3131
# Run usertests or usershell
32-
TEST ?=
32+
TEST ?= 0
3333

3434
# Use existing disk
3535
USE_DISK ?=
@@ -52,7 +52,7 @@ $(KERNEL_BIN): kernel
5252
fs-img: $(APPS)
5353
@cd ../user && make build TEST=$(TEST)
5454
@rm -f $(FS_IMG)
55-
@cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin -t ../user/target/riscv64gc-unknown-none-elf/release/
55+
@cd ../easy-fs-fuse && cargo run --release -- -s ../user/src/bin -t ../user/target/$(TARGET)/$(MODE)/
5656

5757
$(APPS):
5858

os/src/fs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use core::any::Any;
33
use crate::{cast::DowncastArc, mm::UserBuffer};
44

55
mod inode;
6+
mod pipe;
67
mod stdio;
78
pub use inode::*;
9+
pub use pipe::*;
810
pub use stdio::{Stdin, Stdout};
911

1012
pub trait File: Any + Send + Sync {

os/src/fs/pipe.rs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
use alloc::sync::{Arc, Weak};
2+
3+
use crate::{sync::UPSafeCell, task::suspend_current_and_run_next};
4+
5+
use super::File;
6+
7+
pub struct Pipe {
8+
readable: bool,
9+
writable: bool,
10+
buffer: Arc<UPSafeCell<PipeRingBuffer>>,
11+
}
12+
13+
const RING_BUFFER_SIZE: usize = 32;
14+
15+
#[derive(Clone, Copy, PartialEq)]
16+
enum RingBufferStatus {
17+
FULL,
18+
EMPTY,
19+
NORMAL,
20+
}
21+
22+
pub struct PipeRingBuffer {
23+
arr: [u8; RING_BUFFER_SIZE],
24+
head: usize,
25+
tail: usize,
26+
status: RingBufferStatus,
27+
write_end: Option<Weak<Pipe>>, // to tell if all write ends been closed
28+
}
29+
30+
impl PipeRingBuffer {
31+
pub fn new() -> Self {
32+
Self {
33+
arr: [0; RING_BUFFER_SIZE],
34+
head: 0,
35+
tail: 0,
36+
status: RingBufferStatus::EMPTY,
37+
write_end: None,
38+
}
39+
}
40+
41+
pub fn set_write_end(&mut self, write_end: &Arc<Pipe>) {
42+
self.write_end = Some(Arc::downgrade(write_end));
43+
}
44+
45+
pub fn read_byte(&mut self) -> u8 {
46+
self.status = RingBufferStatus::NORMAL;
47+
let c = self.arr[self.head];
48+
self.head = (self.head + 1) % RING_BUFFER_SIZE;
49+
if self.head == self.tail {
50+
self.status = RingBufferStatus::EMPTY;
51+
}
52+
c
53+
}
54+
55+
pub fn write_byte(&mut self, byte: u8) {
56+
self.status = RingBufferStatus::NORMAL;
57+
self.arr[self.tail] = byte;
58+
self.tail = (self.tail + 1) % RING_BUFFER_SIZE;
59+
if self.head == self.tail {
60+
self.status = RingBufferStatus::FULL;
61+
}
62+
}
63+
64+
pub fn available_read(&self) -> usize {
65+
if self.status == RingBufferStatus::EMPTY {
66+
0
67+
} else {
68+
// | head .. tail |
69+
if self.tail > self.head {
70+
self.tail - self.head
71+
}
72+
// | .. .. head | .. tail
73+
// ___________/
74+
// / tail .. .. |
75+
else {
76+
self.tail + RING_BUFFER_SIZE - self.head
77+
}
78+
}
79+
}
80+
81+
pub fn available_write(&self) -> usize {
82+
if self.status == RingBufferStatus::FULL {
83+
0
84+
} else {
85+
RING_BUFFER_SIZE - self.available_read()
86+
}
87+
}
88+
89+
pub fn all_write_ends_closed(&self) -> bool {
90+
if let Some(weak) = &self.write_end {
91+
weak.upgrade().is_none()
92+
} else {
93+
panic!("PipeRingBuffer write_end not set!")
94+
}
95+
}
96+
}
97+
98+
impl Pipe {
99+
pub fn read_end_with_buffer(buffer: Arc<UPSafeCell<PipeRingBuffer>>) -> Self {
100+
Self {
101+
readable: true,
102+
writable: false,
103+
buffer,
104+
}
105+
}
106+
107+
pub fn write_end_with_buffer(buffer: Arc<UPSafeCell<PipeRingBuffer>>) -> Self {
108+
Self {
109+
readable: false,
110+
writable: true,
111+
buffer,
112+
}
113+
}
114+
}
115+
116+
impl File for Pipe {
117+
fn readable(&self) -> bool {
118+
self.readable
119+
}
120+
121+
fn writable(&self) -> bool {
122+
self.writable
123+
}
124+
125+
fn read(&self, buf: crate::mm::UserBuffer) -> usize {
126+
assert!(self.readable);
127+
let want_to_read = buf.len();
128+
let mut buf_iter = buf.into_iter();
129+
let mut already_read = 0;
130+
loop {
131+
let mut rb = self.buffer.exclusive_access();
132+
// how many bytes allowed to read during this iteration
133+
let loop_read = rb.available_read();
134+
if loop_read == 0 {
135+
// if no more available && all write end closed, that's all we get
136+
if rb.all_write_ends_closed() {
137+
return already_read;
138+
}
139+
// else if write end still alive, we wait for more coming
140+
// aka, suspend and run other task(maybe the one holds writer)
141+
// to fill ring_buffer, and before that, we must release it
142+
// to avoid deadlock (coz task switch will not auto drop it)
143+
drop(rb);
144+
suspend_current_and_run_next();
145+
continue;
146+
}
147+
// if loop_read bytes can be read
148+
for _ in 0..loop_read {
149+
// read into buf one-by-one
150+
if let Some(byte_ref) = buf_iter.next() {
151+
unsafe {
152+
*byte_ref = rb.read_byte();
153+
}
154+
already_read += 1;
155+
// return if reach number we need
156+
if already_read == want_to_read {
157+
return want_to_read;
158+
}
159+
} else {
160+
// I think it's exact same with above return condition ..
161+
return already_read;
162+
}
163+
}
164+
}
165+
}
166+
167+
fn write(&self, buf: crate::mm::UserBuffer) -> usize {
168+
assert!(self.writable);
169+
let want_to_write = buf.len();
170+
let mut buf_iter = buf.into_iter();
171+
let mut already_write = 0;
172+
loop {
173+
let mut rb = self.buffer.exclusive_access();
174+
let loop_write = rb.available_write();
175+
if loop_write == 0 {
176+
drop(rb);
177+
suspend_current_and_run_next();
178+
continue;
179+
}
180+
for _ in 0..loop_write {
181+
if let Some(byte_ref) = buf_iter.next() {
182+
rb.write_byte(unsafe { *byte_ref });
183+
already_write += 1;
184+
if already_write == want_to_write {
185+
return want_to_write;
186+
}
187+
} else {
188+
return already_write;
189+
}
190+
}
191+
}
192+
}
193+
}
194+
195+
/// Return (read_end, write_end)
196+
pub fn make_pipe() -> (Arc<Pipe>, Arc<Pipe>) {
197+
let buffer = Arc::new(unsafe { UPSafeCell::new(PipeRingBuffer::new()) });
198+
let r = Arc::new(Pipe::read_end_with_buffer(buffer.clone()));
199+
let w = Arc::new(Pipe::write_end_with_buffer(buffer.clone()));
200+
buffer.exclusive_access().set_write_end(&w);
201+
(r, w)
202+
}

os/src/mm/address.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl PhysAddr {
7979
PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE)
8080
}
8181

82+
pub fn get_ref<T>(&self) -> &'static T {
83+
unsafe { (self.0 as *const T).as_ref().unwrap() }
84+
}
85+
8286
pub fn get_mut<T>(&self) -> &'static mut T {
8387
unsafe { (self.0 as *mut T).as_mut().unwrap() }
8488
}

os/src/mm/page_table.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,13 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String {
246246
s
247247
}
248248

249+
pub fn translate_ref<T>(token: usize, ptr: *const T) -> &'static T {
250+
let page_table = PageTable::from_token(token);
251+
let va = VirtAddr::from(ptr as usize);
252+
let pa = page_table.translate_va(va).unwrap();
253+
pa.get_ref()
254+
}
255+
249256
/// for primitive values only
250257
// Q: https://github.com/rcore-os/rCore-Tutorial-Book-v3/issues/55#issuecomment-1568718900
251258
// A: compiler保证这些值的地址是aligned, 即不会cross page boundary

os/src/syscall/fs.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,12 @@ use easy_fs::Inode;
44

55
use crate::{
66
cast::DowncastArc,
7-
fs::{self, name_for_inode, unlink_file_at, File, OSInode, OpenFlags, ROOT_INODE},
7+
fs::{self, make_pipe, name_for_inode, unlink_file_at, File, OSInode, OpenFlags, ROOT_INODE},
88
mm::{self, translated_byte_buffer, UserBuffer},
99
task::{self, TaskControlBlock},
1010
};
1111

12-
macro_rules! bail_exit {
13-
($e:expr) => {
14-
match $e {
15-
Ok(v) => v,
16-
Err(exit) => return exit,
17-
}
18-
};
19-
}
12+
use super::bail_exit;
2013

2114
/// write buf of length `len` to a file with `fd`
2215
pub fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize {
@@ -320,3 +313,29 @@ pub fn sys_fstat(fd: usize, ptr: *mut Stat) -> isize {
320313
}
321314
0
322315
}
316+
317+
pub fn sys_pipe(pipe: *mut usize) -> isize {
318+
let task = task::current_task().unwrap();
319+
let mut inner = task.inner_exclusive_access();
320+
let token = inner.get_user_token();
321+
let (pipe_read, pipe_write) = make_pipe();
322+
let read_fd = inner.alloc_fd();
323+
inner.fd_table[read_fd] = Some(pipe_read);
324+
let write_fd = inner.alloc_fd();
325+
inner.fd_table[write_fd] = Some(pipe_write);
326+
*mm::translated_refmut(token, pipe) = read_fd;
327+
*mm::translated_refmut(token, unsafe { pipe.add(1) }) = write_fd;
328+
0
329+
}
330+
331+
pub fn sys_dup(fd: usize) -> isize {
332+
let task = task::current_task().unwrap();
333+
let mut inner = task.inner_exclusive_access();
334+
let file = match inner.fd_table.get(fd) {
335+
Some(Some(file)) => file.clone(),
336+
_ => return -1,
337+
};
338+
let new_fd = inner.alloc_fd();
339+
inner.fd_table[new_fd] = Some(file);
340+
new_fd as isize
341+
}

0 commit comments

Comments
 (0)