begin switching to limited data size per file
This commit is contained in:
parent
e7d5daa623
commit
bdd7ba3f36
3 changed files with 502 additions and 247 deletions
|
@ -6,4 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vapfs = { path = "../vapfs" }
|
vapfs = { path = "../vapfs" }
|
||||||
|
ondisk_btree = { path = "../../ondisk_btree" }
|
636
src/lib.rs
636
src/lib.rs
|
@ -296,80 +296,157 @@ pub fn next_journal_position(sb: &Superblock, bd: &mut dyn BlockDevice) -> Optio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the index of an indirectly indexed datablock, or 0 if it does not exist.
|
/// Returns the index of the containing indirect block for the given dba address and the index in that indirect block, or None if the address is invalid.
|
||||||
pub fn get_indirect_datablock(sb: &Superblock, bd: &mut dyn BlockDevice, dbas: [Index; 12], address: Index) -> Index {
|
pub fn get_indirect_datablock(sb: &Superblock, bd: &mut dyn BlockDevice, list: ListBlock, address: Index) -> Option<(Index, Index)> {
|
||||||
if address < 12 {
|
if address < 32 {
|
||||||
dbas[address as usize]
|
None
|
||||||
} else {
|
} else {
|
||||||
let n = address - 12;
|
// copy pasted from structs.rs
|
||||||
let mut blocks_left = n / (sb.block_size as u64 - 8);
|
// if greater than 32, see the following:
|
||||||
let mut indexes_left = n % (sb.block_size as u64 - 8);
|
// let N = (maximum number of pointers in an indirect block) * 32
|
||||||
let mut current_block = dbas[9]; // first indirect block
|
// (beginning...count)
|
||||||
let mut visited = vec![];
|
// 32..N: single indirect block
|
||||||
loop {
|
// 32+N..N^2: double indirect block
|
||||||
if visited.contains(¤t_block) {
|
// 32+N^2..N^3: triple indirect block
|
||||||
return 0;
|
// 32+N^3..N^4: quadruple indirect block
|
||||||
|
// 32+N^4..N^5: quintuple indirect block
|
||||||
|
// 32+N^5..N^6: sextuple indirect block
|
||||||
|
|
||||||
|
// block index is address / (max_per_block ^ (1 if single, 2 if double, etc))
|
||||||
|
// after getting your layer's address, repeat the previous layer's process
|
||||||
|
|
||||||
|
let max_per_block = sb.block_size as u64 / 8;
|
||||||
|
let N = max_per_block * 32;
|
||||||
|
let N2 = N * N;
|
||||||
|
let N3 = N2 * N;
|
||||||
|
let N4 = N3 * N;
|
||||||
|
let N5 = N4 * N;
|
||||||
|
let N6 = N5 * N;
|
||||||
|
|
||||||
|
let mut address = address - 32;
|
||||||
|
|
||||||
|
// todo: you could probably rewrite this using like recursion or smth
|
||||||
|
|
||||||
|
match address {
|
||||||
|
_ if address < N => {
|
||||||
|
let block_index = address / max_per_block;
|
||||||
|
let address = address % max_per_block;
|
||||||
|
Some((list.single_indirect_block_address[block_index as usize], address))
|
||||||
}
|
}
|
||||||
visited.push(current_block);
|
_ if address < N2 => {
|
||||||
let mut head = 0;
|
let address = address - N;
|
||||||
let buf = read_datablock(current_block, sb, bd);
|
let block_index = (address) / (max_per_block ^ 2);
|
||||||
let count = u64::from_be_bytes(buf[0..8].try_into().unwrap());
|
let layer2_block = read_datablock(list.double_indirect_block_address[block_index as usize], sb, bd);
|
||||||
head += 8;
|
let layer2_address = address / max_per_block;
|
||||||
// if blocks_left == 0, we're in the right block (either that or we're in the right block to recurse downwards into)
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
if blocks_left == 0 {
|
buf.copy_from_slice(&layer2_block[(layer2_address * 8) as usize..(layer2_address * 8 + 8) as usize]);
|
||||||
for _ in 0..count.min(indexes_left) {
|
let layer1_block = u64::from_be_bytes(buf);
|
||||||
let isdata_depth = &buf[head..head + 8];
|
let layer1_address = address % max_per_block;
|
||||||
head += 8;
|
Some((layer1_block, layer1_address))
|
||||||
let ptr_data = &buf[head..head + 8];
|
|
||||||
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
|
|
||||||
let is_data = isdata_depth[1] != 0;
|
|
||||||
// if not data, we need to recurse
|
|
||||||
if !is_data {
|
|
||||||
current_block = ptr;
|
|
||||||
break; // skip the rest of the loop
|
|
||||||
} else {
|
|
||||||
// if indexes_left == 0, we found the correct index
|
|
||||||
if indexes_left == 0 {
|
|
||||||
return ptr;
|
|
||||||
} else {
|
|
||||||
indexes_left -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _ in 0..count {
|
|
||||||
let isdata_depth = &buf[head..head + 8];
|
|
||||||
head += 8;
|
|
||||||
let ptr_data = &buf[head..head + 8];
|
|
||||||
let ptr = u64::from_be_bytes(ptr_data.try_into().unwrap());
|
|
||||||
let is_data = isdata_depth[1] != 0;
|
|
||||||
let mut depth = isdata_depth.to_vec();
|
|
||||||
depth[0] = 0;
|
|
||||||
let depth = u64::from_be_bytes(depth.try_into().unwrap());
|
|
||||||
// if blocks_left is less than the depth, we are at the correct block
|
|
||||||
if !is_data {
|
|
||||||
if blocks_left < depth {
|
|
||||||
// if not data, we need to recurse
|
|
||||||
blocks_left = 0;
|
|
||||||
current_block = ptr;
|
|
||||||
break; // skip the rest of the loop
|
|
||||||
} else {
|
|
||||||
blocks_left -= depth;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if indexes_left == 0, we found the correct index
|
|
||||||
if indexes_left == 0 {
|
|
||||||
return ptr;
|
|
||||||
} else {
|
|
||||||
indexes_left -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_ if address < N3 => {
|
||||||
|
let address = address - N2;
|
||||||
|
let block_index = (address) / (max_per_block ^ 3);
|
||||||
|
let layer3_block = read_datablock(list.triple_indirect_block_address[block_index as usize], sb, bd);
|
||||||
|
let layer3_address = address / (max_per_block ^ 2);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer3_block[(layer3_address * 8) as usize..(layer3_address * 8 + 8) as usize]);
|
||||||
|
let layer2_block = u64::from_be_bytes(buf);
|
||||||
|
let layer2_address = (address % (max_per_block ^ 2)) / max_per_block;
|
||||||
|
let layer2_block = read_datablock(layer2_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer2_block[(layer2_address * 8) as usize..(layer2_address * 8 + 8) as usize]);
|
||||||
|
let layer1_block = u64::from_be_bytes(buf);
|
||||||
|
let layer1_address = address % max_per_block;
|
||||||
|
Some((layer1_block, layer1_address))
|
||||||
|
}
|
||||||
|
_ if address < N4 => {
|
||||||
|
let address = address - N3;
|
||||||
|
let block_index = (address) / (max_per_block ^ 4);
|
||||||
|
let layer4_block = read_datablock(list.quadruple_indirect_block_address[block_index as usize], sb, bd);
|
||||||
|
let layer4_address = address / (max_per_block ^ 3);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer4_block[(layer4_address * 8) as usize..(layer4_address * 8 + 8) as usize]);
|
||||||
|
let layer3_block = u64::from_be_bytes(buf);
|
||||||
|
let layer3_address = (address % (max_per_block ^ 3)) / (max_per_block ^ 2);
|
||||||
|
let layer3_block = read_datablock(layer3_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer3_block[(layer3_address * 8) as usize..(layer3_address * 8 + 8) as usize]);
|
||||||
|
let layer2_block = u64::from_be_bytes(buf);
|
||||||
|
let layer2_address = (address % (max_per_block ^ 2)) / max_per_block;
|
||||||
|
let layer2_block = read_datablock(layer2_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer2_block[(layer2_address * 8) as usize..(layer2_address * 8 + 8) as usize]);
|
||||||
|
let layer1_block = u64::from_be_bytes(buf);
|
||||||
|
let layer1_address = address % max_per_block;
|
||||||
|
Some((layer1_block, layer1_address))
|
||||||
|
}
|
||||||
|
_ if address < N5 => {
|
||||||
|
let address = address - N4;
|
||||||
|
let block_index = (address) / (max_per_block ^ 5);
|
||||||
|
let layer5_block = read_datablock(list.quintuple_indirect_block_address[block_index as usize], sb, bd);
|
||||||
|
let layer5_address = address / (max_per_block ^ 4);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer5_block[(layer5_address * 8) as usize..(layer5_address * 8 + 8) as usize]);
|
||||||
|
let layer4_block = u64::from_be_bytes(buf);
|
||||||
|
let layer4_address = (address % (max_per_block ^ 4)) / (max_per_block ^ 3);
|
||||||
|
let layer4_block = read_datablock(layer4_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer4_block[(layer4_address * 8) as usize..(layer4_address * 8 + 8) as usize]);
|
||||||
|
let layer3_block = u64::from_be_bytes(buf);
|
||||||
|
let layer3_address = (address % (max_per_block ^ 3)) / (max_per_block ^ 2);
|
||||||
|
let layer3_block = read_datablock(layer3_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer3_block[(layer3_address * 8) as usize..(layer3_address * 8 + 8) as usize]);
|
||||||
|
let layer2_block = u64::from_be_bytes(buf);
|
||||||
|
let layer2_address = (address % (max_per_block ^ 2)) / max_per_block;
|
||||||
|
let layer2_block = read_datablock(layer2_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer2_block[(layer2_address * 8) as usize..(layer2_address * 8 + 8) as usize]);
|
||||||
|
let layer1_block = u64::from_be_bytes(buf);
|
||||||
|
let layer1_address = address % max_per_block;
|
||||||
|
Some((layer1_block, layer1_address))
|
||||||
|
}
|
||||||
|
_ if address < N6 => {
|
||||||
|
let address = address - N5;
|
||||||
|
let block_index = (address) / (max_per_block ^ 6);
|
||||||
|
let layer6_block = read_datablock(list.sextuple_indirect_block_address[block_index as usize], sb, bd);
|
||||||
|
let layer6_address = address / (max_per_block ^ 5);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer6_block[(layer6_address * 8) as usize..(layer6_address * 8 + 8) as usize]);
|
||||||
|
let layer5_block = u64::from_be_bytes(buf);
|
||||||
|
let layer5_address = (address % (max_per_block ^ 5)) / (max_per_block ^ 4);
|
||||||
|
let layer5_block = read_datablock(layer5_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer5_block[(layer5_address * 8) as usize..(layer5_address * 8 + 8) as usize]);
|
||||||
|
let layer4_block = u64::from_be_bytes(buf);
|
||||||
|
let layer4_address = (address % (max_per_block ^ 4)) / (max_per_block ^ 3);
|
||||||
|
let layer4_block = read_datablock(layer4_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer4_block[(layer4_address * 8) as usize..(layer4_address * 8 + 8) as usize]);
|
||||||
|
let layer3_block = u64::from_be_bytes(buf);
|
||||||
|
let layer3_address = (address % (max_per_block ^ 3)) / (max_per_block ^ 2);
|
||||||
|
let layer3_block = read_datablock(layer3_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer3_block[(layer3_address * 8) as usize..(layer3_address * 8 + 8) as usize]);
|
||||||
|
let layer2_block = u64::from_be_bytes(buf);
|
||||||
|
let layer2_address = (address % (max_per_block ^ 2)) / max_per_block;
|
||||||
|
let layer2_block = read_datablock(layer2_block, sb, bd);
|
||||||
|
let mut buf: [u8; 8] = [0; 8];
|
||||||
|
buf.copy_from_slice(&layer2_block[(layer2_address * 8) as usize..(layer2_address * 8 + 8) as usize]);
|
||||||
|
let layer1_block = u64::from_be_bytes(buf);
|
||||||
|
let layer1_address = address % max_per_block;
|
||||||
|
Some((layer1_block, layer1_address))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resizes an inode to the given size.
|
||||||
|
/// # Safety
|
||||||
|
/// unsafe because it does not journal the write, and does not update any other metadata.
|
||||||
|
|
||||||
/// Creates a journal entry for a single block write operation.
|
/// Creates a journal entry for a single block write operation.
|
||||||
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
|
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
|
||||||
/// Returns None if the journal is full, or if the block device cannot be written to.
|
/// Returns None if the journal is full, or if the block device cannot be written to.
|
||||||
|
@ -447,7 +524,7 @@ pub fn schedule_single_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, co
|
||||||
|
|
||||||
/// Creates a journal entry for a multi block write operation.
|
/// Creates a journal entry for a multi block write operation.
|
||||||
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
|
/// Should be safe to call at anytime, and shouldn't corrupt anything if the system crashes.
|
||||||
/// Returns None if the journal is full, or if the block device cannot be written to.
|
/// Returns None if the journal is full, if the block device cannot be written to, or if you're somehow trying to write over 2105000 terabytes of data.
|
||||||
/// Returns the journal entry index if successful.
|
/// Returns the journal entry index if successful.
|
||||||
pub fn schedule_multi_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, containing_inode_index: Index, datablock_start: Index, datablock_count: Index, data: &[u8]) -> Option<Index> {
|
pub fn schedule_multi_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, containing_inode_index: Index, datablock_start: Index, datablock_count: Index, data: &[u8]) -> Option<Index> {
|
||||||
let entry_index = next_journal_position(sb, bd)?;
|
let entry_index = next_journal_position(sb, bd)?;
|
||||||
|
@ -514,148 +591,314 @@ pub fn schedule_multi_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, con
|
||||||
|
|
||||||
// create a list block
|
// create a list block
|
||||||
let mut list_block = ListBlock {
|
let mut list_block = ListBlock {
|
||||||
using_indirect_blocks: datablock_count > 12,
|
count: 0,
|
||||||
direct_block_addresses: [0; 12],
|
direct_block_addresses: [0; 32],
|
||||||
|
single_indirect_block_address: [0; 32],
|
||||||
|
double_indirect_block_address: [0; 32],
|
||||||
|
triple_indirect_block_address: [0; 32],
|
||||||
|
quadruple_indirect_block_address: [0; 32],
|
||||||
|
quintuple_indirect_block_address: [0; 32],
|
||||||
|
sextuple_indirect_block_address: [0; 32],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut old_list_block = ListBlock {
|
let mut old_list_block = ListBlock {
|
||||||
using_indirect_blocks: false,
|
count: 0,
|
||||||
direct_block_addresses: [0; 12],
|
direct_block_addresses: [0; 32],
|
||||||
|
single_indirect_block_address: [0; 32],
|
||||||
|
double_indirect_block_address: [0; 32],
|
||||||
|
triple_indirect_block_address: [0; 32],
|
||||||
|
quadruple_indirect_block_address: [0; 32],
|
||||||
|
quintuple_indirect_block_address: [0; 32],
|
||||||
|
sextuple_indirect_block_address: [0; 32],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut indirect_blocks_waiting_for_allocation_to_be_set = Vec::new();
|
let mut indirect_blocks_waiting_for_allocation_to_be_set = Vec::new();
|
||||||
|
|
||||||
// if using indirect blocks, only fill out the first (12 - 3) = 9 entries
|
// if using indirect blocks, only fill out the dba
|
||||||
// otherwise, fill out all 12 entries
|
// otherwise, have fun!
|
||||||
if list_block.using_indirect_blocks {
|
if datablock_count > 32 {
|
||||||
list_block.direct_block_addresses[..9].copy_from_slice(&allocated_blocks[..9]);
|
list_block.direct_block_addresses.copy_from_slice(&allocated_blocks[..32]);
|
||||||
|
list_block.count = 32;
|
||||||
|
|
||||||
// if using indirect blocks, fit the remaining entries into the indirect blocks
|
// set the indirect blocks
|
||||||
// layout is u64 count followed by u64 addresses
|
let max_per_block = sb.block_size as u64 / 8;
|
||||||
let max_addresses_per_block = (sb.block_size as usize - core::mem::size_of::<u64>()) / (core::mem::size_of::<u64>() * 2);
|
let N = max_per_block * 32;
|
||||||
let mut indirect_block_count = (datablock_count - 9) / max_addresses_per_block as u64;
|
let N2 = N * N;
|
||||||
// if the count is not a multiple of the max addresses per block, add one
|
let N3 = N2 * N;
|
||||||
if (datablock_count - 9) % max_addresses_per_block as u64 != 0 {
|
let N4 = N3 * N;
|
||||||
indirect_block_count += 1;
|
let N5 = N4 * N;
|
||||||
}
|
let N6 = N5 * N;
|
||||||
// if the count is over 3, we'll need to use nested indirect blocks
|
// figure out how many blocks we need for all indirect blocks
|
||||||
// calculate how many layers of indirect blocks we'll need,
|
let mut indirect_blocks_needed = 0;
|
||||||
// filling max_addresses per block until we have less than max_addresses_per_block left
|
// can we fit them all in the 32 single indirect blocks?
|
||||||
// this will be the amount of layers required to store the data
|
let dba_count = datablock_count - 32;
|
||||||
let depth = {
|
// enclosed in brackets so that you can collapse it in the IDE (:
|
||||||
let mut depth = 0;
|
{
|
||||||
let mut remaining = indirect_block_count;
|
if dba_count < N {
|
||||||
while remaining > max_addresses_per_block as u64 {
|
// yes we can
|
||||||
remaining -= max_addresses_per_block as u64;
|
// how many indirect blocks do we need?
|
||||||
depth += 1;
|
indirect_blocks_needed = (dba_count / max_per_block) + 1;
|
||||||
|
} else if dba_count < N2 {
|
||||||
|
// no, but we can fit it in the double indirect blocks
|
||||||
|
// first, fill up the single indirect blocks
|
||||||
|
indirect_blocks_needed = N / max_per_block;
|
||||||
|
let datablocks_left = dba_count - N;
|
||||||
|
// how many double indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N) + 1;
|
||||||
|
// how many single indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / max_per_block) + 1;
|
||||||
|
} else if dba_count < N3 {
|
||||||
|
// this fills up the single and double indirect blocks
|
||||||
|
indirect_blocks_needed = N / max_per_block; // 32 single indirect blocks
|
||||||
|
indirect_blocks_needed += N2 / N;
|
||||||
|
let datablocks_left = dba_count - N2;
|
||||||
|
// how many triple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N2) + 1;
|
||||||
|
// how many double indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N) + 1;
|
||||||
|
// how many single indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / max_per_block) + 1;
|
||||||
|
} else if dba_count < N4 {
|
||||||
|
// this fills up the single, double, and triple indirect blocks
|
||||||
|
indirect_blocks_needed = N / max_per_block;
|
||||||
|
indirect_blocks_needed += N2 / N;
|
||||||
|
indirect_blocks_needed += N3 / N2;
|
||||||
|
let datablocks_left = dba_count - N3;
|
||||||
|
// how many quadruple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N3) + 1;
|
||||||
|
// how many triple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N2) + 1;
|
||||||
|
// how many double indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N) + 1;
|
||||||
|
// how many single indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / max_per_block) + 1;
|
||||||
|
} else if dba_count < N5 {
|
||||||
|
// this fills up the single, double, triple, and quadruple indirect blocks
|
||||||
|
indirect_blocks_needed = N / max_per_block;
|
||||||
|
indirect_blocks_needed += N2 / N;
|
||||||
|
indirect_blocks_needed += N3 / N2;
|
||||||
|
indirect_blocks_needed += N4 / N3;
|
||||||
|
let datablocks_left = dba_count - N4;
|
||||||
|
// how many quintuple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N4) + 1;
|
||||||
|
// how many quadruple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N3) + 1;
|
||||||
|
// how many triple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N2) + 1;
|
||||||
|
// how many double indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N) + 1;
|
||||||
|
// how many single indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / max_per_block) + 1;
|
||||||
|
} else if dba_count < N6 {
|
||||||
|
// this fills up the single, double, triple, quadruple, and quintuple indirect blocks
|
||||||
|
indirect_blocks_needed = N / max_per_block;
|
||||||
|
indirect_blocks_needed += N2 / N;
|
||||||
|
indirect_blocks_needed += N3 / N2;
|
||||||
|
indirect_blocks_needed += N4 / N3;
|
||||||
|
indirect_blocks_needed += N5 / N4;
|
||||||
|
let datablocks_left = dba_count - N5;
|
||||||
|
// how many sextuple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N5) + 1;
|
||||||
|
// how many quintuple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N4) + 1;
|
||||||
|
// how many quadruple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N3) + 1;
|
||||||
|
// how many triple indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N2) + 1;
|
||||||
|
// how many double indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / N) + 1;
|
||||||
|
// how many single indirect blocks do we need?
|
||||||
|
indirect_blocks_needed += (datablocks_left / max_per_block) + 1;
|
||||||
|
} else {
|
||||||
|
// congratulations, you've attempted to write around 2105000 terabytes of data
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
depth
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// allocate the indirect blocks
|
// allocate the indirect blocks
|
||||||
let indirect_blocks = find_count_unallocated_datablocks(sb, bd, indirect_block_count as usize + (depth * max_addresses_per_block))?;
|
let indirect_blocks = find_count_unallocated_datablocks(sb, bd, indirect_blocks_needed as usize)?;
|
||||||
for i in 0..(indirect_block_count as usize + (depth * max_addresses_per_block)) {
|
|
||||||
list_block.direct_block_addresses[9 + i] = indirect_blocks[i];
|
|
||||||
indirect_blocks_waiting_for_allocation_to_be_set.push(indirect_blocks[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the indirect blocks
|
// fill with data
|
||||||
let mut indirect_block_data = vec![0; core::mem::size_of::<u64>() * max_addresses_per_block];
|
let mut i = 0;
|
||||||
let mut indirect_blocks_from_previous_layer = VecDeque::new();
|
let mut taken = 0;
|
||||||
let mut indirect_blocks_from_previous_layer_alt = VecDeque::new();
|
let data = &allocated_blocks[32..];
|
||||||
let mut using_alt = false;
|
|
||||||
let mut acc: VecDeque<u64> = VecDeque::new(); // how much each previous layer has had
|
|
||||||
let mut acc_alt: VecDeque<u64> = VecDeque::new(); // how much each previous layer has had
|
|
||||||
for i in 0..(indirect_block_count as usize + (depth * max_addresses_per_block)) {
|
|
||||||
// we will write the indirect blocks that contain the data blocks first
|
|
||||||
// then we will write the indirect blocks that contain the indirect blocks
|
|
||||||
|
|
||||||
// are we writing the indirect blocks that contain the data blocks?
|
// once again enclosed so that you can collapse it in the IDE (:
|
||||||
let writing_data_blocks = i < indirect_block_count as usize;
|
{
|
||||||
if writing_data_blocks {
|
fn fillwithdata_1(
|
||||||
let count = if i == (indirect_block_count - 1) as usize { // if we're at the last block, not all of the addresses will be used
|
sb: &Superblock, bd: &mut dyn BlockDevice, i: &mut u64, data: &[Index],
|
||||||
(datablock_count - 9) % max_addresses_per_block as u64
|
block_size: usize, max_per_block: u64, indirect_blocks: &mut Vec<Index>,
|
||||||
} else {
|
taken: &mut usize, dbas: &mut [Index], max: usize) -> bool {
|
||||||
max_addresses_per_block as u64 // otherwise, all of the addresses will be used
|
for block1 in 0..max {
|
||||||
};
|
if *i >= data.len() as u64 {
|
||||||
// add count
|
break;
|
||||||
unsafe { core::ptr::write(indirect_block_data.as_mut_ptr() as *mut u64, count); }
|
}
|
||||||
// add addresses
|
let mut buf = vec![0u8; block_size];
|
||||||
for j in 0..count {
|
let mut j = 0;
|
||||||
unsafe { core::ptr::write((indirect_block_data.as_mut_ptr() as *mut u64).add(8 + j as usize), allocated_blocks[9 + i * max_addresses_per_block + j as usize]); }
|
while j < max_per_block {
|
||||||
|
let index = *i % max_per_block;
|
||||||
|
if *i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[index as usize * 8..(index as usize + 1) * 8].copy_from_slice(&data[*i as usize].to_be_bytes());
|
||||||
|
*i += 1;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[*taken], sb, bd, &buf) } {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*taken += 1;
|
||||||
|
dbas[block1] = indirect_blocks[*taken - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the indirect block
|
true
|
||||||
if !unsafe { write_datablock(indirect_blocks[i], sb, bd, &indirect_block_data) } {
|
}
|
||||||
|
|
||||||
|
// single indirect blocks
|
||||||
|
if !fillwithdata_1(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut list_block.single_indirect_block_address, 32) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// double indirect blocks
|
||||||
|
for block2 in 0..32 {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut list = vec![0u64; max_per_block as usize];
|
||||||
|
if !fillwithdata_1(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut list, max_per_block as usize) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let buf = list.iter().map(|x| x.to_be_bytes()).flatten().collect::<Vec<u8>>();
|
||||||
indirect_blocks_from_previous_layer.push_back(indirect_blocks[i]);
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
acc.push_back(count);
|
return None;
|
||||||
} else {
|
|
||||||
// we're writing the indirect blocks that contain the indirect blocks
|
|
||||||
if !using_alt {
|
|
||||||
|
|
||||||
// write addresses from front of indirect_blocks_from_previous_layer
|
|
||||||
let count = if indirect_blocks_from_previous_layer.len() > max_addresses_per_block - 8 {
|
|
||||||
max_addresses_per_block - 8
|
|
||||||
} else {
|
|
||||||
indirect_blocks_from_previous_layer.len()
|
|
||||||
};
|
|
||||||
// add count
|
|
||||||
unsafe { core::ptr::write(indirect_block_data.as_mut_ptr() as *mut u64, count as u64); }
|
|
||||||
// add addresses
|
|
||||||
for j in 0..count {
|
|
||||||
// get acc value
|
|
||||||
let acc_val = acc.pop_front().unwrap_or(0);
|
|
||||||
unsafe { core::ptr::write((indirect_block_data.as_mut_ptr() as *mut u64).add(8 + (j * 16)), acc_val); }
|
|
||||||
unsafe { core::ptr::write((indirect_block_data.as_mut_ptr() as *mut u64).add(8 + 8 + (j * 16)), indirect_blocks_from_previous_layer.pop_front().unwrap_or(0)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the indirect block
|
|
||||||
if !unsafe { write_datablock(indirect_blocks[i], sb, bd, &indirect_block_data) } {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the indirect block to the back of indirect_blocks_from_previous_layer_alt
|
|
||||||
indirect_blocks_from_previous_layer_alt.push_back(indirect_blocks[i]);
|
|
||||||
acc_alt.push_back(count as u64);
|
|
||||||
|
|
||||||
// if indirect_blocks_from_previous_layer is empty, switch to using_alt
|
|
||||||
if indirect_blocks_from_previous_layer.is_empty() {
|
|
||||||
using_alt = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// write addresses from front of indirect_blocks_from_previous_layer_alt
|
|
||||||
let count = if indirect_blocks_from_previous_layer_alt.len() > max_addresses_per_block - 8 {
|
|
||||||
max_addresses_per_block - 8
|
|
||||||
} else {
|
|
||||||
indirect_blocks_from_previous_layer_alt.len()
|
|
||||||
};
|
|
||||||
// add count
|
|
||||||
unsafe { core::ptr::write(indirect_block_data.as_mut_ptr() as *mut u64, count as u64); }
|
|
||||||
// add addresses
|
|
||||||
for j in 0..count {
|
|
||||||
// get acc value
|
|
||||||
let acc_val = acc_alt.pop_front().unwrap_or(0);
|
|
||||||
unsafe { core::ptr::write((indirect_block_data.as_mut_ptr() as *mut u64).add(8 + (j * 16)), acc_val); }
|
|
||||||
unsafe { core::ptr::write((indirect_block_data.as_mut_ptr() as *mut u64).add(8 + 8 + (j * 16)), indirect_blocks_from_previous_layer_alt.pop_front().unwrap_or(0)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the indirect block
|
|
||||||
if !unsafe { write_datablock(indirect_blocks[i], sb, bd, &indirect_block_data) } {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the indirect block to the back of indirect_blocks_from_previous_layer
|
|
||||||
indirect_blocks_from_previous_layer.push_back(indirect_blocks[i]);
|
|
||||||
acc.push_back(count as u64);
|
|
||||||
|
|
||||||
// if indirect_blocks_from_previous_layer_alt is empty, switch to using_alt
|
|
||||||
if indirect_blocks_from_previous_layer_alt.is_empty() {
|
|
||||||
using_alt = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
taken += 1;
|
||||||
|
list_block.double_indirect_block_address[block2 as usize] = indirect_blocks[taken - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// triple indirect blocks
|
||||||
|
fn fillwithdata_2(
|
||||||
|
sb: &Superblock, bd: &mut dyn BlockDevice, i: &mut u64, data: &[Index],
|
||||||
|
block_size: usize, max_per_block: u64, indirect_blocks: &mut Vec<Index>,
|
||||||
|
taken: &mut usize, dbas: &mut [Index], max: usize) -> bool {
|
||||||
|
for block3 in 0..32 {
|
||||||
|
if *i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut buf = vec![0u8; sb.block_size as usize];
|
||||||
|
for block2 in 0..max_per_block {
|
||||||
|
if *i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut buf2 = vec![0u64; max_per_block as usize];
|
||||||
|
fillwithdata_1(sb, bd, i, data, block_size, max_per_block,
|
||||||
|
indirect_blocks, taken,
|
||||||
|
&mut buf2, max_per_block as usize);
|
||||||
|
let buf2 = buf2.iter().map(|x| x.to_be_bytes()).flatten().collect::<Vec<u8>>();
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[*taken], sb, bd, &buf2) } {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*taken += 1;
|
||||||
|
buf[block2 as usize * 8..(block2 as usize + 1) * 8].copy_from_slice(&indirect_blocks[*taken - 1].to_be_bytes());
|
||||||
|
}
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[*taken], sb, bd, &buf) } {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*taken += 1;
|
||||||
|
dbas[block3 as usize] = indirect_blocks[*taken - 1];
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fillwithdata_2(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut list_block.triple_indirect_block_address, 32);
|
||||||
|
|
||||||
|
// quadruple indirect blocks
|
||||||
|
for block4 in 0..32 {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut list = vec![0u64; max_per_block as usize];
|
||||||
|
fillwithdata_2(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut list, max_per_block as usize);
|
||||||
|
let buf = list.iter().map(|x| x.to_be_bytes()).flatten().collect::<Vec<u8>>();
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
list_block.quadruple_indirect_block_address[block4 as usize] = indirect_blocks[taken - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// quintuple indirect blocks
|
||||||
|
for block5 in 0..32 {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut list = vec![0u8; max_per_block as usize];
|
||||||
|
for block4 in 0..max_per_block {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut buf = vec![0u64; max_per_block as usize];
|
||||||
|
fillwithdata_2(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut buf, max_per_block as usize);
|
||||||
|
let buf = buf.iter().map(|x| x.to_be_bytes()).flatten().collect::<Vec<u8>>();
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
list[block4 as usize * 8..(block4 as usize + 1) * 8].copy_from_slice(&indirect_blocks[taken - 1].to_be_bytes());
|
||||||
|
}
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
list_block.quintuple_indirect_block_address[block5 as usize] = indirect_blocks[taken - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// sextuple indirect blocks
|
||||||
|
for block6 in 0..32 {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut list = vec![0u8; max_per_block as usize];
|
||||||
|
for block5 in 0..max_per_block {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut buf = vec![0u8; max_per_block as usize];
|
||||||
|
for block4 in 0..max_per_block {
|
||||||
|
if i >= data.len() as u64 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut buf2 = vec![0u64; max_per_block as usize];
|
||||||
|
fillwithdata_2(sb, bd, &mut i, data, sb.block_size as usize, max_per_block,
|
||||||
|
&mut indirect_blocks_waiting_for_allocation_to_be_set, &mut taken,
|
||||||
|
&mut buf2, max_per_block as usize);
|
||||||
|
let buf2 = buf2.iter().map(|x| x.to_be_bytes()).flatten().collect::<Vec<u8>>();
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf2) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
buf[block4 as usize * 8..(block4 as usize + 1) * 8].copy_from_slice(&indirect_blocks[taken - 1].to_be_bytes());
|
||||||
|
}
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
list[block5 as usize * 8..(block5 as usize + 1) * 8].copy_from_slice(&indirect_blocks[taken - 1].to_be_bytes());
|
||||||
|
}
|
||||||
|
if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
taken += 1;
|
||||||
|
list_block.sextuple_indirect_block_address[block6 as usize] = indirect_blocks[taken - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -664,8 +907,7 @@ pub fn schedule_multi_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, con
|
||||||
|
|
||||||
// read target inode, and write the old list block
|
// read target inode, and write the old list block
|
||||||
let target_inode = read_inode(containing_inode_index, sb, bd)?;
|
let target_inode = read_inode(containing_inode_index, sb, bd)?;
|
||||||
old_list_block.using_indirect_blocks = target_inode.flags & InodeFlags::INDIRECT as u32 != 0;
|
old_list_block = target_inode.listblock;
|
||||||
old_list_block.direct_block_addresses = target_inode.direct_block_addresses;
|
|
||||||
|
|
||||||
// write the list blocks
|
// write the list blocks
|
||||||
let buf = [0; core::mem::size_of::<ListBlock>()];
|
let buf = [0; core::mem::size_of::<ListBlock>()];
|
||||||
|
@ -827,10 +1069,7 @@ pub fn flush_single_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, entry
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if inode.flags & InodeFlags::INDIRECT as u32 == 0 {
|
let conversion_needed = inode.flags & InodeFlags::INDIRECT as u32 == 0;
|
||||||
// inode doesn't have indirect blocks, this entry is corrupt
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// figure out which indirect block we need to write to (either 1, 2, or 3)
|
// figure out which indirect block we need to write to (either 1, 2, or 3)
|
||||||
// range 12..(12*2) is indirect block 1
|
// range 12..(12*2) is indirect block 1
|
||||||
|
@ -1383,7 +1622,6 @@ pub fn journaled_write_data(sb: &Superblock, bd: &mut dyn BlockDevice, inode: In
|
||||||
return JournaledWriteResult::PotentialFilesystemCorruption;
|
return JournaledWriteResult::PotentialFilesystemCorruption;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JournaledWriteResult::Success
|
JournaledWriteResult::Success
|
||||||
|
|
110
src/structs.rs
110
src/structs.rs
|
@ -7,7 +7,7 @@ pub const MAGIC: u64 = 0x766170554653;
|
||||||
|
|
||||||
/// # Superblock
|
/// # Superblock
|
||||||
/// The primary struct of a VapUFS filesystem, contains metadata about the filesystem.
|
/// The primary struct of a VapUFS filesystem, contains metadata about the filesystem.
|
||||||
/// Located at byte offset 1024 of the block device.
|
/// Located at byte offset 2048 of the block device.
|
||||||
/// All values are big-endian unless otherwise specified.
|
/// All values are big-endian unless otherwise specified.
|
||||||
/// Directly after (i.e. the next block after) the Superblock are the free data blocks bitmap and the free inodes bitmap.
|
/// Directly after (i.e. the next block after) the Superblock are the free data blocks bitmap and the free inodes bitmap.
|
||||||
/// Free data blocks bitmap is data_block_count / 8 bytes long (rounded up).
|
/// Free data blocks bitmap is data_block_count / 8 bytes long (rounded up).
|
||||||
|
@ -17,7 +17,7 @@ pub const MAGIC: u64 = 0x766170554653;
|
||||||
pub struct Superblock {
|
pub struct Superblock {
|
||||||
/// magic number that identifies the Superblock as a valid VapUFS filesystem
|
/// magic number that identifies the Superblock as a valid VapUFS filesystem
|
||||||
pub magic: u64,
|
pub magic: u64,
|
||||||
/// size of each block in bytes, must be *at least* the size of the superblock without the bitmaps
|
/// size of each block in bytes, must be *at least* 2048 bytes
|
||||||
pub block_size: u32,
|
pub block_size: u32,
|
||||||
/// location of first data block in blocks
|
/// location of first data block in blocks
|
||||||
pub first_data_block: Index,
|
pub first_data_block: Index,
|
||||||
|
@ -197,36 +197,10 @@ pub struct Inode {
|
||||||
pub deletion_time: Timestamp,
|
pub deletion_time: Timestamp,
|
||||||
/// Flags field, see `InodeFlags`
|
/// Flags field, see `InodeFlags`
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
/// Direct-Block-Addresses, last three are indirect if `InodeFlags::INDIRECT` is set
|
/// listblock for storing data block addresses
|
||||||
/// Indirect blocks are Indexes to other blocks, their contents are a u64 count "N" followed by
|
pub listblock: ListBlock,
|
||||||
/// for each entry...
|
|
||||||
/// is_data: bool (true if data block, false if another indirect block)
|
|
||||||
/// depth: u56 (in total, how many indirect blocks are pointed to if this isn't data, and how many indirect blocks do they point to if they have indirect blocks)
|
|
||||||
/// ptr: u64 (if is_data, then this is a data block, otherwise it is an indirect block)
|
|
||||||
/// both direct and indirect are pointers to data blocks, starting from data block 0
|
|
||||||
/// ====
|
|
||||||
/// these pointers can be addressed via a u64 in the following way:
|
|
||||||
/// if i < 12, then it refers to a direct block in this array (undefined behaviour if indirect is set and i > 9)
|
|
||||||
/// if i == 12, then it refers to the first index found by going to the first indirect block, and recursing through each found indirect block until the first data block is found.
|
|
||||||
/// if i == 13, then it refers to the second index found by going to the first indirect block, and recursing through each found indirect block until the second data block is found.
|
|
||||||
/// ==
|
|
||||||
/// the algorithm for finding the nth data block is as follows:
|
|
||||||
/// if n < 12, then it is the nth direct block
|
|
||||||
/// if n >= 12...
|
|
||||||
/// let mut n = n - 12;
|
|
||||||
/// let mut block_i = n / (block_size - 8);
|
|
||||||
/// // block_i is how many indirect blocks we need to traverse to get to the indirect block that contains the nth data block
|
|
||||||
/// let mut current_block = self.direct_block_addresses[12];
|
|
||||||
/// while not found...
|
|
||||||
/// // read block, if not data then check depth,
|
|
||||||
/// // if depth implies that this indirect block could contain the nth data block, then recurse
|
|
||||||
/// // otherwise, subtract the depth from n, and continue
|
|
||||||
/// ====
|
|
||||||
/// ideally, this should not take up too much storage space, while allowing for a large number of blocks to be addressed with minimal performance impact
|
|
||||||
pub direct_block_addresses: [Index; 12],
|
|
||||||
/// CRC32 checksum of this inode
|
/// CRC32 checksum of this inode
|
||||||
pub checksum: u32,
|
pub checksum: u32,
|
||||||
// 172 bytes used so far
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inode {
|
impl Inode {
|
||||||
|
@ -246,9 +220,7 @@ impl Inode {
|
||||||
self.last_inode_modification_time = u64::from_be(self.last_inode_modification_time);
|
self.last_inode_modification_time = u64::from_be(self.last_inode_modification_time);
|
||||||
self.deletion_time = u64::from_be(self.deletion_time);
|
self.deletion_time = u64::from_be(self.deletion_time);
|
||||||
self.flags = u32::from_be(self.flags);
|
self.flags = u32::from_be(self.flags);
|
||||||
for i in 0..12 {
|
self.listblock.convert_big_endian_to_native();
|
||||||
self.direct_block_addresses[i] = u64::from_be(self.direct_block_addresses[i]);
|
|
||||||
}
|
|
||||||
self.checksum = u32::from_be(self.checksum);
|
self.checksum = u32::from_be(self.checksum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,9 +241,7 @@ impl Inode {
|
||||||
self.last_inode_modification_time = u64::to_be(self.last_inode_modification_time);
|
self.last_inode_modification_time = u64::to_be(self.last_inode_modification_time);
|
||||||
self.deletion_time = u64::to_be(self.deletion_time);
|
self.deletion_time = u64::to_be(self.deletion_time);
|
||||||
self.flags = u32::to_be(self.flags);
|
self.flags = u32::to_be(self.flags);
|
||||||
for i in 0..12 {
|
self.listblock.convert_native_to_big_endian();
|
||||||
self.direct_block_addresses[i] = u64::to_be(self.direct_block_addresses[i]);
|
|
||||||
}
|
|
||||||
self.checksum = u32::to_be(self.checksum);
|
self.checksum = u32::to_be(self.checksum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,8 +276,18 @@ impl Inode {
|
||||||
pub enum InodeFlags {
|
pub enum InodeFlags {
|
||||||
/// File is corrupted
|
/// File is corrupted
|
||||||
CORRUPT = 1 << 0,
|
CORRUPT = 1 << 0,
|
||||||
/// File uses indirect blocks
|
/// File uses Single Indirect Block
|
||||||
INDIRECT = 1 << 1,
|
INDIRECT1 = 1 << 1,
|
||||||
|
/// File uses Double Indirect Block
|
||||||
|
INDIRECT2 = 1 << 2,
|
||||||
|
/// File uses Triple Indirect Block
|
||||||
|
INDIRECT3 = 1 << 3,
|
||||||
|
/// File uses Quadruple Indirect Block
|
||||||
|
INDIRECT4 = 1 << 4,
|
||||||
|
/// File uses Quintuple Indirect Block
|
||||||
|
INDIRECT5 = 1 << 5,
|
||||||
|
/// File uses Sextuple Indirect Block
|
||||||
|
INDIRECT6 = 1 << 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # JournalEntry
|
/// # JournalEntry
|
||||||
|
@ -400,8 +380,15 @@ pub struct JournalBlockWrite {
|
||||||
/// target inode number
|
/// target inode number
|
||||||
pub target_inode: Index,
|
pub target_inode: Index,
|
||||||
/// target block number (if target is a data block, this will be the index in the inode's direct block array;
|
/// target block number (if target is a data block, this will be the index in the inode's direct block array;
|
||||||
/// if greater than 12, the indirect block this points to (i / 12) will be used, and the index in that block will be i % 12)
|
/// if greater than 32, see the following:
|
||||||
/// (if target is an inode, this field will be ignored)
|
/// let N = maximum number of pointers in an indirect block
|
||||||
|
/// (beginning...count)
|
||||||
|
/// 32..N: single indirect block
|
||||||
|
/// 32+N..N^2: double indirect block
|
||||||
|
/// 32+N^2..N^3: triple indirect block
|
||||||
|
/// 32+N^3..N^4: quadruple indirect block
|
||||||
|
/// 32+N^4..N^5: quintuple indirect block
|
||||||
|
/// 32+N^5..N^6: sextuple indirect block
|
||||||
pub target_block: Index,
|
pub target_block: Index,
|
||||||
/// actual data block number, unused if target is an inode
|
/// actual data block number, unused if target is an inode
|
||||||
pub real_target_block: Index,
|
pub real_target_block: Index,
|
||||||
|
@ -558,11 +545,28 @@ pub enum JMWFlags {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct ListBlock {
|
pub struct ListBlock {
|
||||||
pub using_indirect_blocks: bool,
|
/// Count of blocks used
|
||||||
/// Direct-Block-Addresses, last three are indirect if `using_indirect_blocks` is set
|
pub count: Index,
|
||||||
/// Indirect blocks are Indexes to other blocks, their contents are a u64 count "N" followed by N u64 indexes
|
/// Direct-Block-Addresses
|
||||||
/// both are pointers to data blocks, starting from data block 0
|
pub direct_block_addresses: [Index; 32],
|
||||||
pub direct_block_addresses: [Index; 12],
|
/// Single Indirect-Block-Address
|
||||||
|
/// Indirect blocks are Indexes to other blocks, their contents are N u64 data pointers
|
||||||
|
pub single_indirect_block_address: [Index; 32],
|
||||||
|
/// Double Indirect-Block-Address
|
||||||
|
/// Double indirect blocks are Indexes to other blocks, their contents are N u64 indirect block pointers (they point to single indirect blocks)
|
||||||
|
pub double_indirect_block_address: [Index; 32],
|
||||||
|
/// Triple Indirect-Block-Address
|
||||||
|
/// Triple indirect blocks are Indexes to other blocks, their contents are N u64 double indirect block pointers (they point to double indirect blocks)
|
||||||
|
pub triple_indirect_block_address: [Index; 32],
|
||||||
|
/// Quadruple Indirect-Block-Address
|
||||||
|
/// Quadruple indirect blocks are Indexes to other blocks, their contents are N u64 triple indirect block pointers (they point to triple indirect blocks)
|
||||||
|
pub quadruple_indirect_block_address: [Index; 32],
|
||||||
|
/// Quintuple Indirect-Block-Address
|
||||||
|
/// Quintuple indirect blocks are Indexes to other blocks, their contents are N u64 quadruple indirect block pointers (they point to quadruple indirect blocks)
|
||||||
|
pub quintuple_indirect_block_address: [Index; 32],
|
||||||
|
/// Sextuple Indirect-Block-Address
|
||||||
|
/// Sextuple indirect blocks are Indexes to other blocks, their contents are N u64 quintuple indirect block pointers (they point to quintuple indirect blocks)
|
||||||
|
pub sextuple_indirect_block_address: [Index; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListBlock {
|
impl ListBlock {
|
||||||
|
@ -570,8 +574,14 @@ impl ListBlock {
|
||||||
pub fn convert_big_endian_to_native(&mut self) {
|
pub fn convert_big_endian_to_native(&mut self) {
|
||||||
#[cfg(target_endian = "little")]
|
#[cfg(target_endian = "little")]
|
||||||
{
|
{
|
||||||
for i in 0..12 {
|
for i in 0..32 {
|
||||||
self.direct_block_addresses[i] = u64::from_be(self.direct_block_addresses[i]);
|
self.direct_block_addresses[i] = u64::from_be(self.direct_block_addresses[i]);
|
||||||
|
self.single_indirect_block_address[i] = u64::from_be(self.single_indirect_block_address[i]);
|
||||||
|
self.double_indirect_block_address[i] = u64::from_be(self.double_indirect_block_address[i]);
|
||||||
|
self.triple_indirect_block_address[i] = u64::from_be(self.triple_indirect_block_address[i]);
|
||||||
|
self.quadruple_indirect_block_address[i] = u64::from_be(self.quadruple_indirect_block_address[i]);
|
||||||
|
self.quintuple_indirect_block_address[i] = u64::from_be(self.quintuple_indirect_block_address[i]);
|
||||||
|
self.sextuple_indirect_block_address[i] = u64::from_be(self.sextuple_indirect_block_address[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -580,8 +590,14 @@ impl ListBlock {
|
||||||
pub fn convert_native_to_big_endian(&mut self) {
|
pub fn convert_native_to_big_endian(&mut self) {
|
||||||
#[cfg(target_endian = "little")]
|
#[cfg(target_endian = "little")]
|
||||||
{
|
{
|
||||||
for i in 0..12 {
|
for i in 0..32 {
|
||||||
self.direct_block_addresses[i] = u64::to_be(self.direct_block_addresses[i]);
|
self.direct_block_addresses[i] = u64::to_be(self.direct_block_addresses[i]);
|
||||||
|
self.single_indirect_block_address[i] = u64::to_be(self.single_indirect_block_address[i]);
|
||||||
|
self.double_indirect_block_address[i] = u64::to_be(self.double_indirect_block_address[i]);
|
||||||
|
self.triple_indirect_block_address[i] = u64::to_be(self.triple_indirect_block_address[i]);
|
||||||
|
self.quadruple_indirect_block_address[i] = u64::to_be(self.quadruple_indirect_block_address[i]);
|
||||||
|
self.quintuple_indirect_block_address[i] = u64::to_be(self.quintuple_indirect_block_address[i]);
|
||||||
|
self.sextuple_indirect_block_address[i] = u64::to_be(self.sextuple_indirect_block_address[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue