diff --git a/Cargo.toml b/Cargo.toml index 4a4c621..22975d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vapfs = { path = "../vapfs" } \ No newline at end of file +vapfs = { path = "../vapfs" } +ondisk_btree = { path = "../../ondisk_btree" } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1065a8b..fc1d702 100644 --- a/src/lib.rs +++ b/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. -pub fn get_indirect_datablock(sb: &Superblock, bd: &mut dyn BlockDevice, dbas: [Index; 12], address: Index) -> Index { - if address < 12 { - dbas[address as usize] +/// 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, list: ListBlock, address: Index) -> Option<(Index, Index)> { + if address < 32 { + None } else { - let n = address - 12; - let mut blocks_left = n / (sb.block_size as u64 - 8); - let mut indexes_left = n % (sb.block_size as u64 - 8); - let mut current_block = dbas[9]; // first indirect block - let mut visited = vec![]; - loop { - if visited.contains(¤t_block) { - return 0; + // copy pasted from structs.rs + // if greater than 32, see the following: + // let N = (maximum number of pointers in an indirect block) * 32 + // (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 + + // 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); - let mut head = 0; - let buf = read_datablock(current_block, sb, bd); - let count = u64::from_be_bytes(buf[0..8].try_into().unwrap()); - head += 8; - // if blocks_left == 0, we're in the right block (either that or we're in the right block to recurse downwards into) - if blocks_left == 0 { - for _ in 0..count.min(indexes_left) { - 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; - // 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 < N2 => { + let address = address - N; + let block_index = (address) / (max_per_block ^ 2); + let layer2_block = read_datablock(list.double_indirect_block_address[block_index as usize], sb, bd); + let layer2_address = address / max_per_block; + 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 < 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. /// 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. @@ -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. /// 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. 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 { 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 let mut list_block = ListBlock { - using_indirect_blocks: datablock_count > 12, - direct_block_addresses: [0; 12], + count: 0, + 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 { - using_indirect_blocks: false, - direct_block_addresses: [0; 12], + count: 0, + 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(); - // if using indirect blocks, only fill out the first (12 - 3) = 9 entries - // otherwise, fill out all 12 entries - if list_block.using_indirect_blocks { - list_block.direct_block_addresses[..9].copy_from_slice(&allocated_blocks[..9]); + // if using indirect blocks, only fill out the dba + // otherwise, have fun! + if datablock_count > 32 { + 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 - // layout is u64 count followed by u64 addresses - let max_addresses_per_block = (sb.block_size as usize - core::mem::size_of::()) / (core::mem::size_of::() * 2); - let mut indirect_block_count = (datablock_count - 9) / max_addresses_per_block as u64; - // if the count is not a multiple of the max addresses per block, add one - if (datablock_count - 9) % max_addresses_per_block as u64 != 0 { - indirect_block_count += 1; - } - // if the count is over 3, we'll need to use nested indirect blocks - // calculate how many layers of indirect blocks we'll need, - // filling max_addresses per block until we have less than max_addresses_per_block left - // this will be the amount of layers required to store the data - let depth = { - let mut depth = 0; - let mut remaining = indirect_block_count; - while remaining > max_addresses_per_block as u64 { - remaining -= max_addresses_per_block as u64; - depth += 1; + // set the indirect blocks + 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; + // figure out how many blocks we need for all indirect blocks + let mut indirect_blocks_needed = 0; + // can we fit them all in the 32 single indirect blocks? + let dba_count = datablock_count - 32; + // enclosed in brackets so that you can collapse it in the IDE (: + { + if dba_count < N { + // yes we can + // how many indirect blocks do we need? + 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 - let indirect_blocks = find_count_unallocated_datablocks(sb, bd, indirect_block_count as usize + (depth * max_addresses_per_block))?; - 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]); - } + let indirect_blocks = find_count_unallocated_datablocks(sb, bd, indirect_blocks_needed as usize)?; - // write the indirect blocks - let mut indirect_block_data = vec![0; core::mem::size_of::() * max_addresses_per_block]; - let mut indirect_blocks_from_previous_layer = VecDeque::new(); - let mut indirect_blocks_from_previous_layer_alt = VecDeque::new(); - let mut using_alt = false; - let mut acc: VecDeque = VecDeque::new(); // how much each previous layer has had - let mut acc_alt: VecDeque = 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 + // fill with data + let mut i = 0; + let mut taken = 0; + let data = &allocated_blocks[32..]; - // are we writing the indirect blocks that contain the data blocks? - let writing_data_blocks = i < indirect_block_count as usize; - if writing_data_blocks { - 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 - (datablock_count - 9) % max_addresses_per_block as u64 - } else { - max_addresses_per_block as u64 // otherwise, all of the addresses will be used - }; - // add count - unsafe { core::ptr::write(indirect_block_data.as_mut_ptr() as *mut u64, count); } - // add addresses - for j in 0..count { - 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]); } + // once again enclosed so that you can collapse it in the IDE (: + { + fn fillwithdata_1( + sb: &Superblock, bd: &mut dyn BlockDevice, i: &mut u64, data: &[Index], + block_size: usize, max_per_block: u64, indirect_blocks: &mut Vec, + taken: &mut usize, dbas: &mut [Index], max: usize) -> bool { + for block1 in 0..max { + if *i >= data.len() as u64 { + break; + } + let mut buf = vec![0u8; block_size]; + let mut j = 0; + 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 - if !unsafe { write_datablock(indirect_blocks[i], sb, bd, &indirect_block_data) } { + true + } + + // 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; } - - indirect_blocks_from_previous_layer.push_back(indirect_blocks[i]); - acc.push_back(count); - } 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; - } + let buf = list.iter().map(|x| x.to_be_bytes()).flatten().collect::>(); + if !unsafe { write_datablock(indirect_blocks[taken], sb, bd, &buf) } { + return None; } + 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, + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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 { @@ -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 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.direct_block_addresses = target_inode.direct_block_addresses; + old_list_block = target_inode.listblock; // write the list blocks let buf = [0; core::mem::size_of::()]; @@ -827,10 +1069,7 @@ pub fn flush_single_block_write(sb: &Superblock, bd: &mut dyn BlockDevice, entry return false; } } else { - if inode.flags & InodeFlags::INDIRECT as u32 == 0 { - // inode doesn't have indirect blocks, this entry is corrupt - return false; - } + let conversion_needed = inode.flags & InodeFlags::INDIRECT as u32 == 0; // figure out which indirect block we need to write to (either 1, 2, or 3) // 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; } } - } JournaledWriteResult::Success diff --git a/src/structs.rs b/src/structs.rs index da79ced..0b160c2 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -7,7 +7,7 @@ pub const MAGIC: u64 = 0x766170554653; /// # Superblock /// 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. /// 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). @@ -17,7 +17,7 @@ pub const MAGIC: u64 = 0x766170554653; pub struct Superblock { /// magic number that identifies the Superblock as a valid VapUFS filesystem 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, /// location of first data block in blocks pub first_data_block: Index, @@ -197,36 +197,10 @@ pub struct Inode { pub deletion_time: Timestamp, /// Flags field, see `InodeFlags` pub flags: u32, - /// Direct-Block-Addresses, last three are indirect if `InodeFlags::INDIRECT` is set - /// Indirect blocks are Indexes to other blocks, their contents are a u64 count "N" followed by - /// 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], + /// listblock for storing data block addresses + pub listblock: ListBlock, /// CRC32 checksum of this inode pub checksum: u32, - // 172 bytes used so far } impl Inode { @@ -246,9 +220,7 @@ impl Inode { self.last_inode_modification_time = u64::from_be(self.last_inode_modification_time); self.deletion_time = u64::from_be(self.deletion_time); self.flags = u32::from_be(self.flags); - for i in 0..12 { - self.direct_block_addresses[i] = u64::from_be(self.direct_block_addresses[i]); - } + self.listblock.convert_big_endian_to_native(); 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.deletion_time = u64::to_be(self.deletion_time); self.flags = u32::to_be(self.flags); - for i in 0..12 { - self.direct_block_addresses[i] = u64::to_be(self.direct_block_addresses[i]); - } + self.listblock.convert_native_to_big_endian(); self.checksum = u32::to_be(self.checksum); } } @@ -306,8 +276,18 @@ impl Inode { pub enum InodeFlags { /// File is corrupted CORRUPT = 1 << 0, - /// File uses indirect blocks - INDIRECT = 1 << 1, + /// File uses Single Indirect Block + 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 @@ -400,8 +380,15 @@ pub struct JournalBlockWrite { /// target inode number 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; - /// 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 target is an inode, this field will be ignored) + /// if greater than 32, see the following: + /// 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, /// actual data block number, unused if target is an inode pub real_target_block: Index, @@ -558,11 +545,28 @@ pub enum JMWFlags { #[repr(C)] #[derive(Copy, Clone)] pub struct ListBlock { - pub using_indirect_blocks: bool, - /// Direct-Block-Addresses, last three are indirect if `using_indirect_blocks` is set - /// Indirect blocks are Indexes to other blocks, their contents are a u64 count "N" followed by N u64 indexes - /// both are pointers to data blocks, starting from data block 0 - pub direct_block_addresses: [Index; 12], + /// Count of blocks used + pub count: Index, + /// Direct-Block-Addresses + pub direct_block_addresses: [Index; 32], + /// 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 { @@ -570,8 +574,14 @@ impl ListBlock { pub fn convert_big_endian_to_native(&mut self) { #[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.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) { #[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.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]); } } }