Fix mmap file flush exceeding the file length
This commit is contained in:
parent
1e8c5a6d0a
commit
a99c63e21d
@ -279,7 +279,15 @@ impl VMArea {
|
|||||||
|
|
||||||
if need_flush {
|
if need_flush {
|
||||||
let file_offset = file_offset.unwrap() + (target_range.start() - self.range.start());
|
let file_offset = file_offset.unwrap() + (target_range.start() - self.range.start());
|
||||||
file.unwrap().write_at(file_offset, buf);
|
let file_len = file.unwrap().metadata().unwrap().size;
|
||||||
|
if file_offset < file_len {
|
||||||
|
let effective_mem_len = std::cmp::min(target_range.size(), file_len - file_offset);
|
||||||
|
let len = file
|
||||||
|
.unwrap()
|
||||||
|
.write_at(file_offset, &buf[..effective_mem_len])
|
||||||
|
.expect("flush file failure");
|
||||||
|
debug_assert!(len == effective_mem_len);
|
||||||
|
} // else file_offset >= file_len, no need to write file
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset zeros
|
// reset zeros
|
||||||
@ -541,16 +549,40 @@ impl VMArea {
|
|||||||
if !cond_fn(file) {
|
if !cond_fn(file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
self.flush_file(file, file_offset)
|
||||||
|
.expect("flush memory to file failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_file(&self, file: &Arc<dyn File>, file_offset: usize) -> Result<()> {
|
||||||
|
let file_len = file.metadata().unwrap().size;
|
||||||
|
if file_offset >= file_len {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if self.is_fully_committed() {
|
if self.is_fully_committed() {
|
||||||
file.write_at(file_offset, unsafe { self.as_slice() });
|
let effective_mem_len = std::cmp::min(self.range().size(), file_len - file_offset);
|
||||||
|
let len = file.write_at(file_offset, unsafe {
|
||||||
|
&self.as_slice()[..effective_mem_len]
|
||||||
|
})?;
|
||||||
|
debug_assert!(len == effective_mem_len);
|
||||||
} else {
|
} else {
|
||||||
let committed = true;
|
let committed = true;
|
||||||
let vm_range_start = self.range().start();
|
let vm_range_start = self.range().start();
|
||||||
for range in self.pages().get_ranges(committed) {
|
for range in self.pages().get_ranges(committed) {
|
||||||
let file_offset = file_offset + (range.start() - vm_range_start);
|
let file_offset = file_offset + (range.start() - vm_range_start);
|
||||||
file.write_at(file_offset, unsafe { range.as_slice() });
|
if file_offset >= file_len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let effective_mem_len = std::cmp::min(range.size(), file_len - file_offset);
|
||||||
|
let len = file.write_at(file_offset, unsafe {
|
||||||
|
&range.as_slice()[..effective_mem_len]
|
||||||
|
})?;
|
||||||
|
debug_assert!(len == effective_mem_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_shared(&self) -> bool {
|
pub fn is_shared(&self) -> bool {
|
||||||
|
@ -1536,6 +1536,78 @@ int test_kernel_space_pf_trigger() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_shared_file_mmap_small_file() {
|
||||||
|
int fd;
|
||||||
|
struct stat sb1, sb2;
|
||||||
|
char *mapped;
|
||||||
|
char write_buf[] = "hello world\n";
|
||||||
|
size_t page_sz;
|
||||||
|
size_t file_sz;
|
||||||
|
size_t new_file_sz;
|
||||||
|
|
||||||
|
if ((fd = open("/root/a.txt", O_RDWR | O_CREAT, S_IRWXU)) < 0) {
|
||||||
|
perror("open");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write(fd, write_buf, strlen(write_buf)) < 0) {
|
||||||
|
perror("write");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((fstat(fd, &sb1)) == -1 ) {
|
||||||
|
perror("fstat");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_sz = sb1.st_size;
|
||||||
|
page_sz = getpagesize();
|
||||||
|
|
||||||
|
// Output the size before mmap
|
||||||
|
printf("before msync file_sz = %ld\n", file_sz);
|
||||||
|
if ((mapped = mmap(NULL, page_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
|
||||||
|
0)) == (void *) -1) {
|
||||||
|
perror("mmap");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appending characters at the end of a file.
|
||||||
|
mapped[file_sz] = '9';
|
||||||
|
// Synchronizing the modified contents of a file
|
||||||
|
if ((msync((void *)mapped, page_sz, MS_SYNC)) == -1) {
|
||||||
|
perror("msync");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fd, &sb2) == -1) {
|
||||||
|
perror("fstat");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_file_sz = sb2.st_size;
|
||||||
|
// Output the size after mmap
|
||||||
|
printf("msync after file_sz = %ld\n", new_file_sz);
|
||||||
|
if (new_file_sz != file_sz) {
|
||||||
|
THROW_ERROR("The file size doesn't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((munmap((void *)mapped, page_sz)) == -1) {
|
||||||
|
perror("munmap");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fstat(fd, &sb1)) == -1 ) {
|
||||||
|
perror("fstat");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_sz = sb1.st_size;
|
||||||
|
if (new_file_sz != file_sz) {
|
||||||
|
THROW_ERROR("The file size doesn't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite main
|
// Test suite main
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -1555,6 +1627,7 @@ static test_case_t test_cases[] = {
|
|||||||
TEST_CASE(test_shared_file_mmap_flushing_with_munmap),
|
TEST_CASE(test_shared_file_mmap_flushing_with_munmap),
|
||||||
TEST_CASE(test_shared_file_mmap_flushing_with_fdatasync),
|
TEST_CASE(test_shared_file_mmap_flushing_with_fdatasync),
|
||||||
TEST_CASE(test_shared_file_mmap_flushing_with_fsync),
|
TEST_CASE(test_shared_file_mmap_flushing_with_fsync),
|
||||||
|
TEST_CASE(test_shared_file_mmap_small_file),
|
||||||
TEST_CASE(test_fixed_mmap_that_does_not_override_any_mmaping),
|
TEST_CASE(test_fixed_mmap_that_does_not_override_any_mmaping),
|
||||||
TEST_CASE(test_fixed_mmap_that_overrides_existing_mmaping),
|
TEST_CASE(test_fixed_mmap_that_overrides_existing_mmaping),
|
||||||
TEST_CASE(test_fixed_mmap_with_non_page_aligned_addr),
|
TEST_CASE(test_fixed_mmap_with_non_page_aligned_addr),
|
||||||
|
Loading…
Reference in New Issue
Block a user