-
Notifications
You must be signed in to change notification settings - Fork 138
ramdisk: add 4K sector size support with performance optimizations #1892
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
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: eric135 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems reasonable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds configurable sector size support to the ramdisk implementation, enabling testing with 4K sectors while maintaining full backward compatibility with existing 512-byte sector usage.
- Replaces hardcoded 512-byte sectors with configurable sector sizes via new constructor methods
- Adds new APIs
new_with_sector_size()
andram_disk_with_sector_size()
for custom sector sizes - Comprehensive test coverage for 4K sectors, mixed sizes, error cases, and backward compatibility
Comments suppressed due to low confidence (1)
vm/devices/storage/disklayer_ram/src/lib.rs:199
- The original code used
reader.read_plain()?
which expects a fixed-size array, but this line was removed and replaced with the vector-based approach. However, the diff shows this line is still present, creating a compilation error sinceread_plain()
cannot read into aVec<u8>
.
Entry::Occupied(mut entry) => {
entry.insert(Sector(reader.read_plain()?)); | ||
let mut sector_data = vec![0u8; self.sector_size as usize]; | ||
reader.read(&mut sector_data)?; | ||
entry.insert(Sector(sector_data)); | ||
} | ||
Entry::Occupied(mut entry) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The occupied entry branch also needs to be updated to handle the new Vec<u8>
based Sector
structure, but the diff doesn't show the complete implementation of this branch where similar changes would be needed.
Copilot uses AI. Check for mistakes.
@@ -159,19 +180,21 @@ impl RamDiskLayer { | |||
sector: u64, | |||
overwrite: bool, | |||
) -> Result<(), DiskError> { | |||
let count = buffers.len() / SECTOR_SIZE as usize; | |||
let count = buffers.len() / self.sector_size as usize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a computed sector_shift
field and use that instead of divisions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added sector_shift field and replaced divisions with bit shifts for better performance. Commit 38adbae.
tracing::trace!(sector, count, "write"); | ||
let mut state = self.state.write(); | ||
if sector + count as u64 > state.sector_count { | ||
return Err(DiskError::IllegalBlock); | ||
} | ||
for i in 0..count { | ||
let cur = i + sector as usize; | ||
let buf = buffers.subrange(i * SECTOR_SIZE as usize, SECTOR_SIZE as usize); | ||
let buf = buffers.subrange(i * self.sector_size as usize, self.sector_size as usize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use sector_shift to replace multiplications too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced multiplications with left shifts using sector_shift throughout the codebase. Commit 38adbae.
let mut reader = buf.reader(); | ||
match state.data.entry(cur as u64) { | ||
Entry::Vacant(entry) => { | ||
entry.insert(Sector(reader.read_plain()?)); | ||
let mut sector_data = vec![0u8; self.sector_size as usize]; | ||
reader.read(&mut sector_data)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use reader.read_n
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to use reader.read_n() which properly reads the specified number of bytes. Commit 38adbae.
/// | ||
/// # Arguments | ||
/// * `size` - Total size of the disk in bytes | ||
/// * `sector_size` - Size of each sector in bytes (typically 512 or 4096) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sector size needs to be a power of two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added power-of-two validation for sector sizes with a new error type and comprehensive test coverage. Commit 38adbae.
@copilot, address feedback |
…back Co-authored-by: jstarks <[email protected]>
All feedback has been addressed in commit 38adbae:
|
}); | ||
} | ||
size / SECTOR_SIZE as u64 | ||
size / sector_size as u64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kind of unhinged to use a division here just before computing the shift
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed by computing sector_shift first and then using right shift instead of division for sector_count calculation. Commit 321d880.
tracing::trace!(sector, count, "write"); | ||
let mut state = self.state.write(); | ||
if sector + count as u64 > state.sector_count { | ||
return Err(DiskError::IllegalBlock); | ||
} | ||
for i in 0..count { | ||
let cur = i + sector as usize; | ||
let buf = buffers.subrange(i * SECTOR_SIZE as usize, SECTOR_SIZE as usize); | ||
let buf = buffers.subrange(i << self.sector_shift, 1 << self.sector_shift); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have the sector size buddy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't recompute it from the shift
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to use self.sector_size directly instead of recomputing it from the shift value throughout the codebase. Commit 321d880.
} | ||
Entry::Occupied(mut entry) => { | ||
if overwrite { | ||
reader.read(&mut entry.get_mut().0)?; | ||
let sector_data = reader.read_n(entry.get_mut().0.len())?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use read_n here, that reallocates unnecessarily. Read into the existing value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced read_n with direct read into existing buffer to avoid unnecessary reallocation. Commit 321d880.
@copilot go |
…necessary reallocations Co-authored-by: jstarks <[email protected]>
} | ||
|
||
#[async_test] | ||
async fn test_mixed_sector_sizes() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test seems pointless unless you combine the layers into a single disk and make sure the visible sector size matches what you'd expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the test to create a layered disk with matching sector sizes and verify the visible sector size behavior. Commit 13f0445.
} | ||
|
||
#[async_test] | ||
async fn test_backward_compatibility() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the test_backward_compatibility test as requested. Commit 13f0445.
@@ -52,6 +52,10 @@ pub struct RamDiskLayer { | |||
#[inspect(skip)] | |||
sector_count: AtomicU64, | |||
#[inspect(skip)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't skip inspecting the sector size
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the #[inspect(skip)] annotation from sector_size field to enable inspection. Commit 13f0445.
@copilot go |
… test, remove unnecessary test Co-authored-by: jstarks <[email protected]>
Adds configurable sector size support to the ramdisk implementation with performance optimizations, enabling 4K sector/block size testing as requested in #1492.
Problem
The ramdisk implementation (
disklayer_ram
) had hardcoded 512-byte sectors and used inefficient arithmetic operations, preventing testing of storage devices with 4K sectors - a common real-world scenario needed for comprehensive storage testing.Solution
Made sector size configurable with performance optimizations and proper validation:
Key Features
RamDiskLayer::new()
andram_disk()
continues to work unchangedUsage Examples
Performance Improvements
sector_shift
field to avoid runtime calculationsself.sector_size
directly instead of recomputing from shiftTesting
Enhanced test coverage includes:
Resolves #1492
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.