tmpfs.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. use crate::{
  2. io::copy_offset_count,
  3. kernel::vfs::{
  4. dentry::Dentry,
  5. inode::{Ino, Inode, InodeCache, InodeData, Mode},
  6. mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
  7. s_isblk, s_ischr,
  8. vfs::Vfs,
  9. DevId, ReadDirCallback, TimeSpec,
  10. },
  11. prelude::*,
  12. };
  13. use alloc::sync::{Arc, Weak};
  14. use bindings::{
  15. fs::{D_DIRECTORY, D_LOADED, D_PRESENT, D_SYMLINK},
  16. EINVAL, EIO, EISDIR, ENODEV, ENOTDIR, EROFS, S_IFBLK, S_IFCHR, S_IFDIR,
  17. S_IFLNK, S_IFREG,
  18. };
  19. type TmpFsFile = Vec<u8>;
  20. type TmpFsDirectory = Vec<(Ino, String)>;
  21. enum TmpFsData {
  22. File(TmpFsFile),
  23. Device(DevId),
  24. Directory(TmpFsDirectory),
  25. Symlink(String),
  26. }
  27. struct TmpFsInode {
  28. idata: Mutex<InodeData>,
  29. fsdata: Mutex<TmpFsData>,
  30. vfs: Weak<Mutex<TmpFs>>,
  31. }
  32. impl TmpFsInode {
  33. pub fn new(
  34. idata: InodeData,
  35. fsdata: TmpFsData,
  36. vfs: Weak<Mutex<TmpFs>>,
  37. ) -> Arc<Self> {
  38. Arc::new(Self {
  39. idata: Mutex::new(idata),
  40. fsdata: Mutex::new(fsdata),
  41. vfs,
  42. })
  43. }
  44. fn vfs(&self) -> KResult<Arc<Mutex<TmpFs>>> {
  45. self.vfs.upgrade().ok_or(EIO)
  46. }
  47. /// Link a child inode to the parent inode
  48. ///
  49. /// # Safety
  50. /// If parent is not a directory, this function will panic
  51. ///
  52. fn link_unchecked(
  53. parent_fsdata: &mut TmpFsData,
  54. parent_idata: &mut InodeData,
  55. name: &str,
  56. child_idata: &mut InodeData,
  57. ) {
  58. match parent_fsdata {
  59. TmpFsData::Directory(dir) => {
  60. dir.push((child_idata.ino, String::from(name)));
  61. parent_idata.size += size_of::<TmpFsData>() as u64;
  62. child_idata.nlink += 1;
  63. }
  64. _ => panic!("Parent is not a directory"),
  65. }
  66. }
  67. /// Link a inode to itself
  68. ///
  69. /// # Safety
  70. /// If the inode is not a directory, this function will panic
  71. ///
  72. fn self_link_unchecked(
  73. fsdata: &mut TmpFsData,
  74. idata: &mut InodeData,
  75. name: &str,
  76. ) {
  77. match fsdata {
  78. TmpFsData::Directory(dir) => {
  79. dir.push((idata.ino, String::from(name)));
  80. idata.size += size_of::<TmpFsData>() as u64;
  81. idata.nlink += 1;
  82. }
  83. _ => panic!("parent is not a directory"),
  84. }
  85. }
  86. }
  87. impl Inode for TmpFsInode {
  88. fn idata(&self) -> &Mutex<InodeData> {
  89. &self.idata
  90. }
  91. fn as_any(&self) -> &dyn Any {
  92. self
  93. }
  94. fn readdir(
  95. &self,
  96. offset: usize,
  97. callback: &mut ReadDirCallback,
  98. ) -> KResult<usize> {
  99. let _vfs = self.vfs.upgrade().ok_or(EIO)?;
  100. let vfs = _vfs.lock();
  101. match *self.fsdata.lock() {
  102. TmpFsData::Directory(ref dir) => {
  103. let icache = vfs.icache.lock();
  104. let mut nread = 0;
  105. for (ino, filename) in dir.iter().skip(offset) {
  106. let inode = icache.get(*ino).unwrap();
  107. let ret =
  108. callback(filename, &inode, &inode.idata().lock(), 0)?;
  109. if ret != 0 {
  110. break;
  111. }
  112. nread += 1;
  113. }
  114. Ok(nread)
  115. }
  116. _ => Err(ENOTDIR),
  117. }
  118. }
  119. fn read(&self, buffer: &mut [u8], offset: usize) -> KResult<usize> {
  120. self.vfs()?;
  121. match *self.fsdata.lock() {
  122. TmpFsData::File(ref file) => Ok(copy_offset_count(
  123. file,
  124. buffer,
  125. offset as usize,
  126. buffer.len(),
  127. )),
  128. _ => Err(EINVAL),
  129. }
  130. }
  131. fn write(&self, buffer: &[u8], offset: usize) -> KResult<usize> {
  132. if self.vfs()?.lock().readonly {
  133. return Err(EROFS);
  134. }
  135. match *self.fsdata.lock() {
  136. TmpFsData::File(ref mut file) => {
  137. if file.len() < offset + buffer.len() {
  138. file.resize(offset + buffer.len(), 0);
  139. }
  140. file[offset..offset + buffer.len()].copy_from_slice(&buffer);
  141. self.idata.lock().size = file.len() as u64;
  142. Ok(buffer.len())
  143. }
  144. _ => Err(EINVAL),
  145. }
  146. }
  147. fn creat(&self, at: &mut Dentry, mode: Mode) -> KResult<()> {
  148. let _vfs = self.vfs()?;
  149. let mut vfs = _vfs.lock();
  150. if vfs.readonly {
  151. return Err(EROFS);
  152. }
  153. {
  154. let self_fsdata = self.fsdata.lock();
  155. match *self_fsdata {
  156. TmpFsData::Directory(_) => {}
  157. _ => return Err(ENOTDIR),
  158. }
  159. }
  160. let ino = vfs.assign_ino();
  161. let file = {
  162. let mut locked_icache = vfs.icache.lock();
  163. let file = TmpFsInode::new(
  164. InodeData {
  165. ino,
  166. nlink: 0,
  167. size: 0,
  168. mode: S_IFREG | (mode & 0o777),
  169. atime: TimeSpec::new(),
  170. mtime: TimeSpec::new(),
  171. ctime: TimeSpec::new(),
  172. uid: 0,
  173. gid: 0,
  174. },
  175. TmpFsData::File(vec![]),
  176. locked_icache.get_vfs(),
  177. );
  178. locked_icache.submit(ino, file.clone())?;
  179. file
  180. };
  181. {
  182. let mut self_fsdata = self.fsdata.lock();
  183. let mut self_idata = self.idata.lock();
  184. let mut child_idata = file.idata.lock();
  185. TmpFsInode::link_unchecked(
  186. &mut self_fsdata,
  187. &mut self_idata,
  188. at.get_name(),
  189. &mut child_idata,
  190. );
  191. }
  192. at.save_inode(file);
  193. at.flags |= D_PRESENT;
  194. Ok(())
  195. }
  196. fn mknod(&self, at: &mut Dentry, mode: Mode, dev: DevId) -> KResult<()> {
  197. let _vfs = self.vfs()?;
  198. let mut vfs = _vfs.lock();
  199. if vfs.readonly {
  200. return Err(EROFS);
  201. }
  202. if !s_ischr(mode) && !s_isblk(mode) {
  203. return Err(EINVAL);
  204. }
  205. {
  206. let self_fsdata = self.fsdata.lock();
  207. match *self_fsdata {
  208. TmpFsData::Directory(_) => {}
  209. _ => return Err(ENOTDIR),
  210. }
  211. }
  212. let ino = vfs.assign_ino();
  213. let file = {
  214. let mut locked_icache = vfs.icache.lock();
  215. let file = TmpFsInode::new(
  216. InodeData {
  217. ino,
  218. nlink: 0,
  219. size: 0,
  220. mode: mode & (0o777 | S_IFBLK | S_IFCHR),
  221. atime: TimeSpec::new(),
  222. mtime: TimeSpec::new(),
  223. ctime: TimeSpec::new(),
  224. uid: 0,
  225. gid: 0,
  226. },
  227. TmpFsData::Device(dev),
  228. locked_icache.get_vfs(),
  229. );
  230. locked_icache.submit(ino, file.clone())?;
  231. file
  232. };
  233. {
  234. let mut self_fsdata = self.fsdata.lock();
  235. let mut self_idata = self.idata.lock();
  236. let mut child_idata = file.idata.lock();
  237. TmpFsInode::link_unchecked(
  238. &mut self_fsdata,
  239. &mut self_idata,
  240. at.get_name(),
  241. &mut child_idata,
  242. );
  243. }
  244. at.save_inode(file);
  245. at.flags |= D_PRESENT;
  246. Ok(())
  247. }
  248. fn mkdir(&self, at: &mut Dentry, mode: Mode) -> KResult<()> {
  249. let _vfs = self.vfs()?;
  250. let mut vfs = _vfs.lock();
  251. if vfs.readonly {
  252. return Err(EROFS);
  253. }
  254. {
  255. let self_fsdata = self.fsdata.lock();
  256. match *self_fsdata {
  257. TmpFsData::Directory(_) => {}
  258. _ => return Err(ENOTDIR),
  259. }
  260. }
  261. let ino = vfs.assign_ino();
  262. let dir = {
  263. let mut locked_icache = vfs.icache.lock();
  264. let file = TmpFsInode::new(
  265. InodeData {
  266. ino,
  267. nlink: 0,
  268. size: 0,
  269. mode: S_IFDIR | (mode & 0o777),
  270. atime: TimeSpec::new(),
  271. mtime: TimeSpec::new(),
  272. ctime: TimeSpec::new(),
  273. uid: 0,
  274. gid: 0,
  275. },
  276. TmpFsData::Directory(vec![]),
  277. locked_icache.get_vfs(),
  278. );
  279. locked_icache.submit(ino, file.clone())?;
  280. file
  281. };
  282. {
  283. let mut self_fsdata = self.fsdata.lock();
  284. let mut self_idata = self.idata.lock();
  285. let mut child_fsdata = dir.fsdata.lock();
  286. let mut child_idata = dir.idata.lock();
  287. TmpFsInode::link_unchecked(
  288. &mut child_fsdata,
  289. &mut child_idata,
  290. "..",
  291. &mut self_idata,
  292. );
  293. TmpFsInode::self_link_unchecked(
  294. &mut child_fsdata,
  295. &mut child_idata,
  296. ".",
  297. );
  298. TmpFsInode::link_unchecked(
  299. &mut self_fsdata,
  300. &mut self_idata,
  301. at.get_name(),
  302. &mut child_idata,
  303. );
  304. }
  305. at.save_inode(dir);
  306. // TODO: try remove D_LOADED and check if it works
  307. at.flags |= D_PRESENT | D_DIRECTORY | D_LOADED;
  308. Ok(())
  309. }
  310. fn symlink(&self, at: &mut Dentry, target: &str) -> KResult<()> {
  311. let _vfs = self.vfs()?;
  312. let mut vfs = _vfs.lock();
  313. if vfs.readonly {
  314. return Err(EROFS);
  315. }
  316. {
  317. let self_fsdata = self.fsdata.lock();
  318. match *self_fsdata {
  319. TmpFsData::Directory(_) => {}
  320. _ => return Err(ENOTDIR),
  321. }
  322. }
  323. let ino = vfs.assign_ino();
  324. let file = {
  325. let mut locked_icache = vfs.icache.lock();
  326. let file = TmpFsInode::new(
  327. InodeData {
  328. ino,
  329. nlink: 0,
  330. size: target.len() as u64,
  331. mode: S_IFLNK | 0o777,
  332. atime: TimeSpec::new(),
  333. mtime: TimeSpec::new(),
  334. ctime: TimeSpec::new(),
  335. uid: 0,
  336. gid: 0,
  337. },
  338. TmpFsData::Symlink(String::from(target)),
  339. locked_icache.get_vfs(),
  340. );
  341. locked_icache.submit(ino, file.clone())?;
  342. file
  343. };
  344. {
  345. let mut self_fsdata = self.fsdata.lock();
  346. let mut self_idata = self.idata.lock();
  347. let mut child_idata = file.idata.lock();
  348. TmpFsInode::link_unchecked(
  349. &mut self_fsdata,
  350. &mut self_idata,
  351. at.get_name(),
  352. &mut child_idata,
  353. );
  354. }
  355. at.save_inode(file);
  356. at.flags |= D_PRESENT | D_SYMLINK;
  357. Ok(())
  358. }
  359. fn readlink(&self, buffer: &mut [u8]) -> KResult<usize> {
  360. match *self.fsdata.lock() {
  361. TmpFsData::Symlink(ref target) => {
  362. let len = target.len().min(buffer.len());
  363. buffer[..len].copy_from_slice(target.as_bytes());
  364. Ok(len)
  365. }
  366. _ => Err(EINVAL),
  367. }
  368. }
  369. fn devid(&self) -> KResult<DevId> {
  370. match *self.fsdata.lock() {
  371. TmpFsData::Device(dev) => Ok(dev),
  372. _ => Err(ENODEV),
  373. }
  374. }
  375. fn truncate(&self, length: usize) -> KResult<()> {
  376. if self.vfs()?.lock().readonly {
  377. return Err(EROFS);
  378. }
  379. match *self.fsdata.lock() {
  380. TmpFsData::File(ref mut file) => {
  381. file.resize(length, 0);
  382. self.idata.lock().size = length as u64;
  383. Ok(())
  384. }
  385. _ => Err(EINVAL),
  386. }
  387. }
  388. fn unlink(&self, at: &mut Dentry) -> KResult<()> {
  389. if self.vfs()?.lock().readonly {
  390. return Err(EROFS);
  391. }
  392. let file = at.get_inode_clone();
  393. let file = file.as_any().downcast_ref::<TmpFsInode>().unwrap();
  394. match *file.fsdata.lock() {
  395. TmpFsData::Directory(_) => return Err(EISDIR),
  396. _ => {}
  397. }
  398. let file_data = file.idata.lock();
  399. let mut self_fsdata = self.fsdata.lock();
  400. match *self_fsdata {
  401. TmpFsData::Directory(ref mut dirs) => {
  402. let idx = 'label: {
  403. for (idx, (ino, _)) in dirs.iter().enumerate() {
  404. if *ino != file_data.ino {
  405. continue;
  406. }
  407. break 'label idx;
  408. }
  409. panic!("file not found in directory");
  410. };
  411. drop(file_data);
  412. {
  413. self.idata.lock().size -= size_of::<TmpFsData>() as u64;
  414. file.idata.lock().nlink -= 1;
  415. }
  416. dirs.remove(idx);
  417. // TODO!!!: CHANGE THIS SINCE IT WILL CAUSE MEMORY LEAK
  418. // AND WILL CREATE A RACE CONDITION
  419. at.flags &= !D_PRESENT;
  420. at.take_inode();
  421. at.take_fs();
  422. Ok(())
  423. }
  424. _ => return Err(ENOTDIR),
  425. }
  426. }
  427. fn vfs_weak(&self) -> Weak<Mutex<dyn Vfs>> {
  428. self.vfs.clone()
  429. }
  430. fn vfs_strong(&self) -> Option<Arc<Mutex<dyn Vfs>>> {
  431. match self.vfs.upgrade() {
  432. Some(vfs) => Some(vfs),
  433. None => None,
  434. }
  435. }
  436. }
  437. /// # Lock order
  438. /// vfs -> icache -> fsdata -> data
  439. struct TmpFs {
  440. icache: Mutex<InodeCache<TmpFs>>,
  441. next_ino: Ino,
  442. readonly: bool,
  443. }
  444. impl TmpFs {
  445. fn assign_ino(&mut self) -> Ino {
  446. let ino = self.next_ino;
  447. self.next_ino += 1;
  448. ino
  449. }
  450. pub fn create(
  451. readonly: bool,
  452. ) -> KResult<(Arc<Mutex<TmpFs>>, Arc<TmpFsInode>)> {
  453. let tmpfs = Arc::new(Mutex::new(Self {
  454. icache: Mutex::new(InodeCache::new()),
  455. next_ino: 1,
  456. readonly,
  457. }));
  458. let root_inode = {
  459. let locked_tmpfs = tmpfs.lock();
  460. let mut locked_icache = locked_tmpfs.icache.lock();
  461. locked_icache.set_vfs(Arc::downgrade(&tmpfs));
  462. let file = TmpFsInode::new(
  463. InodeData {
  464. ino: 0,
  465. nlink: 0,
  466. size: 0,
  467. mode: S_IFDIR | 0o755,
  468. atime: TimeSpec::new(),
  469. mtime: TimeSpec::new(),
  470. ctime: TimeSpec::new(),
  471. uid: 0,
  472. gid: 0,
  473. },
  474. TmpFsData::Directory(vec![]),
  475. locked_icache.get_vfs(),
  476. );
  477. locked_icache.submit(0, file.clone())?;
  478. file
  479. };
  480. {
  481. let mut fsdata = root_inode.fsdata.lock();
  482. let mut idata = root_inode.idata.lock();
  483. TmpFsInode::self_link_unchecked(&mut fsdata, &mut idata, ".");
  484. TmpFsInode::self_link_unchecked(&mut fsdata, &mut idata, "..");
  485. }
  486. Ok((tmpfs, root_inode))
  487. }
  488. }
  489. impl Vfs for TmpFs {
  490. fn io_blksize(&self) -> usize {
  491. 4096
  492. }
  493. fn fs_devid(&self) -> DevId {
  494. 2
  495. }
  496. fn as_any(&self) -> &dyn Any {
  497. self
  498. }
  499. }
  500. struct TmpFsMountCreator;
  501. impl MountCreator for TmpFsMountCreator {
  502. fn create_mount(
  503. &self,
  504. _source: &str,
  505. flags: u64,
  506. _data: &[u8],
  507. ) -> KResult<Mount> {
  508. let (fs, root_inode) = TmpFs::create(flags & MS_RDONLY != 0)?;
  509. Ok(Mount::new(fs, root_inode))
  510. }
  511. }
  512. pub fn init() {
  513. register_filesystem("tmpfs", Box::new(TmpFsMountCreator)).unwrap();
  514. }