1919
2020mod gpt;
2121
22- use alloc:: boxed:: Box ;
2322use gpt:: Gpt ;
2423
2524use core:: mem:: MaybeUninit ;
@@ -32,34 +31,92 @@ use crate::fs::devfs::install_device;
3231use crate :: fs:: { FileSystem , Result } ;
3332
3433use crate :: fs:: ext2:: Ext2 ;
34+ use crate :: mem:: paging:: * ;
3535use crate :: utils:: sync:: Mutex ;
3636
37- use super :: cache:: { Cache , Cacheable } ;
37+ use super :: cache:: { Cache , CacheArc , CacheItem , Cacheable } ;
3838use super :: devfs:: { alloc_device_marker, Device } ;
3939use super :: inode:: INodeInterface ;
4040
41- type CachedBlockKey = ( usize , usize ) ; // (block device pointer, block)
41+ type PageCacheKey = ( usize , usize ) ; // (block device pointer, offset)
42+ type PageCacheItem = CacheArc < CacheItem < PageCacheKey , CachedPage > > ;
4243
43- struct CachedBlock {
44+ struct CachedPage {
4445 device : Weak < dyn CachedAccess > ,
45- block : usize ,
46- buffer : Box < [ u8 ] > ,
46+ offset : usize ,
47+ page : PhysFrame ,
4748}
4849
49- impl CachedBlock {
50- fn make_key ( device : Weak < dyn CachedAccess > , block : usize ) -> CachedBlockKey {
51- ( device. as_ptr ( ) as * const u8 as usize , block)
50+ impl CachedPage {
51+ fn new ( device : Weak < dyn CachedAccess > , offset : usize ) -> Self {
52+ Self {
53+ device,
54+ offset,
55+ page : FRAME_ALLOCATOR
56+ . allocate_frame ( )
57+ . expect ( "page_cache: out of memory" ) ,
58+ }
59+ }
60+
61+ fn data_mut ( & self ) -> & mut [ MaybeUninit < u8 > ] {
62+ let data_ptr = self
63+ . page
64+ . start_address ( )
65+ . as_hhdm_virt ( )
66+ . as_mut_ptr :: < MaybeUninit < u8 > > ( ) ;
67+
68+ // SAFETY: It is safe to create a slice of MaybeUninit<T> because it has the same
69+ // size and alignment as T.
70+ unsafe { core:: slice:: from_raw_parts_mut ( data_ptr, Size4KiB :: SIZE as usize ) }
71+ }
72+
73+ fn make_key ( device : Weak < dyn CachedAccess > , offset : usize ) -> PageCacheKey {
74+ ( device. as_ptr ( ) as * const u8 as usize , offset)
5275 }
5376}
5477
55- impl Cacheable < CachedBlockKey > for CachedBlock {
56- fn cache_key ( & self ) -> CachedBlockKey {
57- Self :: make_key ( self . device . clone ( ) , self . block )
78+ impl Cacheable < PageCacheKey > for CachedPage {
79+ fn cache_key ( & self ) -> PageCacheKey {
80+ Self :: make_key ( self . device . clone ( ) , self . offset )
5881 }
5982}
6083
6184lazy_static:: lazy_static! {
62- static ref BLOCK_CACHE : Arc <Cache <CachedBlockKey , CachedBlock >> = Cache :: new( ) ;
85+ static ref PAGE_CACHE : Arc <Cache <PageCacheKey , CachedPage >> = Cache :: new( ) ;
86+ }
87+
88+ impl Cache < PageCacheKey , CachedPage > {
89+ /// Returns the cached page at the given offset, if not present, it will be allocated,
90+ /// initialized with the data on the disk and placed in the page cache.
91+ ///
92+ /// ## Arguments
93+ ///
94+ /// * `device` - The device to get the page from.
95+ ///
96+ /// * `offset` - The offset in bytes to the data. This will be rounded down to
97+ /// the nearest page boundary.
98+ pub fn get_page ( & self , device : Weak < dyn CachedAccess > , offset : usize ) -> PageCacheItem {
99+ let cache_offset = offset / Size4KiB :: SIZE as usize ;
100+ let cache_key = CachedPage :: make_key ( device. clone ( ) , cache_offset) ;
101+
102+ if let Some ( page) = PAGE_CACHE . get ( cache_key) {
103+ return page;
104+ }
105+
106+ let page = CachedPage :: new ( device. clone ( ) , offset) ;
107+ let device = device. upgrade ( ) . expect ( "page_cache: device dropped" ) ;
108+
109+ let aligned_offset = align_down ( offset as u64 , Size4KiB :: SIZE ) as usize ;
110+
111+ device
112+ // FIXME(perf,mem): internally read_block makes use of the DMA API (cc drivers::nvme::dma), which in turn
113+ // allocates another frame in order to make sure the destination buffer is DMA capable. In this
114+ // case, this is not required since we have already allocated a DMA capable frame.
115+ . read_block ( aligned_offset / device. block_size ( ) , page. data_mut ( ) )
116+ . expect ( "page_cache: failed to read block" ) ;
117+
118+ PAGE_CACHE . make_item_cached ( page)
119+ }
63120}
64121
65122pub trait BlockDeviceInterface : Send + Sync {
@@ -72,44 +129,23 @@ pub trait BlockDeviceInterface: Send + Sync {
72129pub trait CachedAccess : BlockDeviceInterface {
73130 fn sref ( & self ) -> Weak < dyn CachedAccess > ;
74131
75- fn read ( & self , offset : usize , dest : & mut [ MaybeUninit < u8 > ] ) -> Option < usize > {
76- let mut progress = 0 ;
77- let block_size = self . block_size ( ) ;
78-
79- while progress < dest. len ( ) {
80- let block = ( offset + progress) / block_size;
81- let loc = ( offset + progress) % block_size;
132+ fn read ( & self , mut offset : usize , dest : & mut [ MaybeUninit < u8 > ] ) -> Option < usize > {
133+ let mut loc = 0 ;
82134
83- let mut chunk = dest. len ( ) - progress;
135+ while loc < dest. len ( ) {
136+ let page = PAGE_CACHE . get_page ( self . sref ( ) , offset) ;
84137
85- if chunk > ( block_size - loc) {
86- chunk = block_size - loc;
87- }
138+ let page_offset = offset % Size4KiB :: SIZE as usize ;
139+ let size = core:: cmp:: min ( Size4KiB :: SIZE as usize - page_offset, dest. len ( ) - loc) ;
88140
89- let key = CachedBlock :: make_key ( self . sref ( ) , block) ;
90-
91- if let Some ( cached) = BLOCK_CACHE . get ( key) {
92- MaybeUninit :: write_slice (
93- & mut dest[ progress..( progress + chunk) ] ,
94- & cached. buffer [ loc..loc + chunk] ,
95- ) ;
96- } else {
97- let mut buffer = Box :: < [ u8 ] > :: new_uninit_slice ( block_size) ;
98-
99- self . read_block ( block, MaybeUninit :: slice_as_bytes_mut ( & mut buffer) ) ?;
100- dest[ progress..( progress + chunk) ] . copy_from_slice ( & buffer[ loc..loc + chunk] ) ;
101-
102- BLOCK_CACHE . make_item_cached ( CachedBlock {
103- device : self . sref ( ) ,
104- block,
105- buffer : unsafe { buffer. assume_init ( ) } ,
106- } ) ;
107- }
141+ let data = & page. data_mut ( ) [ page_offset..page_offset + size] ;
142+ dest[ loc..loc + size] . copy_from_slice ( data) ;
108143
109- progress += chunk;
144+ loc += size;
145+ offset += align_down ( offset as u64 + Size4KiB :: SIZE , Size4KiB :: SIZE ) as usize ;
110146 }
111147
112- Some ( progress )
148+ Some ( loc )
113149 }
114150}
115151
0 commit comments