Skip to content

Commit 02e022f

Browse files
committed
ch6: mmap file with demand-paging
1 parent d69ee2b commit 02e022f

File tree

20 files changed

+1139
-72
lines changed

20 files changed

+1139
-72
lines changed

easy-fs/src/efs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ impl EasyFileSystem {
125125
drop(guard);
126126

127127
Inode::new(
128+
0,
128129
root_inode_block_id,
129130
root_inode_offset,
130131
efs.clone(),

easy-fs/src/vfs.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use crate::{
1010

1111
/// Virtual filesystem layer over easy-fs
1212
pub struct Inode {
13+
inode_id: u32,
14+
1315
// indicate which `DiskInode` is mapping
1416
block_id: usize,
1517
block_offset: usize,
@@ -21,12 +23,14 @@ pub struct Inode {
2123
impl Inode {
2224
/// Create a vfs inode
2325
pub fn new(
26+
inode_id: u32,
2427
block_id: u32,
2528
block_offset: usize,
2629
fs: Arc<Mutex<EasyFileSystem>>,
2730
block_device: Arc<dyn BlockDevice>,
2831
) -> Self {
2932
Self {
33+
inode_id,
3034
block_id: block_id as usize,
3135
block_offset,
3236
fs,
@@ -73,6 +77,7 @@ impl Inode {
7377
self.find_inode_id(name, disk_inode).map(|inode_id| {
7478
let (block_id, block_offset) = fs.get_disk_inode_pos(inode_id);
7579
Arc::new(Inode::new(
80+
inode_id,
7681
block_id,
7782
block_offset,
7883
self.fs.clone(),
@@ -108,7 +113,7 @@ impl Inode {
108113
disk_inode: &mut DiskInode,
109114
fs: &mut MutexGuard<EasyFileSystem>,
110115
) {
111-
if new_size < disk_inode.size {
116+
if new_size <= disk_inode.size {
112117
return;
113118
}
114119

@@ -160,6 +165,7 @@ impl Inode {
160165
// 4. return inode
161166
block_cache_sync_all();
162167
Some(Arc::new(Self::new(
168+
new_inode_id,
163169
new_inode_block_id,
164170
new_inode_block_offset,
165171
self.fs.clone(),
@@ -199,4 +205,14 @@ impl Inode {
199205
disk_inode.write_at(offset, buf, &self.block_device)
200206
})
201207
}
208+
209+
/// Get inode id
210+
pub fn inode_id(&self) -> u32 {
211+
self.inode_id
212+
}
213+
214+
/// Get data size of inode
215+
pub fn get_size(&self) -> usize {
216+
self.read_disk_inode(|disk_inode| disk_inode.size as usize)
217+
}
202218
}

os/src/cast.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use core::any::Any;
2+
3+
use alloc::sync::Arc;
4+
5+
pub trait DowncastArc: Any {
6+
/// must be implemented: cast `Arc<Self>` into `Arc<dyn Any>`
7+
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any>;
8+
9+
/// cast `Arc<dyn impl Trait>` into `Arc<T>`
10+
fn downcast_arc<T: Any>(self: Arc<Self>) -> Option<Arc<T>> {
11+
let arc_any: Arc<dyn Any> = self.as_any_arc();
12+
if arc_any.is::<T>() {
13+
// will not change ref-count
14+
let ptr = Arc::into_raw(arc_any);
15+
Some(unsafe { Arc::from_raw(ptr as *const T) })
16+
} else {
17+
None
18+
}
19+
}
20+
}

os/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ pub const PAGE_SIZE: usize = 0x1000;
1010
pub const PAGE_SIZE_BITS: usize = 12;
1111
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
1212
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
13+
14+
pub const MMAP_AREA_BASE: usize = 0x0000_0001_0000_0000; // base addr in user_space that nobody use

os/src/fs/inode.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,29 @@ impl OSInode {
4141
}
4242
v
4343
}
44+
45+
#[allow(unused)]
46+
pub fn is_dir(&self) -> bool {
47+
self.inner
48+
.exclusive_access()
49+
.inode
50+
.read_disk_inode(|disk_inode| disk_inode.is_dir())
51+
}
52+
53+
pub fn is_file(&self) -> bool {
54+
self.inner
55+
.exclusive_access()
56+
.inode
57+
.read_disk_inode(|disk_inode| disk_inode.is_file())
58+
}
59+
60+
pub fn clone_inner_inode(&self) -> Arc<Inode> {
61+
self.inner.exclusive_access().inode.clone()
62+
}
63+
64+
pub fn copy(&self) -> Self {
65+
Self::new(self.readable, self.writable, self.clone_inner_inode())
66+
}
4467
}
4568

4669
lazy_static! {

os/src/fs/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use crate::mm::UserBuffer;
1+
use core::any::Any;
2+
3+
use crate::{cast::DowncastArc, mm::UserBuffer};
24

35
mod inode;
46
mod stdio;
5-
pub use inode::{list_apps, open_file, OpenFlags};
7+
pub use inode::{list_apps, open_file, OSInode, OpenFlags};
68
pub use stdio::{Stdin, Stdout};
79

8-
pub trait File: Send + Sync {
10+
pub trait File: Any + Send + Sync {
911
/// If readable
1012
fn readable(&self) -> bool;
1113
/// If writable
@@ -15,3 +17,10 @@ pub trait File: Send + Sync {
1517
/// Write `UserBuffer` to file
1618
fn write(&self, buf: UserBuffer) -> usize;
1719
}
20+
21+
impl DowncastArc for dyn File {
22+
fn as_any_arc(self: alloc::sync::Arc<Self>) -> alloc::sync::Arc<dyn Any> {
23+
// need #![feature(trait_upcasting)]
24+
self
25+
}
26+
}

os/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
#![feature(array_windows)]
44
#![feature(alloc_error_handler)]
55
#![feature(slice_split_once)]
6+
#![feature(trait_upcasting)]
67

78
extern crate alloc;
89
extern crate bitflags;
910

1011
#[path = "boards/qemu.rs"]
1112
mod board;
13+
mod cast;
1214
mod config;
1315
#[macro_use]
1416
mod console;

os/src/mm/address.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,22 @@ impl StepByOne for VirtPageNum {
220220
}
221221
}
222222

223-
#[derive(Clone, Copy)]
223+
#[derive(Clone, Copy, PartialEq)]
224224
pub struct SimpleRange<T>
225225
where
226226
T: StepByOne + Copy + Debug + PartialEq + PartialOrd,
227227
{
228228
l: T,
229229
r: T,
230230
}
231+
impl<T> Debug for SimpleRange<T>
232+
where
233+
T: StepByOne + Copy + Debug + PartialEq + PartialOrd,
234+
{
235+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
236+
write!(f, "[{:?}, {:?})", self.l, self.r)
237+
}
238+
}
231239

232240
impl<T> SimpleRange<T>
233241
where
@@ -245,6 +253,21 @@ where
245253
pub fn get_end(&self) -> T {
246254
self.r
247255
}
256+
257+
pub fn contains(&self, v: impl Into<T>) -> bool {
258+
let vpn: T = v.into();
259+
self.l <= vpn && vpn < self.r // r excluded
260+
}
261+
262+
pub fn overlap_with(&self, other: &Self) -> bool {
263+
// coz rhs is excluded, we must make lhs+1 when comparing
264+
let mut other_l = other.get_start();
265+
other_l.step();
266+
let mut self_l = self.l.clone();
267+
self_l.step();
268+
269+
self.r >= other_l && other.get_end() >= self_l
270+
}
248271
}
249272

250273
impl<T> IntoIterator for SimpleRange<T>

os/src/mm/memory_set.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -410,15 +410,11 @@ impl MemorySet {
410410
);
411411
}
412412

413-
/// Delegate to page_table
413+
/// Delegate `token()` to page_table
414414
pub fn token(&self) -> usize {
415415
self.page_table.token()
416416
}
417417

418-
pub fn page_table_mut(&mut self) -> &mut PageTable {
419-
&mut self.page_table
420-
}
421-
422418
pub fn remove_area_with_start_vpn(&mut self, start_vpn: VirtPageNum) {
423419
if let Some((idx, area)) = self
424420
.areas
@@ -434,6 +430,17 @@ impl MemorySet {
434430
pub fn recycle_data_pages(&mut self) {
435431
self.areas.clear();
436432
}
433+
434+
/// Delegate `map()` to page_table
435+
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, map_perm: MapPermission) {
436+
let pte_flags = PTEFlags::from_bits_truncate(map_perm.bits);
437+
self.page_table.map(vpn, ppn, pte_flags);
438+
}
439+
440+
/// Delegate `unmap()` to page_table
441+
pub fn unmap(&mut self, vpn: VirtPageNum) {
442+
self.page_table.unmap(vpn);
443+
}
437444
}
438445

439446
#[allow(unused)]

os/src/mm/page_table.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ impl PageTableEntry {
7373
pub fn executable(&self) -> bool {
7474
self.flags().contains(PTEFlags::X)
7575
}
76+
77+
pub fn is_dirty(&self) -> bool {
78+
self.flags().contains(PTEFlags::D)
79+
}
7680
}
7781

7882
pub struct PageTable {

0 commit comments

Comments
 (0)