tmpfs.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. use crate::{
  2. io::Buffer,
  3. kernel::constants::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFREG},
  4. kernel::vfs::{
  5. dentry::{dcache, Dentry},
  6. inode::{define_struct_inode, AtomicIno, Ino, Inode, Mode, WriteOffset},
  7. mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
  8. s_isblk, s_ischr,
  9. vfs::Vfs,
  10. DevId,
  11. },
  12. prelude::*,
  13. };
  14. use alloc::sync::{Arc, Weak};
  15. use bindings::{EINVAL, EIO, EISDIR};
  16. use core::{ops::ControlFlow, sync::atomic::Ordering};
  17. use eonix_runtime::task::Task;
  18. use eonix_sync::{AsProof as _, AsProofMut as _, Locked, ProofMut};
  19. use itertools::Itertools;
  20. fn acquire(vfs: &Weak<dyn Vfs>) -> KResult<Arc<dyn Vfs>> {
  21. vfs.upgrade().ok_or(EIO)
  22. }
  23. fn astmp(vfs: &Arc<dyn Vfs>) -> &TmpFs {
  24. vfs.as_any()
  25. .downcast_ref::<TmpFs>()
  26. .expect("corrupted tmpfs data structure")
  27. }
  28. define_struct_inode! {
  29. struct NodeInode {
  30. devid: DevId,
  31. }
  32. }
  33. impl NodeInode {
  34. fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode, devid: DevId) -> Arc<Self> {
  35. Self::new_locked(ino, vfs, |inode, _| unsafe {
  36. addr_of_mut_field!(inode, devid).write(devid);
  37. addr_of_mut_field!(inode, mode).write(mode.into());
  38. addr_of_mut_field!(inode, nlink).write(1.into());
  39. })
  40. }
  41. }
  42. impl Inode for NodeInode {
  43. fn devid(&self) -> KResult<DevId> {
  44. Ok(self.devid)
  45. }
  46. }
  47. define_struct_inode! {
  48. struct DirectoryInode {
  49. entries: Locked<Vec<(Arc<[u8]>, Ino)>, ()>,
  50. }
  51. }
  52. impl DirectoryInode {
  53. fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
  54. Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
  55. addr_of_mut_field!(inode, entries)
  56. .write(Locked::new(vec![(Arc::from(b".".as_slice()), ino)], rwsem));
  57. addr_of_mut_field!(inode, size).write(1.into());
  58. addr_of_mut_field!(inode, mode).write((S_IFDIR | (mode & 0o777)).into());
  59. addr_of_mut_field!(inode, nlink).write(1.into()); // link from `.` to itself
  60. })
  61. }
  62. fn link(&self, name: Arc<[u8]>, file: &dyn Inode, dlock: ProofMut<'_, ()>) {
  63. // SAFETY: Only `unlink` will do something based on `nlink` count
  64. // No need to synchronize here
  65. file.nlink.fetch_add(1, Ordering::Relaxed);
  66. // SAFETY: `rwsem` has done the synchronization
  67. self.size.fetch_add(1, Ordering::Relaxed);
  68. self.entries.access_mut(dlock).push((name, file.ino));
  69. }
  70. }
  71. impl Inode for DirectoryInode {
  72. fn do_readdir(
  73. &self,
  74. offset: usize,
  75. callback: &mut dyn FnMut(&[u8], Ino) -> KResult<ControlFlow<(), ()>>,
  76. ) -> KResult<usize> {
  77. let lock = Task::block_on(self.rwsem.read());
  78. self.entries
  79. .access(lock.prove())
  80. .iter()
  81. .skip(offset)
  82. .map(|(name, ino)| callback(&name, *ino))
  83. .take_while(|result| result.map_or(true, |flow| flow.is_continue()))
  84. .take_while_inclusive(|result| result.is_ok())
  85. .fold_ok(0, |acc, _| acc + 1)
  86. }
  87. fn creat(&self, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
  88. let vfs = acquire(&self.vfs)?;
  89. let vfs = astmp(&vfs);
  90. let rwsem = Task::block_on(self.rwsem.write());
  91. let ino = vfs.assign_ino();
  92. let file = FileInode::new(ino, self.vfs.clone(), mode);
  93. self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
  94. at.save_reg(file)
  95. }
  96. fn mknod(&self, at: &Dentry, mode: Mode, dev: DevId) -> KResult<()> {
  97. if !s_ischr(mode) && !s_isblk(mode) {
  98. return Err(EINVAL);
  99. }
  100. let vfs = acquire(&self.vfs)?;
  101. let vfs = astmp(&vfs);
  102. let rwsem = Task::block_on(self.rwsem.write());
  103. let ino = vfs.assign_ino();
  104. let file = NodeInode::new(
  105. ino,
  106. self.vfs.clone(),
  107. mode & (0o777 | S_IFBLK | S_IFCHR),
  108. dev,
  109. );
  110. self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
  111. at.save_reg(file)
  112. }
  113. fn symlink(&self, at: &Arc<Dentry>, target: &[u8]) -> KResult<()> {
  114. let vfs = acquire(&self.vfs)?;
  115. let vfs = astmp(&vfs);
  116. let rwsem = Task::block_on(self.rwsem.write());
  117. let ino = vfs.assign_ino();
  118. let file = SymlinkInode::new(ino, self.vfs.clone(), target.into());
  119. self.link(at.name().clone(), file.as_ref(), rwsem.prove_mut());
  120. at.save_symlink(file)
  121. }
  122. fn mkdir(&self, at: &Dentry, mode: Mode) -> KResult<()> {
  123. let vfs = acquire(&self.vfs)?;
  124. let vfs = astmp(&vfs);
  125. let rwsem = Task::block_on(self.rwsem.write());
  126. let ino = vfs.assign_ino();
  127. let newdir = DirectoryInode::new(ino, self.vfs.clone(), mode);
  128. self.link(at.name().clone(), newdir.as_ref(), rwsem.prove_mut());
  129. at.save_dir(newdir)
  130. }
  131. fn unlink(&self, at: &Arc<Dentry>) -> KResult<()> {
  132. let _vfs = acquire(&self.vfs)?;
  133. let dlock = Task::block_on(self.rwsem.write());
  134. let file = at.get_inode()?;
  135. let _flock = file.rwsem.write();
  136. // SAFETY: `flock` has done the synchronization
  137. if file.mode.load(Ordering::Relaxed) & S_IFDIR != 0 {
  138. return Err(EISDIR);
  139. }
  140. let entries = self.entries.access_mut(dlock.prove_mut());
  141. entries.retain(|(_, ino)| *ino != file.ino);
  142. assert_eq!(
  143. entries.len() as u64,
  144. // SAFETY: `dlock` has done the synchronization
  145. self.size.fetch_sub(1, Ordering::Relaxed) - 1
  146. );
  147. // SAFETY: `flock` has done the synchronization
  148. let file_nlink = file.nlink.fetch_sub(1, Ordering::Relaxed) - 1;
  149. if file_nlink == 0 {
  150. // Remove the file inode from the inode cache
  151. // The last reference to the inode is held by some dentry
  152. // and will be released when the dentry is released
  153. //
  154. // TODO: Should we use some inode cache in tmpfs?
  155. //
  156. // vfs.icache.lock().retain(|ino, _| *ino != file.ino);
  157. }
  158. // Postpone the invalidation of the dentry and inode until the
  159. // last reference to the dentry is released
  160. //
  161. // But we can remove it from the dentry cache immediately
  162. // so later lookup will fail with ENOENT
  163. dcache::d_remove(at);
  164. Ok(())
  165. }
  166. fn chmod(&self, mode: Mode) -> KResult<()> {
  167. let _vfs = acquire(&self.vfs)?;
  168. let _lock = Task::block_on(self.rwsem.write());
  169. // SAFETY: `rwsem` has done the synchronization
  170. let old = self.mode.load(Ordering::Relaxed);
  171. self.mode
  172. .store((old & !0o777) | (mode & 0o777), Ordering::Relaxed);
  173. Ok(())
  174. }
  175. }
  176. define_struct_inode! {
  177. struct SymlinkInode {
  178. target: Arc<[u8]>,
  179. }
  180. }
  181. impl SymlinkInode {
  182. fn new(ino: Ino, vfs: Weak<dyn Vfs>, target: Arc<[u8]>) -> Arc<Self> {
  183. Self::new_locked(ino, vfs, |inode, _| unsafe {
  184. let len = target.len();
  185. addr_of_mut_field!(inode, target).write(target);
  186. addr_of_mut_field!(inode, mode).write((S_IFLNK | 0o777).into());
  187. addr_of_mut_field!(inode, size).write((len as u64).into());
  188. })
  189. }
  190. }
  191. impl Inode for SymlinkInode {
  192. fn readlink(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  193. buffer
  194. .fill(self.target.as_ref())
  195. .map(|result| result.allow_partial())
  196. }
  197. fn chmod(&self, _: Mode) -> KResult<()> {
  198. Ok(())
  199. }
  200. }
  201. define_struct_inode! {
  202. struct FileInode {
  203. filedata: Locked<Vec<u8>, ()>,
  204. }
  205. }
  206. impl FileInode {
  207. fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
  208. Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
  209. addr_of_mut_field!(inode, filedata).write(Locked::new(vec![], rwsem));
  210. addr_of_mut_field!(inode, mode).write((S_IFREG | (mode & 0o777)).into());
  211. addr_of_mut_field!(inode, nlink).write(1.into());
  212. })
  213. }
  214. }
  215. impl Inode for FileInode {
  216. fn read(&self, buffer: &mut dyn Buffer, offset: usize) -> KResult<usize> {
  217. // TODO: We don't need that strong guarantee, find some way to avoid locks
  218. let lock = Task::block_on(self.rwsem.read());
  219. match self.filedata.access(lock.prove()).split_at_checked(offset) {
  220. Some((_, data)) => buffer.fill(data).map(|result| result.allow_partial()),
  221. None => Ok(0),
  222. }
  223. }
  224. fn write(&self, buffer: &[u8], offset: WriteOffset) -> KResult<usize> {
  225. // TODO: We don't need that strong guarantee, find some way to avoid locks
  226. let lock = Task::block_on(self.rwsem.write());
  227. let filedata = self.filedata.access_mut(lock.prove_mut());
  228. let offset = match offset {
  229. WriteOffset::Position(offset) => offset,
  230. // SAFETY: `lock` has done the synchronization
  231. WriteOffset::End(end) => {
  232. let size = self.size.load(Ordering::Relaxed) as usize;
  233. *end = size + buffer.len();
  234. size
  235. }
  236. };
  237. if filedata.len() < offset + buffer.len() {
  238. filedata.resize(offset + buffer.len(), 0);
  239. }
  240. filedata[offset..offset + buffer.len()].copy_from_slice(&buffer);
  241. // SAFETY: `lock` has done the synchronization
  242. self.size.store(filedata.len() as u64, Ordering::Relaxed);
  243. Ok(buffer.len())
  244. }
  245. fn truncate(&self, length: usize) -> KResult<()> {
  246. // TODO: We don't need that strong guarantee, find some way to avoid locks
  247. let lock = Task::block_on(self.rwsem.write());
  248. let filedata = self.filedata.access_mut(lock.prove_mut());
  249. // SAFETY: `lock` has done the synchronization
  250. self.size.store(length as u64, Ordering::Relaxed);
  251. filedata.resize(length, 0);
  252. Ok(())
  253. }
  254. fn chmod(&self, mode: Mode) -> KResult<()> {
  255. let _vfs = acquire(&self.vfs)?;
  256. let _lock = Task::block_on(self.rwsem.write());
  257. // SAFETY: `rwsem` has done the synchronization
  258. let old = self.mode.load(Ordering::Relaxed);
  259. self.mode
  260. .store((old & !0o777) | (mode & 0o777), Ordering::Relaxed);
  261. Ok(())
  262. }
  263. }
  264. impl_any!(TmpFs);
  265. struct TmpFs {
  266. next_ino: AtomicIno,
  267. readonly: bool,
  268. }
  269. impl Vfs for TmpFs {
  270. fn io_blksize(&self) -> usize {
  271. 4096
  272. }
  273. fn fs_devid(&self) -> DevId {
  274. 2
  275. }
  276. fn is_read_only(&self) -> bool {
  277. self.readonly
  278. }
  279. }
  280. impl TmpFs {
  281. fn assign_ino(&self) -> Ino {
  282. self.next_ino.fetch_add(1, Ordering::AcqRel)
  283. }
  284. pub fn create(readonly: bool) -> KResult<(Arc<dyn Vfs>, Arc<dyn Inode>)> {
  285. let tmpfs = Arc::new(Self {
  286. next_ino: AtomicIno::new(1),
  287. readonly,
  288. });
  289. let weak = Arc::downgrade(&tmpfs);
  290. let root_dir = DirectoryInode::new(0, weak, 0o755);
  291. Ok((tmpfs, root_dir))
  292. }
  293. }
  294. struct TmpFsMountCreator;
  295. impl MountCreator for TmpFsMountCreator {
  296. fn create_mount(&self, _source: &str, flags: u64, mp: &Arc<Dentry>) -> KResult<Mount> {
  297. let (fs, root_inode) = TmpFs::create(flags & MS_RDONLY != 0)?;
  298. Mount::new(mp, fs, root_inode)
  299. }
  300. }
  301. pub fn init() {
  302. register_filesystem("tmpfs", Arc::new(TmpFsMountCreator)).unwrap();
  303. }