Add support for the mode of fallocate
This commit is contained in:
		
							parent
							
								
									99688183f0
								
							
						
					
					
						commit
						29eed82a7e
					
				
							
								
								
									
										2
									
								
								deps/sefs
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								deps/sefs
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit 8d999ffdf066cc0601c5a726ccfcca75437ced0b | ||||
| Subproject commit 0a17ee1ec824181c1cf2db97a05f612e96879645 | ||||
							
								
								
									
										1
									
								
								src/libos/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								src/libos/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -417,6 +417,7 @@ dependencies = [ | ||||
| name = "rcore-fs" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "bitflags", | ||||
|  "spin", | ||||
| ] | ||||
| 
 | ||||
|  | ||||
| @ -97,6 +97,7 @@ impl ToErrno for rcore_fs::vfs::FsError { | ||||
|             FsError::PermError => EPERM, | ||||
|             FsError::NameTooLong => ENAMETOOLONG, | ||||
|             FsError::FileTooBig => EFBIG, | ||||
|             FsError::OpNotSupported => EOPNOTSUPP, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -91,7 +91,7 @@ pub trait File: Debug + Sync + Send + Any { | ||||
|         return_op_unsupported_error!("set_advisory_lock") | ||||
|     } | ||||
| 
 | ||||
|     fn fallocate(&self, _mode: u32, _offset: u64, _len: u64) -> Result<()> { | ||||
|     fn fallocate(&self, _flags: FallocateFlags, _offset: usize, _len: usize) -> Result<()> { | ||||
|         return_op_unsupported_error!("fallocate") | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -1,11 +1,89 @@ | ||||
| use super::*; | ||||
| use rcore_fs::vfs::{AllocFlags, FallocateMode}; | ||||
| 
 | ||||
| pub fn do_fallocate(fd: FileDesc, mode: u32, offset: u64, len: u64) -> Result<()> { | ||||
| pub fn do_fallocate(fd: FileDesc, flags: FallocateFlags, offset: usize, len: usize) -> Result<()> { | ||||
|     debug!( | ||||
|         "fallocate: fd: {}, mode: {}, offset: {}, len: {}", | ||||
|         fd, mode, offset, len | ||||
|         "fallocate: fd: {}, flags: {:?}, offset: {}, len: {}", | ||||
|         fd, flags, offset, len | ||||
|     ); | ||||
|     let file_ref = current!().file(fd)?; | ||||
|     file_ref.fallocate(mode, offset, len)?; | ||||
|     file_ref.fallocate(flags, offset, len)?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     /// Operation mode flags for fallocate
 | ||||
|     /// Please checkout linux/include/uapi/linux/falloc.h for the details
 | ||||
|     pub struct FallocateFlags: u32 { | ||||
|         /// File size will not be changed when extend the file
 | ||||
|         const FALLOC_FL_KEEP_SIZE = 0x01; | ||||
|         /// De-allocates range
 | ||||
|         const FALLOC_FL_PUNCH_HOLE = 0x02; | ||||
|         /// Remove a range of a file without leaving a hole in the file
 | ||||
|         const FALLOC_FL_COLLAPSE_RANGE = 0x08; | ||||
|         /// Convert a range of file to zeros
 | ||||
|         const FALLOC_FL_ZERO_RANGE = 0x10; | ||||
|         /// Insert space within the file size without overwriting any existing data
 | ||||
|         const FALLOC_FL_INSERT_RANGE = 0x20; | ||||
|         /// Unshare shared blocks within the file size without overwriting any existing data
 | ||||
|         const FALLOC_FL_UNSHARE_RANGE = 0x40; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FallocateFlags { | ||||
|     pub fn from_u32(raw_flags: u32) -> Result<Self> { | ||||
|         let flags = | ||||
|             Self::from_bits(raw_flags).ok_or_else(|| errno!(EOPNOTSUPP, "invalid flags"))?; | ||||
|         if flags.contains(Self::FALLOC_FL_PUNCH_HOLE) && flags.contains(Self::FALLOC_FL_ZERO_RANGE) | ||||
|         { | ||||
|             return_errno!( | ||||
|                 EOPNOTSUPP, | ||||
|                 "Punch hole and zero range are mutually exclusive" | ||||
|             ); | ||||
|         } | ||||
|         if flags.contains(Self::FALLOC_FL_PUNCH_HOLE) && !flags.contains(Self::FALLOC_FL_KEEP_SIZE) | ||||
|         { | ||||
|             return_errno!(EOPNOTSUPP, "Punch hole must have keep size set"); | ||||
|         } | ||||
|         if flags.contains(Self::FALLOC_FL_COLLAPSE_RANGE) | ||||
|             && !(flags & !Self::FALLOC_FL_COLLAPSE_RANGE).is_empty() | ||||
|         { | ||||
|             return_errno!(EINVAL, "Collapse range should only be used exclusively"); | ||||
|         } | ||||
|         if flags.contains(Self::FALLOC_FL_INSERT_RANGE) | ||||
|             && !(flags & !Self::FALLOC_FL_INSERT_RANGE).is_empty() | ||||
|         { | ||||
|             return_errno!(EINVAL, "Insert range should only be used exclusively"); | ||||
|         } | ||||
|         if flags.contains(Self::FALLOC_FL_UNSHARE_RANGE) | ||||
|             && !(flags & !(Self::FALLOC_FL_UNSHARE_RANGE | Self::FALLOC_FL_KEEP_SIZE)).is_empty() | ||||
|         { | ||||
|             return_errno!( | ||||
|                 EINVAL, | ||||
|                 "Unshare range should only be used with allocate mode" | ||||
|             ); | ||||
|         } | ||||
|         Ok(flags) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<FallocateFlags> for FallocateMode { | ||||
|     fn from(flags: FallocateFlags) -> FallocateMode { | ||||
|         if flags.contains(FallocateFlags::FALLOC_FL_PUNCH_HOLE) { | ||||
|             FallocateMode::PunchHoleKeepSize | ||||
|         } else if flags.contains(FallocateFlags::FALLOC_FL_ZERO_RANGE) { | ||||
|             if flags.contains(FallocateFlags::FALLOC_FL_KEEP_SIZE) { | ||||
|                 FallocateMode::ZeroRangeKeepSize | ||||
|             } else { | ||||
|                 FallocateMode::ZeroRange | ||||
|             } | ||||
|         } else if flags.contains(FallocateFlags::FALLOC_FL_COLLAPSE_RANGE) { | ||||
|             FallocateMode::CollapseRange | ||||
|         } else if flags.contains(FallocateFlags::FALLOC_FL_INSERT_RANGE) { | ||||
|             FallocateMode::InsertRange | ||||
|         } else { | ||||
|             let flags = AllocFlags::from_bits_truncate(flags.bits()); | ||||
|             FallocateMode::Allocate(flags) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,7 @@ pub use self::chmod::{do_fchmod, do_fchmodat, FileMode}; | ||||
| pub use self::chown::{do_fchown, do_fchownat, ChownFlags}; | ||||
| pub use self::close::do_close; | ||||
| pub use self::dup::{do_dup, do_dup2, do_dup3}; | ||||
| pub use self::fallocate::do_fallocate; | ||||
| pub use self::fallocate::{do_fallocate, FallocateFlags}; | ||||
| pub use self::fcntl::{do_fcntl, FcntlCmd}; | ||||
| pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags}; | ||||
| pub use self::flock::{Flock, FlockType}; | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| use super::*; | ||||
| use crate::net::PollEventFlags; | ||||
| use rcore_fs::vfs::FallocateMode; | ||||
| use rcore_fs_sefs::dev::SefsMac; | ||||
| 
 | ||||
| pub struct INodeFile { | ||||
| @ -121,8 +122,12 @@ impl File for INodeFile { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn fallocate(&self, mode: u32, offset: u64, len: u64) -> Result<()> { | ||||
|         self.inode.fallocate(mode, offset, len)?; | ||||
|     fn fallocate(&self, flags: FallocateFlags, offset: usize, len: usize) -> Result<()> { | ||||
|         if !self.access_mode.writable() { | ||||
|             return_errno!(EBADF, "File is not opened for writing"); | ||||
|         } | ||||
|         let mode = FallocateMode::from(flags); | ||||
|         self.inode.fallocate(&mode, offset, len)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -19,8 +19,9 @@ pub use self::event_file::{AsEvent, EventCreationFlags, EventFile}; | ||||
| pub use self::events::{AtomicIoEvents, IoEvents, IoNotifier}; | ||||
| pub use self::file::{File, FileRef}; | ||||
| pub use self::file_ops::{ | ||||
|     occlum_ocall_ioctl, AccessMode, BuiltinIoctlNum, CreationFlags, FileMode, Flock, FlockType, | ||||
|     IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum, | ||||
|     occlum_ocall_ioctl, AccessMode, BuiltinIoctlNum, CreationFlags, FallocateFlags, FileMode, | ||||
|     Flock, FlockType, IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, | ||||
|     StructuredIoctlNum, | ||||
| }; | ||||
| pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier}; | ||||
| pub use self::fs_ops::Statfs; | ||||
|  | ||||
| @ -628,12 +628,8 @@ pub fn do_fallocate(fd: FileDesc, mode: u32, offset: off_t, len: off_t) -> Resul | ||||
|             "offset was less than 0, or len was less than or equal to 0" | ||||
|         ); | ||||
|     } | ||||
|     // Current implementation is just the posix_fallocate
 | ||||
|     // TODO: Support more modes in fallocate
 | ||||
|     if mode != 0 { | ||||
|         return_errno!(ENOSYS, "unsupported mode"); | ||||
|     } | ||||
|     file_ops::do_fallocate(fd, mode, offset as u64, len as u64)?; | ||||
|     let flags = FallocateFlags::from_u32(mode)?; | ||||
|     file_ops::do_fallocate(fd, flags, offset as usize, len as usize)?; | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										299
									
								
								test/file/main.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										299
									
								
								test/file/main.c
									
									
									
									
									
								
							| @ -1,3 +1,4 @@ | ||||
| #define _GNU_SOURCE | ||||
| #include <sys/stat.h> | ||||
| #include <sys/uio.h> | ||||
| #include <errno.h> | ||||
| @ -9,6 +10,9 @@ | ||||
| // Helper function
 | ||||
| // ============================================================================
 | ||||
| 
 | ||||
| #define KB (1024) | ||||
| #define BLK_SIZE (4 * KB) | ||||
| 
 | ||||
| static int create_file(const char *file_path) { | ||||
|     int fd; | ||||
|     int flags = O_RDONLY | O_CREAT | O_TRUNC; | ||||
| @ -164,12 +168,21 @@ static int __test_lseek(const char *file_path) { | ||||
| } | ||||
| 
 | ||||
| static int __test_posix_fallocate(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     int fd = open(file_path, O_RDONLY); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read"); | ||||
|     } | ||||
|     if (posix_fallocate(fd, 0, 16) != EBADF) { | ||||
|         THROW_ERROR("failed to check the open flags for fallocate"); | ||||
|     } | ||||
|     close(fd); | ||||
|     fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t offset = -1; | ||||
|     off_t len = 100; | ||||
|     off_t len = 128; | ||||
|     if (posix_fallocate(fd, offset, len) != EINVAL) { | ||||
|         THROW_ERROR("failed to call posix_fallocate with invalid offset"); | ||||
|     } | ||||
| @ -182,6 +195,7 @@ static int __test_posix_fallocate(const char *file_path) { | ||||
|     if (posix_fallocate(fd, offset, len) != 0) { | ||||
|         THROW_ERROR("failed to call posix_fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
| @ -203,6 +217,257 @@ static int __test_posix_fallocate(const char *file_path) { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #ifndef __GLIBC__ | ||||
| #define FALLOC_FL_COLLAPSE_RANGE (0x08) | ||||
| #define FALLOC_FL_ZERO_RANGE (0x10) | ||||
| #define FALLOC_FL_INSERT_RANGE (0x20) | ||||
| #define FALLOC_FL_UNSHARE_RANGE (0x40) | ||||
| #endif | ||||
| 
 | ||||
| static int __test_fallocate_with_invalid_mode(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t len = 2 * BLK_SIZE; | ||||
|     if (fill_file_with_repeated_bytes(fd, len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to fill file"); | ||||
|     } | ||||
| 
 | ||||
|     // Check the mode with expected errno
 | ||||
|     int mode_with_expected_errno[6][2] = { | ||||
|         {FALLOC_FL_KEEP_SIZE | 0xDEAD, EOPNOTSUPP}, | ||||
|         {FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE, EOPNOTSUPP}, | ||||
|         {FALLOC_FL_PUNCH_HOLE, EOPNOTSUPP}, | ||||
|         {FALLOC_FL_INSERT_RANGE | FALLOC_FL_KEEP_SIZE, EINVAL}, | ||||
|         {FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_KEEP_SIZE, EINVAL}, | ||||
|         {FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_UNSHARE_RANGE, EINVAL}, | ||||
|     }; | ||||
|     int row_cnt = (sizeof(mode_with_expected_errno) / sizeof(int)) / | ||||
|                   (sizeof(mode_with_expected_errno[0]) / sizeof(int)); | ||||
|     for (int i = 0; i < row_cnt; i++) { | ||||
|         int mode = mode_with_expected_errno[i][0]; | ||||
|         int expected_errno = mode_with_expected_errno[i][1]; | ||||
|         off_t offset = 0; | ||||
|         off_t half_len = len / 2; | ||||
|         errno = 0; | ||||
| 
 | ||||
|         int ret = fallocate(fd, mode, offset, half_len); | ||||
|         if (!(ret < 0 && errno == expected_errno)) { | ||||
|             THROW_ERROR("failed to check fallocate with invalid mode"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_fallocate_keep_size(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     int mode = FALLOC_FL_KEEP_SIZE; | ||||
|     off_t offset = 0; | ||||
|     off_t len = 64; | ||||
|     if (fallocate(fd, mode, offset, len) < 0) { | ||||
|         THROW_ERROR("failed to call fallocate with FALLOC_FL_KEEP_SIZE"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     if (stat_buf.st_size != 0) { | ||||
|         THROW_ERROR("failed to check the len after fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_fallocate_punch_hole(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t len = 64; | ||||
|     if (fill_file_with_repeated_bytes(fd, len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to fill file"); | ||||
|     } | ||||
| 
 | ||||
|     int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; | ||||
|     off_t offset = 0; | ||||
|     off_t hole_len = len / 2; | ||||
|     if (fallocate(fd, mode, offset, hole_len) < 0) { | ||||
|         THROW_ERROR("failed to call fallocate with FALLOC_FL_PUNCH_HOLE"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     if (stat_buf.st_size != len) { | ||||
|         THROW_ERROR("failed to check the len after fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     if (lseek(fd, offset, SEEK_SET) != offset) { | ||||
|         THROW_ERROR("failed to lseek the file"); | ||||
|     } | ||||
|     if (check_file_with_repeated_bytes(fd, hole_len, 0x00) < 0) { | ||||
|         THROW_ERROR("failed to check file after punch hole"); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_fallocate_zero_range(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t len = 64; | ||||
|     if (fill_file_with_repeated_bytes(fd, len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to fill file"); | ||||
|     } | ||||
| 
 | ||||
|     int mode = FALLOC_FL_ZERO_RANGE; | ||||
|     off_t offset = len / 2; | ||||
|     off_t zero_len = len * 2; | ||||
|     if (fallocate(fd, mode, offset, zero_len) < 0) { | ||||
|         THROW_ERROR("failed to call fallocate with FALLOC_FL_ZERO_RANGE"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     if (stat_buf.st_size != offset + zero_len) { | ||||
|         THROW_ERROR("failed to check the len after fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     if (lseek(fd, offset, SEEK_SET) != offset) { | ||||
|         THROW_ERROR("failed to lseek the file"); | ||||
|     } | ||||
|     if (check_file_with_repeated_bytes(fd, zero_len, 0x00) < 0) { | ||||
|         THROW_ERROR("failed to check file after zero range"); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_fallocate_insert_range(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t len = 4 * BLK_SIZE; | ||||
|     if (fill_file_with_repeated_bytes(fd, len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to fill file"); | ||||
|     } | ||||
| 
 | ||||
|     int mode = FALLOC_FL_INSERT_RANGE; | ||||
|     off_t offset = len; | ||||
|     off_t insert_len = len / 4; | ||||
|     int ret = fallocate(fd, mode, offset, insert_len); | ||||
|     if (ret >= 0 || errno != EINVAL ) { | ||||
|         THROW_ERROR("failed to check insert range with oversized offset"); | ||||
|     } | ||||
| 
 | ||||
|     // make the offset is not the multiple of the filesystem block size
 | ||||
|     offset += 1; | ||||
|     ret = fallocate(fd, mode, offset, insert_len); | ||||
|     if (ret >= 0 || errno != EINVAL ) { | ||||
|         THROW_ERROR("failed to check insert range with invalid offset"); | ||||
|     } | ||||
| 
 | ||||
|     offset = len / 4; | ||||
|     if (fallocate(fd, mode, offset, insert_len) < 0) { | ||||
|         THROW_ERROR("failed to call fallocate with FALLOC_FL_INSERT_RANGE"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     if (stat_buf.st_size != len + insert_len) { | ||||
|         THROW_ERROR("failed to check the len after fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     if (lseek(fd, offset, SEEK_SET) != offset) { | ||||
|         THROW_ERROR("failed to lseek the file"); | ||||
|     } | ||||
|     if (check_file_with_repeated_bytes(fd, insert_len, 0x00) < 0) { | ||||
|         THROW_ERROR("failed to check inserted contents after insert range"); | ||||
|     } | ||||
|     if (lseek(fd, offset + insert_len, SEEK_SET) != offset + insert_len) { | ||||
|         THROW_ERROR("failed to lseek the file"); | ||||
|     } | ||||
|     if (check_file_with_repeated_bytes(fd, len - offset, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to check shifted contents after insert range"); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int __test_fallocate_collapse_range(const char *file_path) { | ||||
|     int fd = open(file_path, O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         THROW_ERROR("failed to open a file to read/write"); | ||||
|     } | ||||
| 
 | ||||
|     off_t len = 4 * BLK_SIZE; | ||||
|     if (fill_file_with_repeated_bytes(fd, len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to fill file"); | ||||
|     } | ||||
| 
 | ||||
|     int mode = FALLOC_FL_COLLAPSE_RANGE; | ||||
|     off_t offset = len / 4; | ||||
|     off_t collapse_len = len; | ||||
|     int ret = fallocate(fd, mode, offset, collapse_len); | ||||
|     if (ret >= 0 || errno != EINVAL ) { | ||||
|         THROW_ERROR("failed to check collapse range with oversized end_offset"); | ||||
|     } | ||||
| 
 | ||||
|     // make the collapse_len is not the multiple of the filesystem block size
 | ||||
|     collapse_len = len / 4 + 1; | ||||
|     ret = fallocate(fd, mode, offset, collapse_len); | ||||
|     if (ret >= 0 || errno != EINVAL ) { | ||||
|         THROW_ERROR("failed to check collapse range with invalid collapse_len"); | ||||
|     } | ||||
| 
 | ||||
|     collapse_len = len / 4; | ||||
|     if (fallocate(fd, mode, offset, collapse_len) < 0) { | ||||
|         THROW_ERROR("failed to call fallocate with FALLOC_FL_COLLAPSE_RANGE"); | ||||
|     } | ||||
| 
 | ||||
|     struct stat stat_buf; | ||||
|     if (fstat(fd, &stat_buf) < 0) { | ||||
|         THROW_ERROR("failed to stat file"); | ||||
|     } | ||||
|     if (stat_buf.st_size != len - collapse_len) { | ||||
|         THROW_ERROR("failed to check the len after fallocate"); | ||||
|     } | ||||
| 
 | ||||
|     if (lseek(fd, offset, SEEK_SET) != offset) { | ||||
|         THROW_ERROR("failed to lseek the file"); | ||||
|     } | ||||
|     if (check_file_with_repeated_bytes(fd, len - offset - collapse_len, 0xFF) < 0) { | ||||
|         THROW_ERROR("failed to check the moved contents after collapse range"); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| typedef int(*test_file_func_t)(const char *); | ||||
| 
 | ||||
| static int test_file_framework(test_file_func_t fn) { | ||||
| @ -240,6 +505,30 @@ static int test_posix_fallocate() { | ||||
|     return test_file_framework(__test_posix_fallocate); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_with_invalid_mode() { | ||||
|     return test_file_framework(__test_fallocate_with_invalid_mode); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_keep_size() { | ||||
|     return test_file_framework(__test_fallocate_keep_size); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_punch_hole() { | ||||
|     return test_file_framework(__test_fallocate_punch_hole); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_zero_range() { | ||||
|     return test_file_framework(__test_fallocate_zero_range); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_insert_range() { | ||||
|     return test_file_framework(__test_fallocate_insert_range); | ||||
| } | ||||
| 
 | ||||
| static int test_fallocate_collapse_range() { | ||||
|     return test_file_framework(__test_fallocate_collapse_range); | ||||
| } | ||||
| 
 | ||||
| // ============================================================================
 | ||||
| // Test suite main
 | ||||
| // ============================================================================
 | ||||
| @ -250,6 +539,12 @@ static test_case_t test_cases[] = { | ||||
|     TEST_CASE(test_writev_readv), | ||||
|     TEST_CASE(test_lseek), | ||||
|     TEST_CASE(test_posix_fallocate), | ||||
|     TEST_CASE(test_fallocate_with_invalid_mode), | ||||
|     TEST_CASE(test_fallocate_keep_size), | ||||
|     TEST_CASE(test_fallocate_punch_hole), | ||||
|     TEST_CASE(test_fallocate_zero_range), | ||||
|     TEST_CASE(test_fallocate_insert_range), | ||||
|     TEST_CASE(test_fallocate_collapse_range), | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, const char *argv[]) { | ||||
|  | ||||
| @ -76,22 +76,20 @@ int fill_file_with_repeated_bytes(int fd, size_t len, int byte_val) { | ||||
| } | ||||
| 
 | ||||
| int check_file_with_repeated_bytes(int fd, size_t len, int expected_byte_val) { | ||||
|     size_t remain = len; | ||||
|     int remain = len; | ||||
|     char read_buf[512]; | ||||
|     while (remain > 0) { | ||||
|         int read_nbytes = read(fd, read_buf, sizeof(read_buf)); | ||||
|         if (read_nbytes < 0) { | ||||
|             // I/O error
 | ||||
|             return -1; | ||||
|             THROW_ERROR("I/O error"); | ||||
|         } | ||||
|         size_t check_nbytes = remain < read_nbytes ? remain : read_nbytes; | ||||
|         remain -= read_nbytes; | ||||
|         if (read_nbytes == 0 && remain > 0) { | ||||
|             // Not enough data in the file
 | ||||
|             return -1; | ||||
|             THROW_ERROR("Not enough data in the file"); | ||||
|         } | ||||
|         if (check_bytes_in_buf(read_buf, read_nbytes, expected_byte_val) < 0) { | ||||
|             // Incorrect data
 | ||||
|             return -1; | ||||
|         if (check_bytes_in_buf(read_buf, check_nbytes, expected_byte_val) < 0) { | ||||
|             THROW_ERROR("Incorrect data"); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user