Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Falloc error checks and collapse #18

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SQUIRRELFS_CONFIG
Original file line number Diff line number Diff line change
Expand Up @@ -5197,4 +5197,4 @@ CONFIG_ARCH_USE_MEMTEST=y
CONFIG_RUST_OVERFLOW_CHECKS=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
# end of Rust hacking
# end of Kernel hacking
# end of Kernel hacking
1 change: 1 addition & 0 deletions fs/hayleyfs/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub(crate) const MAX_FILENAME_LEN: usize = 110;
pub(crate) const MAX_PAGES: u64 = u64::MAX;
pub(crate) const MAX_LINKS: u16 = u16::MAX;
pub(crate) const DENTRIES_PER_PAGE: usize = 32;
pub(crate) const MAX_FILE_SIZE: u64 = 1000000; // TODO: get a correct number for this.
hayley-leblanc marked this conversation as resolved.
Show resolved Hide resolved

/// Reserved pages
#[allow(dead_code)]
Expand Down
171 changes: 169 additions & 2 deletions fs/hayleyfs/h_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::defs::*;
use crate::h_inode::*;
use crate::typestate::*;
use crate::volatile::*;
use crate::namei::*;
use crate::{end_timing, fence_vec, init_timing, start_timing};
use core::{ffi, marker::Sync, ptr, sync::atomic::Ordering};
use kernel::prelude::*;
Expand All @@ -12,6 +13,7 @@ use kernel::{
iomap, mm,
};


pub(crate) struct Adapter {}

impl<T: Sync> file::OpenAdapter<T> for Adapter {
Expand All @@ -20,6 +22,21 @@ impl<T: Sync> file::OpenAdapter<T> for Adapter {
}
}

// FLags for fallocate modes

#[repr(i32)]
#[allow(non_camel_case_types)]
enum FALLOC_FLAG {
FALLOC_FL_KEEP_SIZE = 0x01,
FALLOC_FL_PUNCH_HOLE = 0x02,
// FALLOC_FL_NO_HIDE_STALE = 0x04,
FALLOC_FL_COLLAPSE_RANGE = 0x08,
FALLOC_FL_ZERO_RANGE = 0x10,
FALLOC_FL_INSERT_RANGE = 0x20,
// FALLOC_FL_UNSHARE_RANGE = 0x40,
}
Comment on lines +27 to +37
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to import these flags from rust/bindings/bindings_generated.rs. If they aren't there, we probably have to add the file in which they are defined by the kernel to rust/bindings/bindings_helper.h. The Rust build system incorporated with the kernel uses this .h file to set up Rust-friendly definitions of everything defined by files it includes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, looks like they are defined as C macros for some reason, which makes our lives a little more difficult. The automatic binding generation doesn't work on C macros, sohe cleanest way to handle this at the moment would be to manually add a wrapper for each macro in rust/helpers.c, following the same style as the existing functions in that file.



pub(crate) struct FileOps;
#[vtable]
impl file::Operations for FileOps {
Expand Down Expand Up @@ -85,7 +102,7 @@ impl file::Operations for FileOps {
Ok((bytes_written, _)) => Ok(bytes_written.try_into()?),
Err(e) => Err(e),
}
}
}

fn read(
_data: (),
Expand Down Expand Up @@ -134,7 +151,157 @@ impl file::Operations for FileOps {
_offset: i64,
_len: i64,
) -> Result<u64> {
Err(EINVAL)
let inode: &mut fs::INode = unsafe { &mut *_file.inode().cast() };

let sb = inode.i_sb();
let fs_info_raw = unsafe { (*sb).s_fs_info };
let sbi = unsafe { &mut *(fs_info_raw as *mut SbInfo) };
hayley-leblanc marked this conversation as resolved.
Show resolved Hide resolved


let pi = sbi.get_init_reg_inode_by_vfs_inode(inode.get_inner())?;
// let pi_info = pi.get_inode_info()?;
let initial_size: u64 = pi.get_size() as u64;

/*
* Error checks beforehand, sourced from below:
* https://man7.org/linux/man-pages/man2/fallocate.2.html#ERRORS
*/
let falloc_fl_insert_range = _mode & FALLOC_FLAG::FALLOC_FL_INSERT_RANGE as i32 == 1;
let falloc_fl_collapse_range = _mode & FALLOC_FLAG::FALLOC_FL_COLLAPSE_RANGE as i32 == 1;
let falloc_fl_keep_size = _mode & FALLOC_FLAG::FALLOC_FL_KEEP_SIZE as i32 == 1;
let falloc_fl_zero_range = _mode & FALLOC_FLAG::FALLOC_FL_ZERO_RANGE as i32 == 1;
let falloc_fl_punch_hole = _mode & FALLOC_FLAG::FALLOC_FL_PUNCH_HOLE as i32 == 1;

/*
* EINVAL: offset was less than 0, or len was less than or equal to
* 0.
*/
if _offset < 0 || _len <= 0 {
return Err(EINVAL);
}
hayley-leblanc marked this conversation as resolved.
Show resolved Hide resolved

pr_info!("Gets past offset and length check");

let len_u64: u64 = _len.try_into().unwrap();
let offset_u64: u64 = _offset.try_into().unwrap();
let final_file_size : u64 = len_u64 + offset_u64;

/*
* EFBIG: offset+len exceeds the maximum file size.
*/
if final_file_size > MAX_FILE_SIZE {
return Err(EFBIG);
}

pr_info!("Gets past file size check");

/*
* EFBIG: mode is FALLOC_FL_INSERT_RANGE, and the current file
* size+len exceeds the maximum file size.
*/
if falloc_fl_insert_range && (initial_size + len_u64 > MAX_FILE_SIZE) {
pr_info!("Fails the insert_range check.");
return Err(EFBIG);
}

/*
* EINTR: A signal was caught during execution; see signal(7).
*/
// TODO: implement me!

/*
* EINVAL: mode is FALLOC_FL_COLLAPSE_RANGE and the range specified
* by offset plus len reaches or passes the end of the file.
*
* EINVAL: mode is FALLOC_FL_COLLAPSE_RANGE or
* FALLOC_FL_INSERT_RANGE, but either offset or len is not a
* multiple of the filesystem block size.
*/
if falloc_fl_collapse_range &&
offset_u64 + len_u64 >= initial_size ||
(offset_u64 % HAYLEYFS_PAGESIZE != 0 || len_u64 % HAYLEYFS_PAGESIZE != 0) // Treat pages as blocks?
{
return Err(EINVAL);
}

/*
* EINVAL: mode is FALLOC_FL_INSERT_RANGE and the range specified by
* offset reaches or passes the end of the file.
*
* EINVAL: mode is FALLOC_FL_COLLAPSE_RANGE or
* FALLOC_FL_INSERT_RANGE, but either offset or len is not a
* multiple of the filesystem block size.
*/
if falloc_fl_insert_range &&
(offset_u64 >= initial_size) ||
(offset_u64 % HAYLEYFS_PAGESIZE != 0 || len_u64 % HAYLEYFS_PAGESIZE != 0)
{
return Err(EINVAL);
}

/*
* EINVAL: mode contains one of FALLOC_FL_COLLAPSE_RANGE or
* FALLOC_FL_INSERT_RANGE and also other flags; no other
* flags are permitted with FALLOC_FL_COLLAPSE_RANGE or
* FALLOC_FL_INSERT_RANGE.
*/
if (falloc_fl_insert_range && falloc_fl_collapse_range) ||
(
(falloc_fl_insert_range ^ falloc_fl_collapse_range) &&
falloc_fl_keep_size || falloc_fl_zero_range || falloc_fl_punch_hole
)
{
return Err(EINVAL);
}

/*
* Implementation below.
*/

if _mode == 0 {
if final_file_size > initial_size {
match hayleyfs_truncate(sbi, pi, final_file_size as i64){
Ok(_) => (),
Err(_e) => {
// do something here to return the right error code
return Err(EINVAL);
}
}
}
}

else if _mode & FALLOC_FLAG::FALLOC_FL_KEEP_SIZE as i32 == 1 {
// truncate extends the flie size when the size is greater than the current size
match hayleyfs_truncate(sbi, pi, final_file_size as i64){
Ok(_) => pr_info!("OK"),
Err(e) => pr_info!("{:?}", e)
}

// size will be restored at the end of this function.
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than calling hayleyfs_truncate and then setting the size back to the original value, you should implement a function that adds the pages to the file but does not change its size at all. With the current design (which appears to not reset the inode size anyway?), if we crash after the hayleyfs_truncate call completes but before fixing up the file size, the file size will end up incorrect.


else if _mode & FALLOC_FLAG::FALLOC_FL_COLLAPSE_RANGE as i32 == 1 { //Charan, Lindsey


}

else if _mode & FALLOC_FLAG::FALLOC_FL_ZERO_RANGE as i32 == 1 { //Lindsey

}

else if _mode & FALLOC_FLAG::FALLOC_FL_INSERT_RANGE as i32 == 1 { //Kaustubh

}
else if _mode & FALLOC_FLAG::FALLOC_FL_PUNCH_HOLE as i32 == 1 { //Devon

}

if _mode & FALLOC_FLAG::FALLOC_FL_KEEP_SIZE as i32 == 1 {
// reset file size to original <-- truncate will add zeroed out pages

}

Ok(0)
}

fn ioctl(data: (), file: &file::File, cmd: &mut file::IoctlCommand) -> Result<i32> {
Expand Down
2 changes: 1 addition & 1 deletion fs/hayleyfs/namei.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1926,7 +1926,7 @@ fn hayleyfs_symlink<'a>(
}

// TODO: return a type indicating that the truncate has completed
fn hayleyfs_truncate<'a>(
pub(crate) fn hayleyfs_truncate<'a>(
sbi: &SbInfo,
pi: InodeWrapper<'a, Clean, Start, RegInode>,
size: i64,
Expand Down
Loading