tmpfs.rs 10 KB

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