keos_project5/page_cache/
overlaying.rs

1//! An overlaying mechanism for appling page cache to any file system.
2
3use super::PageCache;
4use alloc::{string::String, vec::Vec};
5use keos::{
6    fs::{FileBlockNumber, InodeNumber, traits::FileSystem},
7    mm::Page,
8    sync::atomic::AtomicUsize,
9};
10
11/// An overlay on the Directory.
12pub struct Directory<FS: FileSystem + 'static>(keos::fs::Directory, PageCache<FS>);
13
14impl<FS: FileSystem> keos::fs::traits::Directory for Directory<FS> {
15    fn ino(&self) -> InodeNumber {
16        self.0.ino()
17    }
18
19    fn size(&self) -> usize {
20        self.0.size()
21    }
22
23    fn link_count(&self) -> usize {
24        self.0.link_count()
25    }
26
27    fn open_entry(&self, entry: &str) -> Result<keos::fs::File, keos::KernelError> {
28        self.0.open(entry).map(|en| match en {
29            keos::fs::File::RegularFile(r) => {
30                keos::fs::File::RegularFile(keos::fs::RegularFile::new(RegularFile {
31                    size: AtomicUsize::new(r.size()),
32                    file: r,
33                    cache: self.1.clone(),
34                }))
35            }
36            keos::fs::File::Directory(d) => {
37                keos::fs::File::Directory(keos::fs::Directory::new(Directory(d, self.1.clone())))
38            }
39        })
40    }
41
42    fn create_entry(&self, entry: &str, is_dir: bool) -> Result<keos::fs::File, keos::KernelError> {
43        self.0.create(entry, is_dir).map(|en| match en {
44            keos::fs::File::RegularFile(r) => {
45                keos::fs::File::RegularFile(keos::fs::RegularFile::new(RegularFile {
46                    size: AtomicUsize::new(r.size()),
47                    file: r,
48                    cache: self.1.clone(),
49                }))
50            }
51            keos::fs::File::Directory(d) => {
52                keos::fs::File::Directory(keos::fs::Directory::new(Directory(d, self.1.clone())))
53            }
54        })
55    }
56
57    fn unlink_entry(&self, entry: &str) -> Result<(), keos::KernelError> {
58        self.0.open(entry).map(|en| {
59            if let keos::fs::File::RegularFile(r) = en {
60                // Remove the slot from the cache
61                let mut guard = self.1.0.inner.lock();
62                guard.do_unlink(r);
63                guard.unlock();
64            }
65        })?;
66
67        self.0.unlink(entry)
68    }
69
70    fn read_dir(&self) -> Result<Vec<(InodeNumber, String)>, keos::KernelError> {
71        self.0.read_dir()
72    }
73
74    fn removed(&self) -> Result<&keos::sync::atomic::AtomicBool, keos::KernelError> {
75        self.0.removed()
76    }
77}
78
79/// An overlay on the RegularFile.
80pub struct RegularFile<FS: FileSystem> {
81    file: keos::fs::RegularFile,
82    size: AtomicUsize,
83    cache: PageCache<FS>,
84}
85
86impl<FS: FileSystem> keos::fs::traits::RegularFile for RegularFile<FS> {
87    fn ino(&self) -> InodeNumber {
88        self.file.0.ino()
89    }
90
91    fn size(&self) -> usize {
92        self.size.load()
93    }
94
95    fn read(&self, fba: FileBlockNumber, buf: &mut [u8; 4096]) -> Result<bool, keos::KernelError> {
96        self.cache.read(&self.file, fba, buf)
97    }
98
99    fn write(
100        &self,
101        fba: FileBlockNumber,
102        buf: &[u8; 4096],
103        min_size: usize,
104    ) -> Result<(), keos::KernelError> {
105        if self.size() < min_size {
106            self.size.store(min_size);
107            let mut guard = self.cache.0.inner.lock();
108            let result = guard.do_write(self.file.clone(), fba, buf, min_size);
109            guard.unlock();
110            result
111        } else {
112            let mut guard = self.cache.0.inner.lock();
113            let result = guard.do_write(self.file.clone(), fba, buf, self.size.load());
114            guard.unlock();
115            result
116        }
117    }
118
119    fn writeback(&self) -> Result<(), keos::KernelError> {
120        let mut guard = self.cache.0.inner.lock();
121        let result = guard.do_writeback(self.file.clone());
122        guard.unlock();
123        result
124    }
125
126    fn mmap(&self, fba: FileBlockNumber) -> Result<Page, keos::KernelError> {
127        let mut guard = self.cache.0.inner.lock();
128        let result = guard.do_mmap(self.file.clone(), fba);
129        guard.unlock();
130        result
131    }
132}
133
134impl<FS: FileSystem + 'static> FileSystem for PageCache<FS> {
135    fn root(&self) -> Option<keos::fs::Directory> {
136        self.0
137            .fs
138            .root()
139            .map(|n| keos::fs::Directory::new(Directory(n, Self(self.0.clone()))))
140    }
141}