tmpfs.rs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. use core::sync::atomic::Ordering;
  2. use crate::{
  3. io::Buffer,
  4. kernel::vfs::{
  5. dentry::Dentry,
  6. inode::{AtomicIno, Ino, Inode, InodeCache, InodeOps, Mode},
  7. mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
  8. s_isblk, s_ischr,
  9. vfs::Vfs,
  10. DevId, ReadDirCallback,
  11. },
  12. prelude::*,
  13. };
  14. use alloc::sync::Arc;
  15. use bindings::{
  16. EINVAL, EIO, EISDIR, EROFS, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFREG,
  17. };
  18. struct FileOps {
  19. data: Mutex<Vec<u8>>,
  20. }
  21. struct NodeOps {
  22. devid: DevId,
  23. }
  24. impl NodeOps {
  25. fn new(devid: DevId) -> Self {
  26. Self { devid }
  27. }
  28. }
  29. impl InodeOps for NodeOps {
  30. fn as_any(&self) -> &dyn Any {
  31. self
  32. }
  33. fn devid(&self, _: &Inode) -> KResult<DevId> {
  34. Ok(self.devid)
  35. }
  36. }
  37. struct DirectoryOps {
  38. entries: Mutex<Vec<(Arc<[u8]>, Ino)>>,
  39. }
  40. impl DirectoryOps {
  41. fn new() -> Self {
  42. Self {
  43. entries: Mutex::new(vec![]),
  44. }
  45. }
  46. /// Locks the `inode.idata`
  47. fn link(&self, dir: &Inode, file: &Inode, name: Arc<[u8]>) -> KResult<()> {
  48. dir.idata.lock().size += 1;
  49. self.entries.lock().push((name, file.ino));
  50. file.idata.lock().nlink += 1;
  51. Ok(())
  52. }
  53. }
  54. impl InodeOps for DirectoryOps {
  55. fn as_any(&self) -> &dyn Any {
  56. self
  57. }
  58. fn readdir<'cb, 'r: 'cb>(
  59. &self,
  60. _: &Inode,
  61. offset: usize,
  62. callback: &ReadDirCallback<'cb>,
  63. ) -> KResult<usize> {
  64. Ok(self
  65. .entries
  66. .lock()
  67. .iter()
  68. .skip(offset)
  69. .take_while(|(name, ino)| callback(name, *ino).is_ok())
  70. .count())
  71. }
  72. fn creat(&self, dir: &Inode, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
  73. let vfs = dir.vfs.upgrade().ok_or(EIO)?;
  74. let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
  75. if vfs.readonly {
  76. return Err(EROFS);
  77. }
  78. let ino = vfs.assign_ino();
  79. let file = vfs.icache.lock().alloc_file(ino, mode)?;
  80. self.link(dir, file.as_ref(), at.name().clone())?;
  81. at.save_reg(file)
  82. }
  83. fn mknod(
  84. &self,
  85. dir: &Inode,
  86. at: &Arc<Dentry>,
  87. mode: Mode,
  88. dev: DevId,
  89. ) -> KResult<()> {
  90. let vfs = dir.vfs.upgrade().ok_or(EIO)?;
  91. let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
  92. if vfs.readonly {
  93. return Err(EROFS);
  94. }
  95. if !s_ischr(mode) && !s_isblk(mode) {
  96. return Err(EINVAL);
  97. }
  98. let ino = vfs.assign_ino();
  99. let mut icache = vfs.icache.lock();
  100. let file = icache.alloc(ino, Box::new(NodeOps::new(dev)));
  101. file.idata.lock().mode = mode & (0o777 | S_IFBLK | S_IFCHR);
  102. icache.submit(&file)?;
  103. self.link(dir, file.as_ref(), at.name().clone())?;
  104. at.save_reg(file)
  105. }
  106. fn symlink(
  107. &self,
  108. dir: &Inode,
  109. at: &Arc<Dentry>,
  110. target: &[u8],
  111. ) -> KResult<()> {
  112. let vfs = dir.vfs.upgrade().ok_or(EIO)?;
  113. let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
  114. if vfs.readonly {
  115. return Err(EROFS);
  116. }
  117. let ino = vfs.assign_ino();
  118. let mut icache = vfs.icache.lock();
  119. let target_len = target.len() as u64;
  120. let file =
  121. icache.alloc(ino, Box::new(SymlinkOps::new(Arc::from(target))));
  122. {
  123. let mut idata = file.idata.lock();
  124. idata.mode = S_IFLNK | 0o777;
  125. idata.size = target_len;
  126. }
  127. icache.submit(&file)?;
  128. self.link(dir, file.as_ref(), at.name().clone())?;
  129. at.save_symlink(file)
  130. }
  131. fn mkdir(&self, dir: &Inode, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
  132. let vfs = dir.vfs.upgrade().ok_or(EIO)?;
  133. let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
  134. if vfs.readonly {
  135. return Err(EROFS);
  136. }
  137. let ino = vfs.assign_ino();
  138. let mut icache = vfs.icache.lock();
  139. let mut newdir_ops = DirectoryOps::new();
  140. let entries = newdir_ops.entries.get_mut();
  141. entries.push((Arc::from(b".".as_slice()), ino));
  142. entries.push((Arc::from(b"..".as_slice()), dir.ino));
  143. let newdir = icache.alloc(ino, Box::new(newdir_ops));
  144. {
  145. let mut newdir_idata = newdir.idata.lock();
  146. newdir_idata.mode = S_IFDIR | (mode & 0o777);
  147. newdir_idata.nlink = 1;
  148. newdir_idata.size = 2;
  149. }
  150. icache.submit(&newdir)?;
  151. dir.idata.lock().nlink += 1; // link from `newdir` to `dir`, (or parent)
  152. self.link(dir, newdir.as_ref(), at.name().clone())?;
  153. at.save_dir(newdir)
  154. }
  155. fn unlink(&self, dir: &Inode, at: &Arc<Dentry>) -> KResult<()> {
  156. let vfs = dir.vfs.upgrade().ok_or(EIO)?;
  157. let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
  158. if vfs.readonly {
  159. return Err(EROFS);
  160. }
  161. let file = at.get_inode()?;
  162. let mut file_idata = file.idata.lock();
  163. if file_idata.mode & S_IFDIR != 0 {
  164. return Err(EISDIR);
  165. }
  166. let mut self_idata = dir.idata.lock();
  167. let mut entries = self.entries.lock();
  168. let idx = entries
  169. .iter()
  170. .position(|(_, ino)| *ino == file.ino)
  171. .expect("file not found in directory");
  172. self_idata.size -= 1;
  173. file_idata.nlink -= 1;
  174. entries.remove(idx);
  175. at.invalidate()
  176. }
  177. }
  178. struct SymlinkOps {
  179. target: Arc<[u8]>,
  180. }
  181. impl SymlinkOps {
  182. fn new(target: Arc<[u8]>) -> Self {
  183. Self { target }
  184. }
  185. }
  186. impl InodeOps for SymlinkOps {
  187. fn as_any(&self) -> &dyn Any {
  188. self
  189. }
  190. fn readlink(&self, _: &Inode, buffer: &mut dyn Buffer) -> KResult<usize> {
  191. buffer
  192. .fill(self.target.as_ref())
  193. .map(|result| result.allow_partial())
  194. }
  195. }
  196. impl FileOps {
  197. fn new() -> Self {
  198. Self {
  199. data: Mutex::new(vec![]),
  200. }
  201. }
  202. }
  203. impl InodeOps for FileOps {
  204. fn as_any(&self) -> &dyn Any {
  205. self
  206. }
  207. fn read(
  208. &self,
  209. _: &Inode,
  210. buffer: &mut dyn Buffer,
  211. offset: usize,
  212. ) -> KResult<usize> {
  213. let data = self.data.lock();
  214. let data = data.split_at_checked(offset).ok_or(EINVAL)?.1;
  215. buffer.fill(data).map(|result| result.allow_partial())
  216. }
  217. fn write(
  218. &self,
  219. inode: &Inode,
  220. buffer: &[u8],
  221. offset: usize,
  222. ) -> KResult<usize> {
  223. let mut idata = inode.idata.lock();
  224. let mut data = self.data.lock();
  225. if data.len() < offset + buffer.len() {
  226. data.resize(offset + buffer.len(), 0);
  227. }
  228. data[offset..offset + buffer.len()].copy_from_slice(&buffer);
  229. idata.size = data.len() as u64;
  230. Ok(buffer.len())
  231. }
  232. fn truncate(&self, inode: &Inode, length: usize) -> KResult<()> {
  233. let mut idata = inode.idata.lock();
  234. idata.size = length as u64;
  235. self.data.lock().resize(length, 0);
  236. Ok(())
  237. }
  238. }
  239. /// # Lock order
  240. /// `vfs` -> `icache` -> `idata` -> `*ops`.`*data`
  241. struct TmpFs {
  242. icache: Mutex<InodeCache<TmpFs>>,
  243. next_ino: AtomicIno,
  244. readonly: bool,
  245. }
  246. impl InodeCache<TmpFs> {
  247. fn alloc_file(&mut self, ino: Ino, mode: Mode) -> KResult<Arc<Inode>> {
  248. let file = self.alloc(ino, Box::new(FileOps::new()));
  249. file.idata.lock().mode = S_IFREG | (mode & 0o777);
  250. self.submit(&file)?;
  251. Ok(file)
  252. }
  253. }
  254. impl TmpFs {
  255. fn assign_ino(&self) -> Ino {
  256. self.next_ino.fetch_add(1, Ordering::SeqCst)
  257. }
  258. pub fn create(readonly: bool) -> KResult<(Arc<TmpFs>, Arc<Inode>)> {
  259. let tmpfs = Arc::new_cyclic(|weak| Self {
  260. icache: Mutex::new(InodeCache::new(weak.clone())),
  261. next_ino: AtomicIno::new(1),
  262. readonly,
  263. });
  264. let mut dir = DirectoryOps::new();
  265. let entries = dir.entries.get_mut();
  266. entries.push((Arc::from(b".".as_slice()), 0));
  267. entries.push((Arc::from(b"..".as_slice()), 0));
  268. let root_dir = {
  269. let mut icache = tmpfs.icache.lock();
  270. let root_dir = icache.alloc(0, Box::new(dir));
  271. {
  272. let mut idata = root_dir.idata.lock();
  273. idata.mode = S_IFDIR | 0o755;
  274. idata.nlink = 2;
  275. idata.size = 2;
  276. }
  277. icache.submit(&root_dir)?;
  278. root_dir
  279. };
  280. Ok((tmpfs, root_dir))
  281. }
  282. }
  283. impl Vfs for TmpFs {
  284. fn io_blksize(&self) -> usize {
  285. 4096
  286. }
  287. fn fs_devid(&self) -> DevId {
  288. 2
  289. }
  290. fn as_any(&self) -> &dyn Any {
  291. self
  292. }
  293. }
  294. struct TmpFsMountCreator;
  295. impl MountCreator for TmpFsMountCreator {
  296. fn create_mount(
  297. &self,
  298. _source: &str,
  299. flags: u64,
  300. _data: &[u8],
  301. mp: &Arc<Dentry>,
  302. ) -> KResult<Mount> {
  303. let (fs, root_inode) = TmpFs::create(flags & MS_RDONLY != 0)?;
  304. Mount::new(mp, fs, root_inode)
  305. }
  306. }
  307. pub fn init() {
  308. register_filesystem("tmpfs", Box::new(TmpFsMountCreator)).unwrap();
  309. }