tmpfs.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. use crate::io::Stream;
  2. use crate::kernel::constants::{EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR};
  3. use crate::kernel::mem::{CachePage, CachePageStream, PageCache, PageCacheBackend};
  4. use crate::kernel::task::block_on;
  5. use crate::kernel::timer::Instant;
  6. use crate::kernel::vfs::inode::RenameData;
  7. use crate::kernel::vfs::inode::{AtomicMode, InodeData};
  8. use crate::{
  9. io::Buffer,
  10. kernel::vfs::{
  11. dentry::{dcache, Dentry},
  12. inode::{define_struct_inode, AtomicIno, Ino, Inode, Mode, WriteOffset},
  13. mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
  14. vfs::Vfs,
  15. DevId,
  16. },
  17. prelude::*,
  18. };
  19. use alloc::sync::{Arc, Weak};
  20. use core::fmt::Debug;
  21. use core::{ops::ControlFlow, sync::atomic::Ordering};
  22. use eonix_mm::paging::PAGE_SIZE;
  23. use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Mutex, ProofMut};
  24. use itertools::Itertools;
  25. fn acquire(vfs: &Weak<dyn Vfs>) -> KResult<Arc<dyn Vfs>> {
  26. vfs.upgrade().ok_or(EIO)
  27. }
  28. fn astmp(vfs: &Arc<dyn Vfs>) -> &TmpFs {
  29. vfs.as_any()
  30. .downcast_ref::<TmpFs>()
  31. .expect("corrupted tmpfs data structure")
  32. }
  33. define_struct_inode! {
  34. struct NodeInode {
  35. devid: DevId,
  36. }
  37. }
  38. impl NodeInode {
  39. fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode, devid: DevId) -> Arc<Self> {
  40. Self::new_locked(ino, vfs, |inode, _| unsafe {
  41. addr_of_mut_field!(inode, devid).write(devid);
  42. addr_of_mut_field!(&mut *inode, mode).write(AtomicMode::from(mode));
  43. addr_of_mut_field!(&mut *inode, nlink).write(1.into());
  44. addr_of_mut_field!(&mut *inode, ctime).write(Spin::new(Instant::now()));
  45. addr_of_mut_field!(&mut *inode, mtime).write(Spin::new(Instant::now()));
  46. addr_of_mut_field!(&mut *inode, atime).write(Spin::new(Instant::now()));
  47. })
  48. }
  49. }
  50. impl Inode for NodeInode {
  51. fn devid(&self) -> KResult<DevId> {
  52. Ok(self.devid)
  53. }
  54. }
  55. define_struct_inode! {
  56. pub(super) struct DirectoryInode {
  57. entries: Locked<Vec<(Arc<[u8]>, Ino)>, ()>,
  58. }
  59. }
  60. impl DirectoryInode {
  61. fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
  62. Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
  63. addr_of_mut_field!(inode, entries)
  64. .write(Locked::new(vec![(Arc::from(b".".as_slice()), ino)], rwsem));
  65. addr_of_mut_field!(&mut *inode, size).write(1.into());
  66. addr_of_mut_field!(&mut *inode, mode)
  67. .write(AtomicMode::from(Mode::DIR.perm(mode.non_format_bits())));
  68. addr_of_mut_field!(&mut *inode, nlink).write(1.into()); // link from `.` to itself
  69. addr_of_mut_field!(&mut *inode, ctime).write(Spin::new(Instant::now()));
  70. addr_of_mut_field!(&mut *inode, mtime).write(Spin::new(Instant::now()));
  71. addr_of_mut_field!(&mut *inode, atime).write(Spin::new(Instant::now()));
  72. })
  73. }
  74. fn link(&self, name: Arc<[u8]>, file: &dyn Inode, dlock: ProofMut<'_, ()>) {
  75. let now = Instant::now();
  76. // SAFETY: Only `unlink` will do something based on `nlink` count
  77. // No need to synchronize here
  78. file.nlink.fetch_add(1, Ordering::Relaxed);
  79. *self.ctime.lock() = now;
  80. // SAFETY: `rwsem` has done the synchronization
  81. self.size.fetch_add(1, Ordering::Relaxed);
  82. *self.mtime.lock() = now;
  83. self.entries.access_mut(dlock).push((name, file.ino));
  84. }
  85. fn do_unlink(
  86. &self,
  87. file: &Arc<dyn Inode>,
  88. filename: &[u8],
  89. entries: &mut Vec<(Arc<[u8]>, Ino)>,
  90. now: Instant,
  91. decrease_size: bool,
  92. _dir_lock: ProofMut<()>,
  93. _file_lock: ProofMut<()>,
  94. ) -> KResult<()> {
  95. // SAFETY: `file_lock` has done the synchronization
  96. if file.mode.load().is_dir() {
  97. return Err(EISDIR);
  98. }
  99. entries.retain(|(name, ino)| *ino != file.ino || name.as_ref() != filename);
  100. if decrease_size {
  101. // SAFETY: `dir_lock` has done the synchronization
  102. self.size.fetch_sub(1, Ordering::Relaxed);
  103. }
  104. *self.mtime.lock() = now;
  105. // The last reference to the inode is held by some dentry
  106. // and will be released when the dentry is released
  107. // SAFETY: `file_lock` has done the synchronization
  108. file.nlink.fetch_sub(1, Ordering::Relaxed);
  109. *file.ctime.lock() = now;
  110. Ok(())
  111. }
  112. }
  113. impl Inode for DirectoryInode {
  114. fn do_readdir(
  115. &self,
  116. offset: usize,
  117. callback: &mut dyn FnMut(&[u8], Ino) -> KResult<ControlFlow<(), ()>>,
  118. ) -> KResult<usize> {
  119. let lock = block_on(self.rwsem.read());
  120. self.entries
  121. .access(lock.prove())
  122. .iter()
  123. .skip(offset)
  124. .map(|(name, ino)| callback(&name, *ino))
  125. .take_while(|result| result.map_or(true, |flow| flow.is_continue()))
  126. .take_while_inclusive(|result| result.is_ok())
  127. .fold_ok(0, |acc, _| acc + 1)
  128. }
  129. fn creat(&self, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
  130. let vfs = acquire(&self.vfs)?;
  131. let vfs = astmp(&vfs);
  132. let rwsem = block_on(self.rwsem.write());
  133. let ino = vfs.assign_ino();
  134. let file = FileInode::new(ino, self.vfs.clone(), 0, mode);
  135. self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
  136. at.save_reg(file)
  137. }
  138. fn mknod(&self, at: &Dentry, mode: Mode, dev: DevId) -> KResult<()> {
  139. if !mode.is_chr() && !mode.is_blk() {
  140. return Err(EINVAL);
  141. }
  142. let vfs = acquire(&self.vfs)?;
  143. let vfs = astmp(&vfs);
  144. let rwsem = block_on(self.rwsem.write());
  145. let ino = vfs.assign_ino();
  146. let file = NodeInode::new(ino, self.vfs.clone(), mode, dev);
  147. self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
  148. at.save_reg(file)
  149. }
  150. fn symlink(&self, at: &Arc<Dentry>, target: &[u8]) -> KResult<()> {
  151. let vfs = acquire(&self.vfs)?;
  152. let vfs = astmp(&vfs);
  153. let rwsem = block_on(self.rwsem.write());
  154. let ino = vfs.assign_ino();
  155. let file = SymlinkInode::new(ino, self.vfs.clone(), target.into());
  156. self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
  157. at.save_symlink(file)
  158. }
  159. fn mkdir(&self, at: &Dentry, mode: Mode) -> KResult<()> {
  160. let vfs = acquire(&self.vfs)?;
  161. let vfs = astmp(&vfs);
  162. let rwsem = block_on(self.rwsem.write());
  163. let ino = vfs.assign_ino();
  164. let newdir = DirectoryInode::new(ino, self.vfs.clone(), mode);
  165. self.link(at.get_name(), newdir.as_ref(), rwsem.prove_mut());
  166. at.save_dir(newdir)
  167. }
  168. fn unlink(&self, at: &Arc<Dentry>) -> KResult<()> {
  169. let _vfs = acquire(&self.vfs)?;
  170. let dir_lock = block_on(self.rwsem.write());
  171. let file = at.get_inode()?;
  172. let filename = at.get_name();
  173. let file_lock = block_on(file.rwsem.write());
  174. let entries = self.entries.access_mut(dir_lock.prove_mut());
  175. self.do_unlink(
  176. &file,
  177. &filename,
  178. entries,
  179. Instant::now(),
  180. true,
  181. dir_lock.prove_mut(),
  182. file_lock.prove_mut(),
  183. )?;
  184. // Remove the dentry from the dentry cache immediately
  185. // so later lookup will fail with ENOENT
  186. dcache::d_remove(at);
  187. Ok(())
  188. }
  189. fn chmod(&self, mode: Mode) -> KResult<()> {
  190. let _vfs = acquire(&self.vfs)?;
  191. let _lock = block_on(self.rwsem.write());
  192. // SAFETY: `rwsem` has done the synchronization
  193. let old = self.mode.load();
  194. self.mode.store(old.perm(mode.non_format_bits()));
  195. *self.ctime.lock() = Instant::now();
  196. Ok(())
  197. }
  198. fn rename(&self, rename_data: RenameData) -> KResult<()> {
  199. let RenameData {
  200. old_dentry,
  201. new_dentry,
  202. new_parent,
  203. is_exchange,
  204. no_replace,
  205. vfs,
  206. } = rename_data;
  207. if is_exchange {
  208. println_warn!("TmpFs does not support exchange rename for now");
  209. return Err(ENOSYS);
  210. }
  211. let vfs = vfs
  212. .as_any()
  213. .downcast_ref::<TmpFs>()
  214. .expect("vfs must be a TmpFs");
  215. let _rename_lock = block_on(vfs.rename_lock.lock());
  216. let old_file = old_dentry.get_inode()?;
  217. let new_file = new_dentry.get_inode();
  218. if no_replace && new_file.is_ok() {
  219. return Err(EEXIST);
  220. }
  221. let same_parent = Arc::as_ptr(&new_parent) == &raw const *self;
  222. if same_parent {
  223. // Same directory rename
  224. // Remove from old location and add to new location
  225. let parent_lock = block_on(self.rwsem.write());
  226. let entries = self.entries.access_mut(parent_lock.prove_mut());
  227. fn rename_old(
  228. old_entry: &mut (Arc<[u8]>, Ino),
  229. old_file: &Arc<dyn Inode + 'static>,
  230. new_dentry: &Arc<Dentry>,
  231. now: Instant,
  232. ) {
  233. let (name, _) = old_entry;
  234. *name = new_dentry.get_name();
  235. *old_file.ctime.lock() = now;
  236. }
  237. let old_ino = old_file.ino;
  238. let new_ino = new_file.as_ref().ok().map(|f| f.ino);
  239. let old_name = old_dentry.get_name();
  240. let new_name = new_dentry.get_name();
  241. // Find the old and new entries in the directory after we've locked the directory.
  242. let indices =
  243. entries
  244. .iter()
  245. .enumerate()
  246. .fold([None, None], |[old, new], (idx, (name, ino))| {
  247. if Some(*ino) == new_ino && *name == new_name {
  248. [old, Some(idx)]
  249. } else if *ino == old_ino && *name == old_name {
  250. [Some(idx), new]
  251. } else {
  252. [old, new]
  253. }
  254. });
  255. let (old_entry_idx, new_entry_idx) = match indices {
  256. [None, ..] => return Err(ENOENT),
  257. [Some(old_idx), new_idx] => (old_idx, new_idx),
  258. };
  259. let now = Instant::now();
  260. if let Some(new_idx) = new_entry_idx {
  261. // Replace existing file (i.e. rename the old and unlink the new)
  262. let new_file = new_file.unwrap();
  263. let _new_file_lock = block_on(new_file.rwsem.write());
  264. // SAFETY: `new_file_lock` has done the synchronization
  265. match (new_file.mode.load(), old_file.mode.load()) {
  266. (Mode::DIR, _) => return Err(EISDIR),
  267. (_, Mode::DIR) => return Err(ENOTDIR),
  268. _ => {}
  269. }
  270. entries.remove(new_idx);
  271. // SAFETY: `parent_lock` has done the synchronization
  272. self.size.fetch_sub(1, Ordering::Relaxed);
  273. // The last reference to the inode is held by some dentry
  274. // and will be released when the dentry is released
  275. // SAFETY: `new_file_lock` has done the synchronization
  276. new_file.nlink.fetch_sub(1, Ordering::Relaxed);
  277. *new_file.ctime.lock() = now;
  278. }
  279. rename_old(&mut entries[old_entry_idx], &old_file, new_dentry, now);
  280. *self.mtime.lock() = now;
  281. } else {
  282. // Cross-directory rename - handle similar to same directory case
  283. // Get new parent directory
  284. let new_parent_inode = new_dentry.parent().get_inode()?;
  285. assert!(new_parent_inode.is_dir());
  286. let new_parent = (new_parent_inode.as_ref() as &dyn Any)
  287. .downcast_ref::<DirectoryInode>()
  288. .expect("new parent must be a DirectoryInode");
  289. let old_parent_lock = block_on(self.rwsem.write());
  290. let new_parent_lock = block_on(new_parent_inode.rwsem.write());
  291. let old_ino = old_file.ino;
  292. let new_ino = new_file.as_ref().ok().map(|f| f.ino);
  293. let old_name = old_dentry.get_name();
  294. let new_name = new_dentry.get_name();
  295. // Find the old entry in the old directory
  296. let old_entries = self.entries.access_mut(old_parent_lock.prove_mut());
  297. let old_pos = old_entries
  298. .iter()
  299. .position(|(name, ino)| *ino == old_ino && *name == old_name)
  300. .ok_or(ENOENT)?;
  301. // Find the new entry in the new directory (if it exists)
  302. let new_entries = new_parent.entries.access_mut(new_parent_lock.prove_mut());
  303. let has_new = new_entries
  304. .iter()
  305. .position(|(name, ino)| Some(*ino) == new_ino && *name == new_name)
  306. .is_some();
  307. let now = Instant::now();
  308. if has_new {
  309. // Replace existing file (i.e. move the old and unlink the new)
  310. let new_file = new_file.unwrap();
  311. let new_file_lock = block_on(new_file.rwsem.write());
  312. match (old_file.mode.load(), new_file.mode.load()) {
  313. (Mode::DIR, Mode::DIR) => {}
  314. (Mode::DIR, _) => return Err(ENOTDIR),
  315. (_, _) => {}
  316. }
  317. // Unlink the old file that was replaced
  318. new_parent.do_unlink(
  319. &new_file,
  320. &new_name,
  321. new_entries,
  322. now,
  323. false,
  324. new_parent_lock.prove_mut(),
  325. new_file_lock.prove_mut(),
  326. )?;
  327. } else {
  328. new_parent.size.fetch_add(1, Ordering::Relaxed);
  329. }
  330. // Remove from old directory
  331. old_entries.remove(old_pos);
  332. // Add new entry
  333. new_entries.push((new_name, old_ino));
  334. self.size.fetch_sub(1, Ordering::Relaxed);
  335. *self.mtime.lock() = now;
  336. *old_file.ctime.lock() = now;
  337. }
  338. block_on(dcache::d_exchange(old_dentry, new_dentry));
  339. Ok(())
  340. }
  341. }
  342. define_struct_inode! {
  343. struct SymlinkInode {
  344. target: Arc<[u8]>,
  345. }
  346. }
  347. impl SymlinkInode {
  348. fn new(ino: Ino, vfs: Weak<dyn Vfs>, target: Arc<[u8]>) -> Arc<Self> {
  349. Self::new_locked(ino, vfs, |inode, _| unsafe {
  350. let len = target.len();
  351. addr_of_mut_field!(inode, target).write(target);
  352. addr_of_mut_field!(&mut *inode, mode).write(AtomicMode::from(Mode::LNK.perm(0o777)));
  353. addr_of_mut_field!(&mut *inode, size).write((len as u64).into());
  354. addr_of_mut_field!(&mut *inode, ctime).write(Spin::new(Instant::now()));
  355. addr_of_mut_field!(&mut *inode, mtime).write(Spin::new(Instant::now()));
  356. addr_of_mut_field!(&mut *inode, atime).write(Spin::new(Instant::now()));
  357. })
  358. }
  359. }
  360. impl Inode for SymlinkInode {
  361. fn readlink(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  362. buffer
  363. .fill(self.target.as_ref())
  364. .map(|result| result.allow_partial())
  365. }
  366. fn chmod(&self, _: Mode) -> KResult<()> {
  367. Ok(())
  368. }
  369. }
  370. define_struct_inode! {
  371. pub struct FileInode {
  372. pages: PageCache,
  373. }
  374. }
  375. impl Debug for FileInode {
  376. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  377. write!(f, "FileInode({:?})", self.idata)
  378. }
  379. }
  380. impl FileInode {
  381. pub fn new(ino: Ino, vfs: Weak<dyn Vfs>, size: usize, mode: Mode) -> Arc<Self> {
  382. let inode = Arc::new_cyclic(|weak_self: &Weak<FileInode>| FileInode {
  383. idata: InodeData::new(ino, vfs),
  384. pages: PageCache::new(weak_self.clone()),
  385. });
  386. inode.mode.store(Mode::REG.perm(mode.non_format_bits()));
  387. inode.nlink.store(1, Ordering::Relaxed);
  388. inode.size.store(size as u64, Ordering::Relaxed);
  389. inode
  390. }
  391. }
  392. impl PageCacheBackend for FileInode {
  393. fn read_page(&self, _cache_page: &mut CachePage, _offset: usize) -> KResult<usize> {
  394. Ok(PAGE_SIZE)
  395. }
  396. fn write_page(&self, _page: &mut CachePageStream, _offset: usize) -> KResult<usize> {
  397. Ok(PAGE_SIZE)
  398. }
  399. fn size(&self) -> usize {
  400. self.size.load(Ordering::Relaxed) as usize
  401. }
  402. }
  403. impl Inode for FileInode {
  404. fn page_cache(&self) -> Option<&PageCache> {
  405. Some(&self.pages)
  406. }
  407. fn read(&self, buffer: &mut dyn Buffer, offset: usize) -> KResult<usize> {
  408. let _lock = block_on(self.rwsem.write());
  409. block_on(self.pages.read(buffer, offset))
  410. }
  411. fn write(&self, stream: &mut dyn Stream, offset: WriteOffset) -> KResult<usize> {
  412. // TODO: We don't need that strong guarantee, find some way to avoid locks
  413. let _lock = block_on(self.rwsem.write());
  414. let mut store_new_end = None;
  415. let offset = match offset {
  416. WriteOffset::Position(offset) => offset,
  417. WriteOffset::End(end) => {
  418. store_new_end = Some(end);
  419. // SAFETY: `lock` has done the synchronization
  420. self.size.load(Ordering::Relaxed) as usize
  421. }
  422. };
  423. let wrote = block_on(self.pages.write(stream, offset))?;
  424. let cursor_end = offset + wrote;
  425. if let Some(store_end) = store_new_end {
  426. *store_end = cursor_end;
  427. }
  428. // SAFETY: `lock` has done the synchronization
  429. *self.mtime.lock() = Instant::now();
  430. self.size.store(cursor_end as u64, Ordering::Relaxed);
  431. Ok(wrote)
  432. }
  433. fn truncate(&self, length: usize) -> KResult<()> {
  434. let _lock = block_on(self.rwsem.write());
  435. block_on(self.pages.resize(length))?;
  436. self.size.store(length as u64, Ordering::Relaxed);
  437. *self.mtime.lock() = Instant::now();
  438. Ok(())
  439. }
  440. fn chmod(&self, mode: Mode) -> KResult<()> {
  441. let _vfs = acquire(&self.vfs)?;
  442. let _lock = block_on(self.rwsem.write());
  443. // SAFETY: `rwsem` has done the synchronization
  444. let old = self.mode.load();
  445. self.mode.store(old.perm(mode.non_format_bits()));
  446. *self.ctime.lock() = Instant::now();
  447. Ok(())
  448. }
  449. }
  450. impl_any!(TmpFs);
  451. pub(super) struct TmpFs {
  452. next_ino: AtomicIno,
  453. readonly: bool,
  454. rename_lock: Mutex<()>,
  455. }
  456. impl Vfs for TmpFs {
  457. fn io_blksize(&self) -> usize {
  458. 4096
  459. }
  460. fn fs_devid(&self) -> DevId {
  461. 2
  462. }
  463. fn is_read_only(&self) -> bool {
  464. self.readonly
  465. }
  466. }
  467. impl TmpFs {
  468. pub(super) fn assign_ino(&self) -> Ino {
  469. self.next_ino.fetch_add(1, Ordering::AcqRel)
  470. }
  471. pub fn create(readonly: bool) -> KResult<(Arc<TmpFs>, Arc<DirectoryInode>)> {
  472. let tmpfs = Arc::new(Self {
  473. next_ino: AtomicIno::new(1),
  474. readonly,
  475. rename_lock: Mutex::new(()),
  476. });
  477. let weak = Arc::downgrade(&tmpfs);
  478. let root_dir = DirectoryInode::new(0, weak, Mode::new(0o755));
  479. Ok((tmpfs, root_dir))
  480. }
  481. }
  482. struct TmpFsMountCreator;
  483. impl MountCreator for TmpFsMountCreator {
  484. fn create_mount(&self, _source: &str, flags: u64, mp: &Arc<Dentry>) -> KResult<Mount> {
  485. let (fs, root_inode) = TmpFs::create(flags & MS_RDONLY != 0)?;
  486. Mount::new(mp, fs, root_inode)
  487. }
  488. fn check_signature(&self, _: &[u8]) -> KResult<bool> {
  489. Ok(true)
  490. }
  491. }
  492. pub fn init() {
  493. register_filesystem("tmpfs", Arc::new(TmpFsMountCreator)).unwrap();
  494. }