tmpfs.rs 19 KB

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