|
@@ -1,373 +1,333 @@
|
|
|
|
+use alloc::sync::{Arc, Weak};
|
|
|
|
+use bindings::{EINVAL, EIO, EISDIR, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFREG};
|
|
use core::sync::atomic::Ordering;
|
|
use core::sync::atomic::Ordering;
|
|
|
|
|
|
use crate::{
|
|
use crate::{
|
|
io::Buffer,
|
|
io::Buffer,
|
|
kernel::vfs::{
|
|
kernel::vfs::{
|
|
- dentry::Dentry,
|
|
|
|
- inode::{AtomicIno, Ino, Inode, InodeCache, InodeOps, Mode},
|
|
|
|
|
|
+ dentry::{dcache, Dentry},
|
|
|
|
+ inode::{define_struct_inode, AtomicIno, Ino, Inode, Mode},
|
|
mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
|
|
mount::{register_filesystem, Mount, MountCreator, MS_RDONLY},
|
|
s_isblk, s_ischr,
|
|
s_isblk, s_ischr,
|
|
vfs::Vfs,
|
|
vfs::Vfs,
|
|
DevId, ReadDirCallback,
|
|
DevId, ReadDirCallback,
|
|
},
|
|
},
|
|
prelude::*,
|
|
prelude::*,
|
|
|
|
+ sync::Locked,
|
|
};
|
|
};
|
|
|
|
|
|
-use alloc::sync::Arc;
|
|
|
|
-
|
|
|
|
-use bindings::{
|
|
|
|
- EINVAL, EIO, EISDIR, EROFS, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFREG,
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-struct FileOps {
|
|
|
|
- data: Mutex<Vec<u8>>,
|
|
|
|
|
|
+fn acquire(vfs: &Weak<dyn Vfs>) -> KResult<Arc<dyn Vfs>> {
|
|
|
|
+ vfs.upgrade().ok_or(EIO)
|
|
}
|
|
}
|
|
|
|
|
|
-struct NodeOps {
|
|
|
|
- devid: DevId,
|
|
|
|
|
|
+fn astmp(vfs: &Arc<dyn Vfs>) -> &TmpFs {
|
|
|
|
+ vfs.as_any()
|
|
|
|
+ .downcast_ref::<TmpFs>()
|
|
|
|
+ .expect("corrupted tmpfs data structure")
|
|
}
|
|
}
|
|
|
|
|
|
-impl NodeOps {
|
|
|
|
- fn new(devid: DevId) -> Self {
|
|
|
|
- Self { devid }
|
|
|
|
|
|
+define_struct_inode! {
|
|
|
|
+ struct NodeInode {
|
|
|
|
+ devid: DevId,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl InodeOps for NodeOps {
|
|
|
|
- fn as_any(&self) -> &dyn Any {
|
|
|
|
- self
|
|
|
|
|
|
+impl NodeInode {
|
|
|
|
+ fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode, devid: DevId) -> Arc<Self> {
|
|
|
|
+ Self::new_locked(ino, vfs, |inode, _| unsafe {
|
|
|
|
+ addr_of_mut_field!(inode, devid).write(devid);
|
|
|
|
+
|
|
|
|
+ addr_of_mut_field!(inode, mode).write(mode.into());
|
|
|
|
+ addr_of_mut_field!(inode, nlink).write(1.into());
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- fn devid(&self, _: &Inode) -> KResult<DevId> {
|
|
|
|
|
|
+impl Inode for NodeInode {
|
|
|
|
+ fn devid(&self) -> KResult<DevId> {
|
|
Ok(self.devid)
|
|
Ok(self.devid)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct DirectoryOps {
|
|
|
|
- entries: Mutex<Vec<(Arc<[u8]>, Ino)>>,
|
|
|
|
|
|
+define_struct_inode! {
|
|
|
|
+ struct DirectoryInode {
|
|
|
|
+ entries: Locked<Vec<(Arc<[u8]>, Ino)>, ()>,
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-impl DirectoryOps {
|
|
|
|
- fn new() -> Self {
|
|
|
|
- Self {
|
|
|
|
- entries: Mutex::new(vec![]),
|
|
|
|
- }
|
|
|
|
|
|
+impl DirectoryInode {
|
|
|
|
+ fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
|
|
|
|
+ Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
|
|
|
|
+ addr_of_mut_field!(inode, entries)
|
|
|
|
+ .write(Locked::new(vec![(Arc::from(b".".as_slice()), ino)], rwsem));
|
|
|
|
+
|
|
|
|
+ addr_of_mut_field!(inode, size).write(1.into());
|
|
|
|
+ addr_of_mut_field!(inode, mode).write((S_IFDIR | (mode & 0o777)).into());
|
|
|
|
+ addr_of_mut_field!(inode, nlink).write(1.into()); // link from `.` to itself
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
- /// Locks the `inode.idata`
|
|
|
|
- fn link(&self, dir: &Inode, file: &Inode, name: Arc<[u8]>) -> KResult<()> {
|
|
|
|
- dir.idata.lock().size += 1;
|
|
|
|
- self.entries.lock().push((name, file.ino));
|
|
|
|
|
|
+ fn link(&self, name: Arc<[u8]>, file: &dyn Inode, dlock: &mut ()) {
|
|
|
|
+ // Safety: Only `unlink` will do something based on `nlink` count
|
|
|
|
+ // No need to synchronize here
|
|
|
|
+ file.nlink.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
|
- file.idata.lock().nlink += 1;
|
|
|
|
|
|
+ // Safety: `rwsem` has done the synchronization
|
|
|
|
+ self.size.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
|
- Ok(())
|
|
|
|
|
|
+ self.entries.access_mut(dlock).push((name, file.ino));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl InodeOps for DirectoryOps {
|
|
|
|
- fn as_any(&self) -> &dyn Any {
|
|
|
|
- self
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+impl Inode for DirectoryInode {
|
|
fn readdir<'cb, 'r: 'cb>(
|
|
fn readdir<'cb, 'r: 'cb>(
|
|
- &self,
|
|
|
|
- _: &Inode,
|
|
|
|
|
|
+ &'r self,
|
|
offset: usize,
|
|
offset: usize,
|
|
callback: &ReadDirCallback<'cb>,
|
|
callback: &ReadDirCallback<'cb>,
|
|
) -> KResult<usize> {
|
|
) -> KResult<usize> {
|
|
|
|
+ let lock = self.rwsem.lock_shared();
|
|
Ok(self
|
|
Ok(self
|
|
.entries
|
|
.entries
|
|
- .lock()
|
|
|
|
|
|
+ .access(lock.as_ref())
|
|
.iter()
|
|
.iter()
|
|
.skip(offset)
|
|
.skip(offset)
|
|
.take_while(|(name, ino)| callback(name, *ino).is_ok())
|
|
.take_while(|(name, ino)| callback(name, *ino).is_ok())
|
|
.count())
|
|
.count())
|
|
}
|
|
}
|
|
|
|
|
|
- fn creat(&self, dir: &Inode, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
|
|
|
|
- let vfs = dir.vfs.upgrade().ok_or(EIO)?;
|
|
|
|
- let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
|
|
|
|
|
|
+ fn creat(&self, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
|
|
|
|
+ let vfs = acquire(&self.vfs)?;
|
|
|
|
+ let vfs = astmp(&vfs);
|
|
|
|
|
|
- if vfs.readonly {
|
|
|
|
- return Err(EROFS);
|
|
|
|
- }
|
|
|
|
|
|
+ let mut rwsem = self.rwsem.lock();
|
|
|
|
|
|
let ino = vfs.assign_ino();
|
|
let ino = vfs.assign_ino();
|
|
- let file = vfs.icache.lock().alloc_file(ino, mode)?;
|
|
|
|
|
|
+ let file = FileInode::new(ino, self.vfs.clone(), mode);
|
|
|
|
|
|
- self.link(dir, file.as_ref(), at.name().clone())?;
|
|
|
|
|
|
+ self.link(at.name().clone(), file.as_ref(), rwsem.as_mut());
|
|
at.save_reg(file)
|
|
at.save_reg(file)
|
|
}
|
|
}
|
|
|
|
|
|
- fn mknod(
|
|
|
|
- &self,
|
|
|
|
- dir: &Inode,
|
|
|
|
- at: &Arc<Dentry>,
|
|
|
|
- mode: Mode,
|
|
|
|
- dev: DevId,
|
|
|
|
- ) -> KResult<()> {
|
|
|
|
- let vfs = dir.vfs.upgrade().ok_or(EIO)?;
|
|
|
|
- let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
|
|
|
|
-
|
|
|
|
- if vfs.readonly {
|
|
|
|
- return Err(EROFS);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ fn mknod(&self, at: &Arc<Dentry>, mode: Mode, dev: DevId) -> KResult<()> {
|
|
if !s_ischr(mode) && !s_isblk(mode) {
|
|
if !s_ischr(mode) && !s_isblk(mode) {
|
|
return Err(EINVAL);
|
|
return Err(EINVAL);
|
|
}
|
|
}
|
|
|
|
|
|
- let ino = vfs.assign_ino();
|
|
|
|
- let mut icache = vfs.icache.lock();
|
|
|
|
- let file = icache.alloc(ino, Box::new(NodeOps::new(dev)));
|
|
|
|
- file.idata.lock().mode = mode & (0o777 | S_IFBLK | S_IFCHR);
|
|
|
|
- icache.submit(&file)?;
|
|
|
|
|
|
+ let vfs = acquire(&self.vfs)?;
|
|
|
|
+ let vfs = astmp(&vfs);
|
|
|
|
+
|
|
|
|
+ let mut rwsem = self.rwsem.lock();
|
|
|
|
|
|
- self.link(dir, file.as_ref(), at.name().clone())?;
|
|
|
|
|
|
+ let ino = vfs.assign_ino();
|
|
|
|
+ let file = NodeInode::new(
|
|
|
|
+ ino,
|
|
|
|
+ self.vfs.clone(),
|
|
|
|
+ mode & (0o777 | S_IFBLK | S_IFCHR),
|
|
|
|
+ dev,
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ self.link(at.name().clone(), file.as_ref(), rwsem.as_mut());
|
|
at.save_reg(file)
|
|
at.save_reg(file)
|
|
}
|
|
}
|
|
|
|
|
|
- fn symlink(
|
|
|
|
- &self,
|
|
|
|
- dir: &Inode,
|
|
|
|
- at: &Arc<Dentry>,
|
|
|
|
- target: &[u8],
|
|
|
|
- ) -> KResult<()> {
|
|
|
|
- let vfs = dir.vfs.upgrade().ok_or(EIO)?;
|
|
|
|
- let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
|
|
|
|
-
|
|
|
|
- if vfs.readonly {
|
|
|
|
- return Err(EROFS);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let ino = vfs.assign_ino();
|
|
|
|
- let mut icache = vfs.icache.lock();
|
|
|
|
|
|
+ fn symlink(&self, at: &Arc<Dentry>, target: &[u8]) -> KResult<()> {
|
|
|
|
+ let vfs = acquire(&self.vfs)?;
|
|
|
|
+ let vfs = astmp(&vfs);
|
|
|
|
|
|
- let target_len = target.len() as u64;
|
|
|
|
|
|
+ let mut rwsem = self.rwsem.lock();
|
|
|
|
|
|
- let file =
|
|
|
|
- icache.alloc(ino, Box::new(SymlinkOps::new(Arc::from(target))));
|
|
|
|
- {
|
|
|
|
- let mut idata = file.idata.lock();
|
|
|
|
- idata.mode = S_IFLNK | 0o777;
|
|
|
|
- idata.size = target_len;
|
|
|
|
- }
|
|
|
|
- icache.submit(&file)?;
|
|
|
|
|
|
+ let ino = vfs.assign_ino();
|
|
|
|
+ let file = SymlinkInode::new(ino, self.vfs.clone(), target.into());
|
|
|
|
|
|
- self.link(dir, file.as_ref(), at.name().clone())?;
|
|
|
|
|
|
+ self.link(at.name().clone(), file.as_ref(), rwsem.as_mut());
|
|
at.save_symlink(file)
|
|
at.save_symlink(file)
|
|
}
|
|
}
|
|
|
|
|
|
- fn mkdir(&self, dir: &Inode, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
|
|
|
|
- let vfs = dir.vfs.upgrade().ok_or(EIO)?;
|
|
|
|
- let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
|
|
|
|
|
|
+ fn mkdir(&self, at: &Arc<Dentry>, mode: Mode) -> KResult<()> {
|
|
|
|
+ let vfs = acquire(&self.vfs)?;
|
|
|
|
+ let vfs = astmp(&vfs);
|
|
|
|
|
|
- if vfs.readonly {
|
|
|
|
- return Err(EROFS);
|
|
|
|
- }
|
|
|
|
|
|
+ let mut rwsem = self.rwsem.lock();
|
|
|
|
|
|
let ino = vfs.assign_ino();
|
|
let ino = vfs.assign_ino();
|
|
- let mut icache = vfs.icache.lock();
|
|
|
|
-
|
|
|
|
- let mut newdir_ops = DirectoryOps::new();
|
|
|
|
- let entries = newdir_ops.entries.get_mut();
|
|
|
|
- entries.push((Arc::from(b".".as_slice()), ino));
|
|
|
|
- entries.push((Arc::from(b"..".as_slice()), dir.ino));
|
|
|
|
-
|
|
|
|
- let newdir = icache.alloc(ino, Box::new(newdir_ops));
|
|
|
|
- {
|
|
|
|
- let mut newdir_idata = newdir.idata.lock();
|
|
|
|
- newdir_idata.mode = S_IFDIR | (mode & 0o777);
|
|
|
|
- newdir_idata.nlink = 1;
|
|
|
|
- newdir_idata.size = 2;
|
|
|
|
- }
|
|
|
|
|
|
+ let newdir = DirectoryInode::new(ino, self.vfs.clone(), mode);
|
|
|
|
|
|
- icache.submit(&newdir)?;
|
|
|
|
- dir.idata.lock().nlink += 1; // link from `newdir` to `dir`, (or parent)
|
|
|
|
-
|
|
|
|
- self.link(dir, newdir.as_ref(), at.name().clone())?;
|
|
|
|
|
|
+ self.link(at.name().clone(), newdir.as_ref(), rwsem.as_mut());
|
|
at.save_dir(newdir)
|
|
at.save_dir(newdir)
|
|
}
|
|
}
|
|
|
|
|
|
- fn unlink(&self, dir: &Inode, at: &Arc<Dentry>) -> KResult<()> {
|
|
|
|
- let vfs = dir.vfs.upgrade().ok_or(EIO)?;
|
|
|
|
- let vfs = vfs.as_any().downcast_ref::<TmpFs>().unwrap();
|
|
|
|
|
|
+ fn unlink(&self, at: &Arc<Dentry>) -> KResult<()> {
|
|
|
|
+ let vfs = acquire(&self.vfs)?;
|
|
|
|
+ let vfs = astmp(&vfs);
|
|
|
|
|
|
- if vfs.readonly {
|
|
|
|
- return Err(EROFS);
|
|
|
|
- }
|
|
|
|
|
|
+ let mut dlock = self.rwsem.lock();
|
|
|
|
|
|
let file = at.get_inode()?;
|
|
let file = at.get_inode()?;
|
|
|
|
+ let _flock = file.rwsem.lock();
|
|
|
|
|
|
- let mut file_idata = file.idata.lock();
|
|
|
|
-
|
|
|
|
- if file_idata.mode & S_IFDIR != 0 {
|
|
|
|
|
|
+ // Safety: `flock` has done the synchronization
|
|
|
|
+ if file.mode.load(Ordering::Relaxed) & S_IFDIR != 0 {
|
|
return Err(EISDIR);
|
|
return Err(EISDIR);
|
|
}
|
|
}
|
|
|
|
|
|
- let mut self_idata = dir.idata.lock();
|
|
|
|
- let mut entries = self.entries.lock();
|
|
|
|
-
|
|
|
|
- let idx = entries
|
|
|
|
- .iter()
|
|
|
|
- .position(|(_, ino)| *ino == file.ino)
|
|
|
|
- .expect("file not found in directory");
|
|
|
|
|
|
+ let entries = self.entries.access_mut(dlock.as_mut());
|
|
|
|
+ entries.retain(|(_, ino)| *ino != file.ino);
|
|
|
|
+
|
|
|
|
+ assert_eq!(
|
|
|
|
+ entries.len() as u64,
|
|
|
|
+ // Safety: `dlock` has done the synchronization
|
|
|
|
+ self.size.fetch_sub(1, Ordering::Relaxed) - 1
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ // Safety: `flock` has done the synchronization
|
|
|
|
+ let file_nlink = file.nlink.fetch_sub(1, Ordering::Relaxed) - 1;
|
|
|
|
+
|
|
|
|
+ if file_nlink == 0 {
|
|
|
|
+ // Remove the file inode from the inode cache
|
|
|
|
+ // The last reference to the inode is held by some dentry
|
|
|
|
+ // and will be released when the dentry is released
|
|
|
|
+ //
|
|
|
|
+ // TODO: Should we use some inode cache in tmpfs?
|
|
|
|
+ //
|
|
|
|
+ // vfs.icache.lock().retain(|ino, _| *ino != file.ino);
|
|
|
|
+ }
|
|
|
|
|
|
- self_idata.size -= 1;
|
|
|
|
- file_idata.nlink -= 1;
|
|
|
|
- entries.remove(idx);
|
|
|
|
|
|
+ // Postpone the invalidation of the dentry and inode until the
|
|
|
|
+ // last reference to the dentry is released
|
|
|
|
+ //
|
|
|
|
+ // But we can remove it from the dentry cache immediately
|
|
|
|
+ // so later lookup will fail with ENOENT
|
|
|
|
+ dcache::d_remove(at);
|
|
|
|
|
|
- at.invalidate()
|
|
|
|
|
|
+ Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-struct SymlinkOps {
|
|
|
|
- target: Arc<[u8]>,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl SymlinkOps {
|
|
|
|
- fn new(target: Arc<[u8]>) -> Self {
|
|
|
|
- Self { target }
|
|
|
|
|
|
+define_struct_inode! {
|
|
|
|
+ struct SymlinkInode {
|
|
|
|
+ target: Arc<[u8]>,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl InodeOps for SymlinkOps {
|
|
|
|
- fn as_any(&self) -> &dyn Any {
|
|
|
|
- self
|
|
|
|
|
|
+impl SymlinkInode {
|
|
|
|
+ fn new(ino: Ino, vfs: Weak<dyn Vfs>, target: Arc<[u8]>) -> Arc<Self> {
|
|
|
|
+ Self::new_locked(ino, vfs, |inode, _| unsafe {
|
|
|
|
+ let len = target.len();
|
|
|
|
+ addr_of_mut_field!(inode, target).write(target);
|
|
|
|
+
|
|
|
|
+ addr_of_mut_field!(inode, mode).write((S_IFLNK | 0o777).into());
|
|
|
|
+ addr_of_mut_field!(inode, size).write((len as u64).into());
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- fn readlink(&self, _: &Inode, buffer: &mut dyn Buffer) -> KResult<usize> {
|
|
|
|
|
|
+impl Inode for SymlinkInode {
|
|
|
|
+ fn readlink(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
|
|
buffer
|
|
buffer
|
|
.fill(self.target.as_ref())
|
|
.fill(self.target.as_ref())
|
|
.map(|result| result.allow_partial())
|
|
.map(|result| result.allow_partial())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl FileOps {
|
|
|
|
- fn new() -> Self {
|
|
|
|
- Self {
|
|
|
|
- data: Mutex::new(vec![]),
|
|
|
|
- }
|
|
|
|
|
|
+define_struct_inode! {
|
|
|
|
+ struct FileInode {
|
|
|
|
+ filedata: Locked<Vec<u8>, ()>,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl InodeOps for FileOps {
|
|
|
|
- fn as_any(&self) -> &dyn Any {
|
|
|
|
- self
|
|
|
|
|
|
+impl FileInode {
|
|
|
|
+ fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
|
|
|
|
+ Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
|
|
|
|
+ addr_of_mut_field!(inode, filedata).write(Locked::new(vec![], rwsem));
|
|
|
|
+
|
|
|
|
+ addr_of_mut_field!(inode, mode).write((S_IFREG | (mode & 0o777)).into());
|
|
|
|
+ addr_of_mut_field!(inode, nlink).write(1.into());
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- fn read(
|
|
|
|
- &self,
|
|
|
|
- _: &Inode,
|
|
|
|
- buffer: &mut dyn Buffer,
|
|
|
|
- offset: usize,
|
|
|
|
- ) -> KResult<usize> {
|
|
|
|
- let data = self.data.lock();
|
|
|
|
- let data = data.split_at_checked(offset).ok_or(EINVAL)?.1;
|
|
|
|
|
|
+impl Inode for FileInode {
|
|
|
|
+ fn read(&self, buffer: &mut dyn Buffer, offset: usize) -> KResult<usize> {
|
|
|
|
+ // TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
|
+ let lock = self.rwsem.lock_shared();
|
|
|
|
+
|
|
|
|
+ let (_, data) = self
|
|
|
|
+ .filedata
|
|
|
|
+ .access(lock.as_ref())
|
|
|
|
+ .split_at_checked(offset)
|
|
|
|
+ .ok_or(EINVAL)?;
|
|
|
|
|
|
buffer.fill(data).map(|result| result.allow_partial())
|
|
buffer.fill(data).map(|result| result.allow_partial())
|
|
}
|
|
}
|
|
|
|
|
|
- fn write(
|
|
|
|
- &self,
|
|
|
|
- inode: &Inode,
|
|
|
|
- buffer: &[u8],
|
|
|
|
- offset: usize,
|
|
|
|
- ) -> KResult<usize> {
|
|
|
|
- let mut idata = inode.idata.lock();
|
|
|
|
- let mut data = self.data.lock();
|
|
|
|
|
|
+ fn write(&self, buffer: &[u8], offset: usize) -> KResult<usize> {
|
|
|
|
+ // TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
|
+ let mut lock = self.rwsem.lock();
|
|
|
|
+ let filedata = self.filedata.access_mut(lock.as_mut());
|
|
|
|
|
|
- if data.len() < offset + buffer.len() {
|
|
|
|
- data.resize(offset + buffer.len(), 0);
|
|
|
|
|
|
+ if filedata.len() < offset + buffer.len() {
|
|
|
|
+ filedata.resize(offset + buffer.len(), 0);
|
|
}
|
|
}
|
|
|
|
|
|
- data[offset..offset + buffer.len()].copy_from_slice(&buffer);
|
|
|
|
- idata.size = data.len() as u64;
|
|
|
|
|
|
+ filedata[offset..offset + buffer.len()].copy_from_slice(&buffer);
|
|
|
|
+
|
|
|
|
+ // Safety: `lock` has done the synchronization
|
|
|
|
+ self.size.store(filedata.len() as u64, Ordering::Relaxed);
|
|
|
|
|
|
Ok(buffer.len())
|
|
Ok(buffer.len())
|
|
}
|
|
}
|
|
|
|
|
|
- fn truncate(&self, inode: &Inode, length: usize) -> KResult<()> {
|
|
|
|
- let mut idata = inode.idata.lock();
|
|
|
|
|
|
+ fn truncate(&self, length: usize) -> KResult<()> {
|
|
|
|
+ // TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
|
+ let mut lock = self.rwsem.lock();
|
|
|
|
+ let filedata = self.filedata.access_mut(lock.as_mut());
|
|
|
|
|
|
- idata.size = length as u64;
|
|
|
|
- self.data.lock().resize(length, 0);
|
|
|
|
|
|
+ // Safety: `lock` has done the synchronization
|
|
|
|
+ self.size.store(length as u64, Ordering::Relaxed);
|
|
|
|
+ filedata.resize(length, 0);
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/// # Lock order
|
|
|
|
-/// `vfs` -> `icache` -> `idata` -> `*ops`.`*data`
|
|
|
|
|
|
+impl_any!(TmpFs);
|
|
struct TmpFs {
|
|
struct TmpFs {
|
|
- icache: Mutex<InodeCache<TmpFs>>,
|
|
|
|
next_ino: AtomicIno,
|
|
next_ino: AtomicIno,
|
|
readonly: bool,
|
|
readonly: bool,
|
|
}
|
|
}
|
|
|
|
|
|
-impl InodeCache<TmpFs> {
|
|
|
|
- fn alloc_file(&mut self, ino: Ino, mode: Mode) -> KResult<Arc<Inode>> {
|
|
|
|
- let file = self.alloc(ino, Box::new(FileOps::new()));
|
|
|
|
- file.idata.lock().mode = S_IFREG | (mode & 0o777);
|
|
|
|
|
|
+impl Vfs for TmpFs {
|
|
|
|
+ fn io_blksize(&self) -> usize {
|
|
|
|
+ 4096
|
|
|
|
+ }
|
|
|
|
|
|
- self.submit(&file)?;
|
|
|
|
|
|
+ fn fs_devid(&self) -> DevId {
|
|
|
|
+ 2
|
|
|
|
+ }
|
|
|
|
|
|
- Ok(file)
|
|
|
|
|
|
+ fn is_read_only(&self) -> bool {
|
|
|
|
+ self.readonly
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
impl TmpFs {
|
|
impl TmpFs {
|
|
fn assign_ino(&self) -> Ino {
|
|
fn assign_ino(&self) -> Ino {
|
|
- self.next_ino.fetch_add(1, Ordering::SeqCst)
|
|
|
|
|
|
+ self.next_ino.fetch_add(1, Ordering::AcqRel)
|
|
}
|
|
}
|
|
|
|
|
|
- pub fn create(readonly: bool) -> KResult<(Arc<TmpFs>, Arc<Inode>)> {
|
|
|
|
- let tmpfs = Arc::new_cyclic(|weak| Self {
|
|
|
|
- icache: Mutex::new(InodeCache::new(weak.clone())),
|
|
|
|
|
|
+ pub fn create(readonly: bool) -> KResult<(Arc<dyn Vfs>, Arc<dyn Inode>)> {
|
|
|
|
+ let tmpfs = Arc::new(Self {
|
|
next_ino: AtomicIno::new(1),
|
|
next_ino: AtomicIno::new(1),
|
|
readonly,
|
|
readonly,
|
|
});
|
|
});
|
|
|
|
|
|
- let mut dir = DirectoryOps::new();
|
|
|
|
- let entries = dir.entries.get_mut();
|
|
|
|
- entries.push((Arc::from(b".".as_slice()), 0));
|
|
|
|
- entries.push((Arc::from(b"..".as_slice()), 0));
|
|
|
|
-
|
|
|
|
- let root_dir = {
|
|
|
|
- let mut icache = tmpfs.icache.lock();
|
|
|
|
- let root_dir = icache.alloc(0, Box::new(dir));
|
|
|
|
- {
|
|
|
|
- let mut idata = root_dir.idata.lock();
|
|
|
|
-
|
|
|
|
- idata.mode = S_IFDIR | 0o755;
|
|
|
|
- idata.nlink = 2;
|
|
|
|
- idata.size = 2;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- icache.submit(&root_dir)?;
|
|
|
|
-
|
|
|
|
- root_dir
|
|
|
|
- };
|
|
|
|
|
|
+ let weak = Arc::downgrade(&tmpfs);
|
|
|
|
+ let root_dir = DirectoryInode::new(0, weak, 0o755);
|
|
|
|
|
|
Ok((tmpfs, root_dir))
|
|
Ok((tmpfs, root_dir))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl Vfs for TmpFs {
|
|
|
|
- fn io_blksize(&self) -> usize {
|
|
|
|
- 4096
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn fs_devid(&self) -> DevId {
|
|
|
|
- 2
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fn as_any(&self) -> &dyn Any {
|
|
|
|
- self
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
struct TmpFsMountCreator;
|
|
struct TmpFsMountCreator;
|
|
|
|
|
|
impl MountCreator for TmpFsMountCreator {
|
|
impl MountCreator for TmpFsMountCreator {
|
|
@@ -385,5 +345,5 @@ impl MountCreator for TmpFsMountCreator {
|
|
}
|
|
}
|
|
|
|
|
|
pub fn init() {
|
|
pub fn init() {
|
|
- register_filesystem("tmpfs", Box::new(TmpFsMountCreator)).unwrap();
|
|
|
|
|
|
+ register_filesystem("tmpfs", Arc::new(TmpFsMountCreator)).unwrap();
|
|
}
|
|
}
|