Store number of blocks actually used
This commit is contained in:
+11
-11
@@ -191,11 +191,11 @@ impl AllocEntry {
|
||||
}
|
||||
|
||||
pub fn allocate(addr: BlockAddr) -> Self {
|
||||
Self::new(addr.index(), -addr.level().blocks())
|
||||
Self::new(addr.index(), -addr.level().blocks::<i64>())
|
||||
}
|
||||
|
||||
pub fn deallocate(addr: BlockAddr) -> Self {
|
||||
Self::new(addr.index(), addr.level().blocks())
|
||||
Self::new(addr.index(), addr.level().blocks::<i64>())
|
||||
}
|
||||
|
||||
pub fn index(&self) -> u64 {
|
||||
@@ -282,17 +282,17 @@ fn alloc_node_size_test() {
|
||||
fn allocator_test() {
|
||||
let mut alloc = Allocator::default();
|
||||
|
||||
assert_eq!(alloc.allocate(BlockLevel::default()), None);
|
||||
assert_eq!(alloc.allocate(BlockMeta::default()), None);
|
||||
|
||||
alloc.deallocate(unsafe { BlockAddr::new(1, BlockLevel::default()) });
|
||||
alloc.deallocate(unsafe { BlockAddr::new(1, BlockMeta::default()) });
|
||||
assert_eq!(
|
||||
alloc.allocate(BlockLevel::default()),
|
||||
Some(unsafe { BlockAddr::new(1, BlockLevel::default()) })
|
||||
alloc.allocate(BlockMeta::default()),
|
||||
Some(unsafe { BlockAddr::new(1, BlockMeta::default()) })
|
||||
);
|
||||
assert_eq!(alloc.allocate(BlockLevel::default()), None);
|
||||
assert_eq!(alloc.allocate(BlockMeta::default()), None);
|
||||
|
||||
for addr in 1023..2048 {
|
||||
alloc.deallocate(unsafe { BlockAddr::new(addr, BlockLevel::default()) });
|
||||
alloc.deallocate(unsafe { BlockAddr::new(addr, BlockMeta::default()) });
|
||||
}
|
||||
|
||||
assert_eq!(alloc.levels.len(), 11);
|
||||
@@ -308,11 +308,11 @@ fn allocator_test() {
|
||||
|
||||
for addr in 1023..2048 {
|
||||
assert_eq!(
|
||||
alloc.allocate(BlockLevel::default()),
|
||||
Some(unsafe { BlockAddr::new(addr, BlockLevel::default()) })
|
||||
alloc.allocate(BlockMeta::default()),
|
||||
Some(unsafe { BlockAddr::new(addr, BlockMeta::default()) })
|
||||
);
|
||||
}
|
||||
assert_eq!(alloc.allocate(BlockLevel::default()), None);
|
||||
assert_eq!(alloc.allocate(BlockMeta::default()), None);
|
||||
|
||||
assert_eq!(alloc.levels.len(), 11);
|
||||
for level in 0..alloc.levels.len() {
|
||||
|
||||
+2
-2
@@ -125,8 +125,8 @@ impl BlockLevel {
|
||||
|
||||
/// The number of [`BLOCK_SIZE`] blocks (i.e, level 0 blocks)
|
||||
/// in a block of this level
|
||||
pub fn blocks(self) -> i64 {
|
||||
1 << self.0
|
||||
pub fn blocks<T: From<u32>>(self) -> T {
|
||||
T::from(1u32 << self.0)
|
||||
}
|
||||
|
||||
/// The number of bytes in a block of this level
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ fn node_attr(node: &TreeData<Node>) -> FileAttr {
|
||||
ino: node.id() as u64,
|
||||
size: node.data().size(),
|
||||
// Blocks is in 512 byte blocks, not in our block size
|
||||
blocks: node.data().size().div_ceil(BLOCK_SIZE) * (BLOCK_SIZE / 512),
|
||||
blocks: node.data().blocks() * (BLOCK_SIZE / 512),
|
||||
blksize: 512,
|
||||
atime: SystemTime::UNIX_EPOCH + Duration::new(node.data().atime().0, node.data().atime().1),
|
||||
mtime: SystemTime::UNIX_EPOCH + Duration::new(node.data().mtime().0, node.data().mtime().1),
|
||||
|
||||
@@ -14,7 +14,7 @@ use syscall::flag::{
|
||||
};
|
||||
use syscall::{EBADFD, PAGE_SIZE};
|
||||
|
||||
use crate::{Disk, Node, Transaction, TreePtr};
|
||||
use crate::{Disk, Node, Transaction, TreePtr, BLOCK_SIZE};
|
||||
|
||||
pub type Fmaps = BTreeMap<u32, FileMmapInfo>;
|
||||
|
||||
@@ -117,13 +117,15 @@ pub trait Resource<D: Disk> {
|
||||
st_uid: node.data().uid(),
|
||||
st_gid: node.data().gid(),
|
||||
st_size: node.data().size(),
|
||||
st_blksize: 512,
|
||||
// Blocks is in 512 byte blocks, not in our block size
|
||||
st_blocks: node.data().blocks() * (BLOCK_SIZE / 512),
|
||||
st_mtime: mtime.0,
|
||||
st_mtime_nsec: mtime.1,
|
||||
st_atime: atime.0,
|
||||
st_atime_nsec: atime.1,
|
||||
st_ctime: ctime.0,
|
||||
st_ctime_nsec: ctime.1,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
||||
+27
-7
@@ -107,17 +107,25 @@ pub struct Node {
|
||||
|
||||
/// The length of this file, in bytes
|
||||
pub size: Le<u64>,
|
||||
/// The disk usage of this file, in blocks
|
||||
pub blocks: Le<u64>,
|
||||
|
||||
/// Creation time
|
||||
pub ctime: Le<u64>,
|
||||
pub ctime_nsec: Le<u32>,
|
||||
|
||||
/// Modification time
|
||||
pub mtime: Le<u64>,
|
||||
pub mtime_nsec: Le<u32>,
|
||||
|
||||
/// Access time
|
||||
pub atime: Le<u64>,
|
||||
pub atime_nsec: Le<u32>,
|
||||
|
||||
/// Record level
|
||||
pub record_level: Le<u32>,
|
||||
|
||||
pub padding: [u8; BLOCK_SIZE as usize - 4094],
|
||||
pub padding: [u8; BLOCK_SIZE as usize - 4038],
|
||||
|
||||
/// The first 128 blocks of this file.
|
||||
///
|
||||
@@ -143,11 +151,11 @@ pub struct Node {
|
||||
/// Total size: 16 * 256 * 256 * 256 * RECORD_SIZE (32 TiB, 2 TiB each)
|
||||
pub level3: [BlockPtr<BlockListL3>; 16],
|
||||
|
||||
/// The next 12 * 256 * 256 * 256 * 256 blocks of this file,
|
||||
/// stored behind 12 level four tables.
|
||||
/// The next 8 * 256 * 256 * 256 * 256 blocks of this file,
|
||||
/// stored behind 8 level four tables.
|
||||
///
|
||||
/// Total size: 12 * 256 * 256 * 256 * 256 * RECORD_SIZE (6 PiB, 512 TiB each)
|
||||
pub level4: [BlockPtr<BlockListL4>; 12],
|
||||
/// Total size: 8 * 256 * 256 * 256 * 256 * RECORD_SIZE (4 PiB, 512 TiB each)
|
||||
pub level4: [BlockPtr<BlockListL4>; 8],
|
||||
}
|
||||
|
||||
unsafe impl BlockTrait for Node {
|
||||
@@ -168,6 +176,9 @@ impl Default for Node {
|
||||
gid: 0.into(),
|
||||
links: 0.into(),
|
||||
size: 0.into(),
|
||||
// Node counts as a block.
|
||||
//TODO: track all the blocks in indirect levels
|
||||
blocks: 1.into(),
|
||||
ctime: 0.into(),
|
||||
ctime_nsec: 0.into(),
|
||||
mtime: 0.into(),
|
||||
@@ -175,12 +186,12 @@ impl Default for Node {
|
||||
atime: 0.into(),
|
||||
atime_nsec: 0.into(),
|
||||
record_level: 0.into(),
|
||||
padding: [0; BLOCK_SIZE as usize - 4094],
|
||||
padding: [0; BLOCK_SIZE as usize - 4038],
|
||||
level0: [BlockPtr::default(); 128],
|
||||
level1: [BlockPtr::default(); 64],
|
||||
level2: [BlockPtr::default(); 32],
|
||||
level3: [BlockPtr::default(); 16],
|
||||
level4: [BlockPtr::default(); 12],
|
||||
level4: [BlockPtr::default(); 8],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,6 +264,11 @@ impl Node {
|
||||
self.size.to_ne()
|
||||
}
|
||||
|
||||
/// The disk usage of this file, in blocks.
|
||||
pub fn blocks(&self) -> u64 {
|
||||
self.blocks.to_ne()
|
||||
}
|
||||
|
||||
pub fn ctime(&self) -> (u64, u32) {
|
||||
(self.ctime.to_ne(), self.ctime_nsec.to_ne())
|
||||
}
|
||||
@@ -289,6 +305,10 @@ impl Node {
|
||||
self.size = size.into();
|
||||
}
|
||||
|
||||
pub fn set_blocks(&mut self, blocks: u64) {
|
||||
self.blocks = blocks.into();
|
||||
}
|
||||
|
||||
pub fn set_mtime(&mut self, mtime: u64, mtime_nsec: u32) {
|
||||
self.mtime = mtime.into();
|
||||
self.mtime_nsec = mtime_nsec.into();
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
use crate::htree::{HTreeHash, HTreeNode, HTreePtr, HTREE_IDX_ENTRIES};
|
||||
use crate::{
|
||||
unmount_path, BlockAddr, BlockData, BlockLevel, BlockPtr, DirEntry, DirList, DiskMemory,
|
||||
unmount_path, BlockAddr, BlockData, BlockMeta, BlockPtr, DirEntry, DirList, DiskMemory,
|
||||
DiskSparse, FileSystem, Node, TreePtr, ALLOC_GC_THRESHOLD, BLOCK_SIZE,
|
||||
};
|
||||
use core::panic::AssertUnwindSafe;
|
||||
@@ -515,7 +515,7 @@ fn create_minimal_l2_htree(
|
||||
let mut parent = tx.read_tree(parent_ptr).unwrap();
|
||||
|
||||
let child1_block_data = BlockData::new(
|
||||
unsafe { tx.allocate(BlockLevel::default()) }.unwrap(),
|
||||
unsafe { tx.allocate(BlockMeta::default()) }.unwrap(),
|
||||
Node::new(
|
||||
Node::MODE_FILE,
|
||||
parent.data().uid(),
|
||||
|
||||
+61
-25
@@ -84,7 +84,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
let mut found = false;
|
||||
for i in (0..self.allocator_log.len()).rev() {
|
||||
let entry = self.allocator_log[i];
|
||||
if entry.index() == addr.index() && entry.count() == -addr.level().blocks() {
|
||||
if entry.index() == addr.index() && entry.count() == -addr.level().blocks::<i64>() {
|
||||
found = true;
|
||||
self.allocator_log.remove(i);
|
||||
break;
|
||||
@@ -100,14 +100,44 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn deallocate_block<T: BlockTrait>(&mut self, ptr: BlockPtr<T>) {
|
||||
if !ptr.is_null() {
|
||||
unsafe {
|
||||
self.deallocate(ptr.addr());
|
||||
}
|
||||
unsafe fn node_allocate(
|
||||
&mut self,
|
||||
node: &mut TreeData<Node>,
|
||||
meta: BlockMeta,
|
||||
) -> Result<BlockAddr> {
|
||||
let addr = self.allocate(meta)?;
|
||||
let blocks = node.data().blocks();
|
||||
node.data_mut().set_blocks(
|
||||
blocks
|
||||
.checked_add(addr.level().blocks())
|
||||
.expect("node allocated too many blocks"),
|
||||
);
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
unsafe fn node_deallocate(&mut self, node: &mut TreeData<Node>, addr: BlockAddr) -> bool {
|
||||
if !addr.is_null() {
|
||||
self.deallocate(addr);
|
||||
let blocks = node.data().blocks();
|
||||
node.data_mut().set_blocks(
|
||||
blocks
|
||||
.checked_sub(addr.level().blocks())
|
||||
.expect("node deallocated too many blocks"),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn node_deallocate_block<T: BlockTrait>(
|
||||
&mut self,
|
||||
node: &mut TreeData<Node>,
|
||||
ptr: BlockPtr<T>,
|
||||
) -> bool {
|
||||
self.node_deallocate(node, ptr.addr())
|
||||
}
|
||||
|
||||
/// Drain `self.allocator_log` and `self.deallocate`,
|
||||
/// updating the [`AllocList`] with the resulting state.
|
||||
///
|
||||
@@ -1343,13 +1373,15 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
unsafe {
|
||||
match NodeLevel::new(record_offset).ok_or(Error::new(ERANGE))? {
|
||||
NodeLevel::L0(i0) => {
|
||||
self.deallocate_block(node.data_mut().level0[i0].clear());
|
||||
let ptr = node.data_mut().level0[i0].clear();
|
||||
self.node_deallocate_block(node, ptr);
|
||||
}
|
||||
NodeLevel::L1(i1, i0) => {
|
||||
let mut l0 = self.read_block_or_empty(node.data().level1[i1])?;
|
||||
self.deallocate_block(l0.data_mut().ptrs[i0].clear());
|
||||
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
|
||||
if l0.data().is_empty() {
|
||||
self.deallocate_block(node.data_mut().level1[i1].clear());
|
||||
let ptr = node.data_mut().level1[i1].clear();
|
||||
self.node_deallocate_block(node, ptr);
|
||||
} else {
|
||||
node.data_mut().level1[i1] = self.sync_block(l0)?;
|
||||
}
|
||||
@@ -1357,14 +1389,15 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
NodeLevel::L2(i2, i1, i0) => {
|
||||
let mut l1 = self.read_block_or_empty(node.data().level2[i2])?;
|
||||
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
|
||||
self.deallocate_block(l0.data_mut().ptrs[i0].clear());
|
||||
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
|
||||
if l0.data().is_empty() {
|
||||
self.deallocate_block(l1.data_mut().ptrs[i1].clear());
|
||||
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
|
||||
} else {
|
||||
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
|
||||
}
|
||||
if l1.data().is_empty() {
|
||||
self.deallocate_block(node.data_mut().level2[i2].clear());
|
||||
let ptr = node.data_mut().level2[i2].clear();
|
||||
self.node_deallocate_block(node, ptr);
|
||||
} else {
|
||||
node.data_mut().level2[i2] = self.sync_block(l1)?;
|
||||
}
|
||||
@@ -1373,19 +1406,20 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
let mut l2 = self.read_block_or_empty(node.data().level3[i3])?;
|
||||
let mut l1 = self.read_block_or_empty(l2.data().ptrs[i2])?;
|
||||
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
|
||||
self.deallocate_block(l0.data_mut().ptrs[i0].clear());
|
||||
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
|
||||
if l0.data().is_empty() {
|
||||
self.deallocate_block(l1.data_mut().ptrs[i1].clear());
|
||||
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
|
||||
} else {
|
||||
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
|
||||
}
|
||||
if l1.data().is_empty() {
|
||||
self.deallocate_block(l2.data_mut().ptrs[i2].clear());
|
||||
self.node_deallocate_block(node, l2.data_mut().ptrs[i2].clear());
|
||||
} else {
|
||||
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
|
||||
}
|
||||
if l2.data().is_empty() {
|
||||
self.deallocate_block(node.data_mut().level3[i3].clear());
|
||||
let ptr = node.data_mut().level3[i3].clear();
|
||||
self.node_deallocate_block(node, ptr);
|
||||
} else {
|
||||
node.data_mut().level3[i3] = self.sync_block(l2)?;
|
||||
}
|
||||
@@ -1395,24 +1429,25 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
let mut l2 = self.read_block_or_empty(l3.data().ptrs[i3])?;
|
||||
let mut l1 = self.read_block_or_empty(l2.data().ptrs[i2])?;
|
||||
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
|
||||
self.deallocate_block(l0.data_mut().ptrs[i0].clear());
|
||||
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
|
||||
if l0.data().is_empty() {
|
||||
self.deallocate_block(l1.data_mut().ptrs[i1].clear());
|
||||
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
|
||||
} else {
|
||||
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
|
||||
}
|
||||
if l1.data().is_empty() {
|
||||
self.deallocate_block(l2.data_mut().ptrs[i2].clear());
|
||||
self.node_deallocate_block(node, l2.data_mut().ptrs[i2].clear());
|
||||
} else {
|
||||
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
|
||||
}
|
||||
if l2.data().is_empty() {
|
||||
self.deallocate_block(l3.data_mut().ptrs[i3].clear());
|
||||
self.node_deallocate_block(node, l3.data_mut().ptrs[i3].clear());
|
||||
} else {
|
||||
l3.data_mut().ptrs[i3] = self.sync_block(l2)?;
|
||||
}
|
||||
if l3.data().is_empty() {
|
||||
self.deallocate_block(node.data_mut().level4[i4].clear());
|
||||
let ptr = node.data_mut().level4[i4].clear();
|
||||
self.node_deallocate_block(node, ptr);
|
||||
} else {
|
||||
node.data_mut().level4[i4] = self.sync_block(l3)?;
|
||||
}
|
||||
@@ -1676,8 +1711,8 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
}
|
||||
|
||||
// CoW record using its current level
|
||||
let mut old_addr =
|
||||
unsafe { record.swap_addr(self.allocate(record.addr().meta())?) };
|
||||
let new_addr = unsafe { self.node_allocate(node, record.addr().meta())? };
|
||||
let mut old_addr = record.swap_addr(new_addr);
|
||||
|
||||
// If the record was resized we need to dealloc the original ptr
|
||||
if old_addr.is_null() {
|
||||
@@ -1685,6 +1720,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
}
|
||||
|
||||
// Write record to disk
|
||||
//TODO: deallocate new_addr on failure?
|
||||
record_ptr = unsafe { self.write_block(record)? };
|
||||
|
||||
// Update record pointer
|
||||
@@ -1692,8 +1728,8 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
node_changed = true;
|
||||
|
||||
// Deallocate old record
|
||||
if !old_addr.is_null() {
|
||||
unsafe { self.deallocate(old_addr) };
|
||||
unsafe {
|
||||
self.node_deallocate(node, old_addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -224,7 +224,7 @@ impl<T> Default for TreePtr<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{BlockAddr, BlockData};
|
||||
use crate::{BlockAddr, BlockData, BlockMeta};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -257,7 +257,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn mock_block(addr: u64) -> BlockPtr<BlockRaw> {
|
||||
let block_addr = unsafe { BlockAddr::new(addr, BlockLevel::default()) };
|
||||
let block_addr = unsafe { BlockAddr::new(addr, BlockMeta::default()) };
|
||||
BlockData::empty(block_addr).unwrap().create_ptr()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user