diff --git a/kernel/aster-nix/src/fs/exfat/mod.rs b/kernel/aster-nix/src/fs/exfat/mod.rs index fb961d8a..23036eb9 100644 --- a/kernel/aster-nix/src/fs/exfat/mod.rs +++ b/kernel/aster-nix/src/fs/exfat/mod.rs @@ -19,7 +19,7 @@ mod test { use aster_block::{ bio::{BioEnqueueError, BioStatus, BioType, SubmittedBio}, - BlockDevice, + BlockDevice, BlockDeviceMeta, }; use ostd::{ mm::{FrameAllocOptions, Segment, VmIo}, @@ -99,8 +99,11 @@ mod test { Ok(()) } - fn max_nr_segments_per_bio(&self) -> usize { - usize::MAX + fn metadata(&self) -> BlockDeviceMeta { + BlockDeviceMeta { + max_nr_segments_per_bio: usize::MAX, + nr_sectors: self.sectors_count(), + } } } /// Exfat disk image diff --git a/kernel/aster-nix/src/fs/ext2/fs.rs b/kernel/aster-nix/src/fs/ext2/fs.rs index ec2250f0..6420096f 100644 --- a/kernel/aster-nix/src/fs/ext2/fs.rs +++ b/kernel/aster-nix/src/fs/ext2/fs.rs @@ -36,7 +36,11 @@ impl Ext2 { let raw_super_block = block_device.read_val::(SUPER_BLOCK_OFFSET)?; SuperBlock::try_from(raw_super_block)? }; - assert!(super_block.block_size() == BLOCK_SIZE); + assert_eq!( + super_block.block_size(), + BLOCK_SIZE, + "currently only support 4096-byte block size" + ); let group_descriptors_segment = { let npages = ((super_block.block_groups_count() as usize) diff --git a/kernel/comps/block/src/lib.rs b/kernel/comps/block/src/lib.rs index fe228cab..9b40d49b 100644 --- a/kernel/comps/block/src/lib.rs +++ b/kernel/comps/block/src/lib.rs @@ -56,8 +56,19 @@ pub const SECTOR_SIZE: usize = 512; pub trait BlockDevice: Send + Sync + Any + Debug { /// Enqueues a new `SubmittedBio` to the block device. fn enqueue(&self, bio: SubmittedBio) -> Result<(), BioEnqueueError>; - /// Returns the upper limit for the number of segments per bio. - fn max_nr_segments_per_bio(&self) -> usize; + + /// Returns the metadata of the block device. + fn metadata(&self) -> BlockDeviceMeta; +} + +/// Metadata for a block device. +#[derive(Debug, Clone, Copy)] +pub struct BlockDeviceMeta { + /// The upper limit for the number of segments per bio. + pub max_nr_segments_per_bio: usize, + /// The total number of sectors of the block device. + pub nr_sectors: usize, + // Additional useful metadata can be added here in the future. } impl dyn BlockDevice { diff --git a/kernel/comps/virtio/src/device/block/device.rs b/kernel/comps/virtio/src/device/block/device.rs index 8c28d231..67f566fc 100644 --- a/kernel/comps/virtio/src/device/block/device.rs +++ b/kernel/comps/virtio/src/device/block/device.rs @@ -6,6 +6,7 @@ use core::{fmt::Debug, hint::spin_loop, mem::size_of}; use aster_block::{ bio::{BioEnqueueError, BioStatus, BioType, SubmittedBio}, request_queue::{BioRequest, BioRequestSingleQueue}, + BlockDeviceMeta, }; use aster_util::safe_ptr::SafePtr; use id_alloc::IdAlloc; @@ -79,8 +80,12 @@ impl aster_block::BlockDevice for BlockDevice { self.queue.enqueue(bio) } - fn max_nr_segments_per_bio(&self) -> usize { - self.queue.max_nr_segments_per_bio() + fn metadata(&self) -> BlockDeviceMeta { + let device_config = self.device.config.read().unwrap(); + BlockDeviceMeta { + max_nr_segments_per_bio: self.queue.max_nr_segments_per_bio(), + nr_sectors: device_config.capacity_sectors(), + } } } @@ -101,6 +106,11 @@ impl DeviceInner { /// Creates and inits the device. pub fn init(mut transport: Box) -> Result, VirtioDeviceError> { let config = VirtioBlockConfig::new(transport.as_mut()); + assert_eq!( + config.read().unwrap().block_size(), + VirtioBlockConfig::sector_size(), + "currently not support customized device logical block size" + ); let num_queues = transport.num_queues(); if num_queues != 1 { return Err(VirtioDeviceError::QueuesAmountDoNotMatch(num_queues, 1)); diff --git a/kernel/comps/virtio/src/device/block/mod.rs b/kernel/comps/virtio/src/device/block/mod.rs index e0970a80..9c84f1bd 100644 --- a/kernel/comps/virtio/src/device/block/mod.rs +++ b/kernel/comps/virtio/src/device/block/mod.rs @@ -2,6 +2,7 @@ pub mod device; +use aster_block::SECTOR_SIZE; use aster_util::safe_ptr::SafePtr; use bitflags::bitflags; use int_to_c_enum::TryFromInt; @@ -56,18 +57,32 @@ pub enum RespStatus { #[derive(Debug, Copy, Clone, Pod)] #[repr(C)] pub struct VirtioBlockConfig { + /// The number of 512-byte sectors. capacity: u64, + /// The maximum segment size. size_max: u64, + /// The geometry of the device. geometry: VirtioBlockGeometry, + /// The block size. If `logical_block_size` is not given in qemu cmdline, + /// `blk_size` will be set to sector size (512 bytes) by default. blk_size: u32, + /// The topology of the device. topology: VirtioBlockTopology, + /// Writeback mode. writeback: u8, unused0: [u8; 3], + /// The maximum discard sectors for one segment. max_discard_sectors: u32, + /// The maximum number of discard segments in a discard command. max_discard_seg: u32, + /// Discard commands must be aligned to this number of sectors. discard_sector_alignment: u32, + /// The maximum number of write zeroes sectors in one segment. max_write_zeroes_sectors: u32, + /// The maximum number of segments in a write zeroes command. max_write_zeroes_seg: u32, + /// Set if a write zeroes command may result in the + /// deallocation of one or more of the sectors. write_zeros_may_unmap: u8, unused1: [u8; 3], } @@ -83,9 +98,13 @@ pub struct VirtioBlockGeometry { #[derive(Debug, Copy, Clone, Pod)] #[repr(C)] pub struct VirtioBlockTopology { + /// Exponent for physical block per logical block. physical_block_exp: u8, + /// Alignment offset in logical blocks. alignment_offset: u8, + /// Minimum I/O size without performance penalty in logical blocks. min_io_size: u16, + /// Optimal sustained I/O size in logical blocks. opt_io_size: u32, } @@ -94,4 +113,20 @@ impl VirtioBlockConfig { let memory = transport.device_config_memory(); SafePtr::new(memory, 0) } + + pub(self) const fn sector_size() -> usize { + SECTOR_SIZE + } + + pub(self) fn block_size(&self) -> usize { + self.blk_size as usize + } + + pub(self) fn capacity_sectors(&self) -> usize { + self.capacity as usize + } + + pub(self) fn capacity_bytes(&self) -> usize { + self.capacity_sectors() * Self::sector_size() + } }