Merge branch 'node_leak' into 'master'
Don't leak node block on node remove. See merge request redox-os/redoxfs!81
This commit is contained in:
@@ -14,7 +14,7 @@ pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback:
|
|||||||
where
|
where
|
||||||
D: Disk,
|
D: Disk,
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
F: FnMut(&Path) -> T,
|
F: FnOnce(&Path) -> T,
|
||||||
{
|
{
|
||||||
let mountpoint = mountpoint.as_ref();
|
let mountpoint = mountpoint.as_ref();
|
||||||
let socket = Socket::<V2>::create(&format!("{}", mountpoint.display()))?;
|
let socket = Socket::<V2>::create(&format!("{}", mountpoint.display()))?;
|
||||||
|
|||||||
+60
-28
@@ -1,49 +1,61 @@
|
|||||||
use std::ops::DerefMut;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{fs, sync, thread, time};
|
use std::{fs, thread, time};
|
||||||
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
use crate::{unmount_path, DiskSparse, FileSystem, Node, TreePtr};
|
||||||
|
|
||||||
use crate::{unmount_path, DiskSparse, FileSystem};
|
static IMAGE_SEQ: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
fn with_redoxfs<T, F>(callback: F) -> T
|
fn with_redoxfs<T, F>(callback: F) -> T
|
||||||
where
|
where
|
||||||
T: Send + Sync + 'static,
|
T: Send + Sync + 'static,
|
||||||
F: FnMut(&Path) -> T + Send + Sync + 'static,
|
F: FnOnce(FileSystem<DiskSparse>) -> T + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let disk_path = "image.bin";
|
let disk_path = format!("image{}.bin", IMAGE_SEQ.fetch_add(1, Relaxed));
|
||||||
let mount_path = "image";
|
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
let disk = DiskSparse::create(dbg!(disk_path), 1024 * 1024 * 1024).unwrap();
|
let disk = DiskSparse::create(dbg!(&disk_path), 1024 * 1024 * 1024).unwrap();
|
||||||
|
|
||||||
if cfg!(not(target_os = "redox")) {
|
|
||||||
if !Path::new(mount_path).exists() {
|
|
||||||
dbg!(fs::create_dir(dbg!(mount_path))).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ctime = dbg!(time::SystemTime::now().duration_since(time::UNIX_EPOCH)).unwrap();
|
let ctime = dbg!(time::SystemTime::now().duration_since(time::UNIX_EPOCH)).unwrap();
|
||||||
let fs = FileSystem::create(disk, None, ctime.as_secs(), ctime.subsec_nanos()).unwrap();
|
let fs = FileSystem::create(disk, None, ctime.as_secs(), ctime.subsec_nanos()).unwrap();
|
||||||
|
|
||||||
let callback_mutex = sync::Arc::new(sync::Mutex::new(callback));
|
callback(fs)
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(fs::remove_file(dbg!(disk_path))).unwrap();
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_mounted<T, F>(callback: F) -> T
|
||||||
|
where
|
||||||
|
T: Send + Sync + 'static,
|
||||||
|
F: FnOnce(&Path) -> T + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
let mount_path_o = format!("image{}", IMAGE_SEQ.fetch_add(1, Relaxed));
|
||||||
|
let mount_path = mount_path_o.clone();
|
||||||
|
|
||||||
|
let res = with_redoxfs(move |fs| {
|
||||||
|
if cfg!(not(target_os = "redox")) {
|
||||||
|
if !Path::new(&mount_path).exists() {
|
||||||
|
dbg!(fs::create_dir(dbg!(&mount_path))).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
let join_handle = crate::mount(fs, dbg!(mount_path), move |real_path| {
|
let join_handle = crate::mount(fs, dbg!(mount_path), move |real_path| {
|
||||||
let callback_mutex = callback_mutex.clone();
|
|
||||||
let real_path = real_path.to_owned();
|
let real_path = real_path.to_owned();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let res = {
|
let res = callback(&real_path);
|
||||||
let mut callback_guard = callback_mutex.lock().unwrap();
|
let real_path = real_path.to_str().unwrap();
|
||||||
let callback = callback_guard.deref_mut();
|
|
||||||
callback(&real_path)
|
|
||||||
};
|
|
||||||
|
|
||||||
if cfg!(target_os = "redox") {
|
if cfg!(target_os = "redox") {
|
||||||
dbg!(fs::remove_file(dbg!(format!(":{}", mount_path)))).unwrap();
|
dbg!(fs::remove_file(dbg!(format!(":{}", real_path)))).unwrap();
|
||||||
} else {
|
} else {
|
||||||
if !dbg!(Command::new("sync").status()).unwrap().success() {
|
if !dbg!(Command::new("sync").status()).unwrap().success() {
|
||||||
panic!("sync failed");
|
panic!("sync failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if !unmount_path(mount_path).is_ok() {
|
if !unmount_path(real_path).is_ok() {
|
||||||
panic!("umount failed");
|
panic!("umount failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,12 +66,10 @@ where
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
join_handle.join().unwrap()
|
join_handle.join().unwrap()
|
||||||
};
|
});
|
||||||
|
|
||||||
dbg!(fs::remove_file(dbg!(disk_path))).unwrap();
|
|
||||||
|
|
||||||
if cfg!(not(target_os = "redox")) {
|
if cfg!(not(target_os = "redox")) {
|
||||||
dbg!(fs::remove_dir(dbg!(mount_path))).unwrap();
|
dbg!(fs::remove_dir(dbg!(mount_path_o))).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
@@ -67,7 +77,7 @@ where
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
with_redoxfs(|path| {
|
with_mounted(|path| {
|
||||||
dbg!(fs::create_dir(&path.join("test"))).unwrap();
|
dbg!(fs::create_dir(&path.join("test"))).unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -78,7 +88,7 @@ fn mmap() {
|
|||||||
use syscall;
|
use syscall;
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
with_redoxfs(|path| {
|
with_mounted(|path| {
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
let path = dbg!(path.join("test"));
|
let path = dbg!(path.join("test"));
|
||||||
@@ -129,3 +139,25 @@ fn mmap() {
|
|||||||
mmap_inner(false);
|
mmap_inner(false);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_remove_should_not_increase_size() {
|
||||||
|
with_redoxfs(|mut fs| {
|
||||||
|
let initially_free = fs.allocator().free();
|
||||||
|
|
||||||
|
let tree_ptr = TreePtr::<Node>::root();
|
||||||
|
let name = "test";
|
||||||
|
let _ = fs.tx(|tx| {
|
||||||
|
tx.create_node(
|
||||||
|
tree_ptr,
|
||||||
|
name,
|
||||||
|
Node::MODE_FILE | 0644,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
tx.remove_node(tree_ptr, name, Node::MODE_FILE)
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(fs.allocator().free(), initially_free);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
+26
-10
@@ -372,10 +372,10 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
Ok(block.create_ptr())
|
Ok(block.create_ptr())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_tree<T: BlockTrait + DerefMut<Target = [u8]>>(
|
fn read_tree_and_addr<T: BlockTrait + DerefMut<Target = [u8]>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ptr: TreePtr<T>,
|
ptr: TreePtr<T>,
|
||||||
) -> Result<TreeData<T>> {
|
) -> Result<(TreeData<T>, BlockAddr)> {
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
// ID is invalid (should this return None?)
|
// ID is invalid (should this return None?)
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
@@ -401,7 +401,14 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
};
|
};
|
||||||
data.copy_from_slice(raw.data());
|
data.copy_from_slice(raw.data());
|
||||||
|
|
||||||
Ok(TreeData::new(ptr.id(), data))
|
Ok((TreeData::new(ptr.id(), data), raw.addr()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_tree<T: BlockTrait + DerefMut<Target = [u8]>>(
|
||||||
|
&mut self,
|
||||||
|
ptr: TreePtr<T>,
|
||||||
|
) -> Result<TreeData<T>> {
|
||||||
|
Ok(self.read_tree_and_addr(ptr)?.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: improve performance, reduce writes
|
//TODO: improve performance, reduce writes
|
||||||
@@ -666,7 +673,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
if let Some(entry_name) = entry.name() {
|
if let Some(entry_name) = entry.name() {
|
||||||
if entry_name == name {
|
if entry_name == name {
|
||||||
// Read node and test type against requested type
|
// Read node and test type against requested type
|
||||||
let node = self.read_tree(node_ptr)?;
|
let (node, addr) = self.read_tree_and_addr(node_ptr)?;
|
||||||
if node.data().mode() & Node::MODE_TYPE == mode {
|
if node.data().mode() & Node::MODE_TYPE == mode {
|
||||||
if node.data().is_dir()
|
if node.data().is_dir()
|
||||||
&& node.data().size() > 0
|
&& node.data().size() > 0
|
||||||
@@ -677,7 +684,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save node and clear entry
|
// Save node and clear entry
|
||||||
node_opt = Some(node);
|
node_opt = Some((node, addr));
|
||||||
*entry = DirEntry::default();
|
*entry = DirEntry::default();
|
||||||
break;
|
break;
|
||||||
} else if node.data().is_dir() {
|
} else if node.data().is_dir() {
|
||||||
@@ -691,14 +698,16 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut node) = node_opt {
|
if let Some((mut node, addr)) = node_opt {
|
||||||
let links = node.data().links();
|
let links = node.data().links();
|
||||||
if links > 1 {
|
let remove_node = if links > 1 {
|
||||||
node.data_mut().set_links(links - 1);
|
node.data_mut().set_links(links - 1);
|
||||||
|
false
|
||||||
} else {
|
} else {
|
||||||
node.data_mut().set_links(0);
|
node.data_mut().set_links(0);
|
||||||
self.truncate_node_inner(&mut node, 0)?;
|
self.truncate_node_inner(&mut node, 0)?;
|
||||||
}
|
true
|
||||||
|
};
|
||||||
|
|
||||||
if record_offset == records - 1 && dir.data().is_empty() {
|
if record_offset == records - 1 && dir.data().is_empty() {
|
||||||
let mut remove_record = record_offset;
|
let mut remove_record = record_offset;
|
||||||
@@ -728,8 +737,15 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
|||||||
self.sync_node_record_ptr(&mut parent, record_offset, dir_record_ptr)?;
|
self.sync_node_record_ptr(&mut parent, record_offset, dir_record_ptr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync both parent and node at the same time
|
if remove_node {
|
||||||
self.sync_trees(&[parent, node])?;
|
self.sync_tree(parent)?;
|
||||||
|
unsafe {
|
||||||
|
self.deallocate(addr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Sync both parent and node at the same time
|
||||||
|
self.sync_trees(&[parent, node])?;
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user