begin switching to limited data size per file

This commit is contained in:
husky 2023-09-10 00:02:26 -07:00
parent e7d5daa623
commit bdd7ba3f36
No known key found for this signature in database
GPG key ID: 6B3D8CB511646891
3 changed files with 502 additions and 247 deletions

View file

@ -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" }

View file

@ -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(&current_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

View file

@ -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]);
} }
} }
} }