@@ -22,6 +22,8 @@ mod gpt;
2222use gpt:: Gpt ;
2323
2424use core:: mem:: MaybeUninit ;
25+ use core:: ops:: { Deref , DerefMut } ;
26+ use core:: sync:: atomic:: { AtomicBool , Ordering } ;
2527
2628use alloc:: collections:: BTreeMap ;
2729use alloc:: sync:: { Arc , Weak } ;
@@ -45,6 +47,7 @@ struct CachedPage {
4547 device : Weak < dyn CachedAccess > ,
4648 offset : usize ,
4749 page : PhysFrame ,
50+ dirty : AtomicBool ,
4851}
4952
5053impl CachedPage {
@@ -55,6 +58,7 @@ impl CachedPage {
5558 page : FRAME_ALLOCATOR
5659 . allocate_frame ( )
5760 . expect ( "page_cache: out of memory" ) ,
61+ dirty : AtomicBool :: new ( false ) ,
5862 }
5963 }
6064
@@ -77,6 +81,39 @@ impl CachedPage {
7781 fn make_key ( device : Weak < dyn CachedAccess > , offset : usize ) -> PageCacheKey {
7882 ( device. as_ptr ( ) as * const u8 as usize , offset)
7983 }
84+
85+ /// Returns whether the page has been marked dirty.
86+ fn is_dirty ( & self ) -> bool {
87+ self . dirty . load ( Ordering :: SeqCst )
88+ }
89+
90+ fn mark_dirty ( & self ) {
91+ self . dirty . store ( true , Ordering :: SeqCst ) ;
92+ }
93+
94+ fn device ( & self ) -> Arc < dyn CachedAccess > {
95+ self . device . upgrade ( ) . unwrap ( )
96+ }
97+
98+ fn sync ( & self ) {
99+ if !self . is_dirty ( ) {
100+ return ;
101+ }
102+
103+ // Commit the changes made to the cache to the disk.
104+ let disk = self . device ( ) ;
105+
106+ let offset_bytes = self . offset * Size4KiB :: SIZE as usize ;
107+ let sector = offset_bytes / disk. block_size ( ) ;
108+
109+ disk. write_dma ( sector, self . data_addr ( ) , Size4KiB :: SIZE as usize ) ;
110+ }
111+ }
112+
113+ impl Drop for CachedPage {
114+ fn drop ( & mut self ) {
115+ self . sync ( )
116+ }
80117}
81118
82119impl Cacheable < PageCacheKey > for CachedPage {
@@ -96,9 +133,8 @@ impl Cache<PageCacheKey, CachedPage> {
96133 /// ## Arguments
97134 ///
98135 /// * `device` - The device to get the page from.
99- ///
100- /// * `offset` - The offset in bytes to the data. This will be rounded down to
101- /// the nearest page boundary.
136+ /// * `offset` - The offset in bytes to the data. This will be rounded down to the nearest page
137+ /// boundary.
102138 pub fn get_page ( & self , device : Weak < dyn CachedAccess > , offset : usize ) -> PageCacheItem {
103139 let cache_offset = offset / Size4KiB :: SIZE as usize ;
104140 let cache_key = CachedPage :: make_key ( device. clone ( ) , cache_offset) ;
@@ -121,10 +157,48 @@ impl Cache<PageCacheKey, CachedPage> {
121157 }
122158}
123159
160+ pub struct DirtyRef < T : Sized > {
161+ cache : PageCacheItem ,
162+ ptr : * mut T ,
163+ }
164+
165+ impl < T > DirtyRef < T > {
166+ pub fn new ( device : Weak < dyn CachedAccess > , offset : usize ) -> Self {
167+ let cache = PAGE_CACHE . get_page ( device, offset) ;
168+
169+ let ptr_offset = offset % Size4KiB :: SIZE as usize ;
170+ let ptr = & cache. data_mut ( ) [ ptr_offset..ptr_offset + core:: mem:: size_of :: < T > ( ) ] ;
171+
172+ Self {
173+ ptr : ptr. as_ptr ( ) as * mut T ,
174+ cache,
175+ }
176+ }
177+ }
178+
179+ impl < T > Deref for DirtyRef < T > {
180+ type Target = T ;
181+
182+ fn deref ( & self ) -> & Self :: Target {
183+ unsafe { & * self . ptr }
184+ }
185+ }
186+
187+ impl < T > DerefMut for DirtyRef < T > {
188+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
189+ self . cache . mark_dirty ( ) ;
190+ unsafe { & mut * self . ptr }
191+ }
192+ }
193+
194+ unsafe impl < T > Sync for DirtyRef < T > { }
195+ unsafe impl < T > Send for DirtyRef < T > { }
196+
124197pub trait BlockDeviceInterface : Send + Sync {
125198 fn block_size ( & self ) -> usize ;
126199
127200 fn read_dma ( & self , sector : usize , start : PhysAddr , size : usize ) -> Option < usize > ;
201+ fn write_dma ( & self , sector : usize , start : PhysAddr , size : usize ) -> Option < usize > ;
128202
129203 fn read_block ( & self , sector : usize , dest : & mut [ MaybeUninit < u8 > ] ) -> Option < usize > ;
130204 fn write_block ( & self , sector : usize , buf : & [ u8 ] ) -> Option < usize > ;
@@ -228,6 +302,10 @@ impl BlockDeviceInterface for BlockDevice {
228302 self . dev . read_dma ( sector, start, size)
229303 }
230304
305+ fn write_dma ( & self , sector : usize , start : PhysAddr , size : usize ) -> Option < usize > {
306+ self . dev . write_dma ( sector, start, size)
307+ }
308+
231309 fn read_block ( & self , sector : usize , dest : & mut [ MaybeUninit < u8 > ] ) -> Option < usize > {
232310 self . dev . read_block ( sector, dest)
233311 }
@@ -292,6 +370,14 @@ impl BlockDeviceInterface for PartitionBlockDevice {
292370 self . device . write_block ( self . offset + sector, buf)
293371 }
294372
373+ fn write_dma ( & self , sector : usize , start : PhysAddr , size : usize ) -> Option < usize > {
374+ if sector >= self . size {
375+ return None ;
376+ }
377+
378+ self . write_dma ( self . offset + sector, start, size)
379+ }
380+
295381 fn read_dma ( & self , sector : usize , start : PhysAddr , size : usize ) -> Option < usize > {
296382 if sector >= self . size {
297383 return None ;
0 commit comments