Fix some issues about Ext2's `blocks_count`.

- Rename `sector_count` to `occupied_sector_count`.
- Rename `blocks_count` to `size_in_blocks` and fix the related code.
- Fix the issue that `Metadata::blocks` return `blocks_count`, it
should be `occupied_sectors_count` instead.
This commit is contained in:
Chaoqun Zheng 2026-01-13 22:44:06 +08:00
parent 6d2ff13a63
commit 7f30f8226d
1 changed files with 32 additions and 26 deletions

View File

@ -110,7 +110,11 @@ impl Inode {
ino: self.ino() as _,
size: inner.file_size() as _,
blk_size: BLOCK_SIZE,
blocks: inner.blocks_count() as _,
// We should return the number of blocks occupied by this file rather than the file size.
// The former value would be smaller than the latter one if the file is sparse.
//
// Reference: <https://elixir.bootlin.com/linux/v6.18/source/include/uapi/asm-generic/stat.h#L36>
blocks: sectors_to_blocks(inner.occupied_sectors_count()) as usize,
atime: inner.atime(),
mtime: inner.mtime(),
ctime: inner.ctime(),
@ -887,7 +891,7 @@ impl Inode {
pub fn gid(&self) -> u32;
pub fn file_flags(&self) -> FileFlags;
pub fn hard_links(&self) -> u16;
pub fn blocks_count(&self) -> Ext2Bid;
pub fn size_in_blocks(&self) -> Ext2Bid;
pub fn acl(&self) -> Bid;
pub fn atime(&self) -> Duration;
pub fn mtime(&self) -> Duration;
@ -1191,7 +1195,8 @@ impl InodeInner {
pub fn hard_links(&self) -> u16;
pub fn inc_hard_links(&mut self);
pub fn dec_hard_links(&mut self);
pub fn blocks_count(&self) -> Ext2Bid;
pub fn size_in_blocks(&self) -> Ext2Bid;
pub fn occupied_sectors_count(&self) -> u32;
pub fn acl(&self) -> Bid;
pub fn set_acl(&mut self, bid: Bid);
pub fn atime(&self) -> Duration;
@ -1216,7 +1221,7 @@ struct InodeImpl {
impl InodeImpl {
pub fn new(desc: Dirty<InodeDesc>, weak_self: Weak<Inode>, fs: Weak<Ext2>) -> Self {
let block_manager = InodeBlockManager {
nblocks: AtomicUsize::new(desc.blocks_count() as _),
nblocks: AtomicUsize::new(desc.size_in_blocks() as _),
block_ptrs: RwMutex::new(desc.block_ptrs),
indirect_blocks: RwMutex::new(IndirectBlockCache::new(fs.clone())),
fs,
@ -1287,8 +1292,12 @@ impl InodeImpl {
self.desc.hard_links -= 1;
}
pub fn blocks_count(&self) -> Ext2Bid {
self.desc.blocks_count()
pub fn size_in_blocks(&self) -> Ext2Bid {
self.desc.size_in_blocks()
}
pub fn occupied_sectors_count(&self) -> u32 {
self.desc.occupied_sectors_count
}
pub fn acl(&self) -> Bid {
@ -1397,7 +1406,7 @@ impl InodeImpl {
/// which may result in an increased block count.
fn expand(&mut self, new_size: usize) -> Result<()> {
let new_blocks = self.desc.size_to_blocks(new_size);
let old_blocks = self.desc.blocks_count();
let old_blocks = self.desc.size_in_blocks();
// Expands block count if necessary
if new_blocks > old_blocks {
@ -1474,7 +1483,6 @@ impl InodeImpl {
self.fs().free_blocks(device_range).unwrap();
return Err(e);
}
self.last_alloc_device_bid = Some(device_range.end - 1);
let nr_blocks = device_range.len() as Ext2Bid;
self.desc.set_data_blocks(range.start + nr_blocks);
@ -1657,7 +1665,7 @@ impl InodeImpl {
/// which may result in an decreased block count.
fn shrink(&mut self, new_size: usize) {
let new_blocks = self.desc.size_to_blocks(new_size);
let old_blocks = self.desc.blocks_count();
let old_blocks = self.desc.size_in_blocks();
// Shrinks block count if necessary
if new_blocks < old_blocks {
@ -1672,7 +1680,7 @@ impl InodeImpl {
self.desc.size = new_size;
self.block_manager
.nblocks
.store(self.blocks_count() as _, Ordering::Release);
.store(self.size_in_blocks() as _, Ordering::Release);
}
/// Shrinks inode blocks.
@ -2132,8 +2140,8 @@ pub(super) struct InodeDesc {
dtime: Duration,
/// Hard links count.
hard_links: u16,
/// Number of sectors.
sector_count: u32,
/// Number of sectors occupied.
occupied_sectors_count: u32,
/// File flags.
flags: FileFlags,
/// Pointers to blocks.
@ -2162,7 +2170,7 @@ impl TryFrom<RawInode> for InodeDesc {
mtime: Duration::from(inode.mtime),
dtime: Duration::from(inode.dtime),
hard_links: inode.hard_links,
sector_count: inode.sector_count,
occupied_sectors_count: inode.occupied_sectors_count,
flags: FileFlags::from_bits(inode.flags)
.ok_or(Error::with_message(Errno::EINVAL, "invalid file flags"))?,
block_ptrs: inode.block_ptrs,
@ -2190,7 +2198,7 @@ impl InodeDesc {
mtime: now,
dtime: Duration::ZERO,
hard_links: 1,
sector_count: 0,
occupied_sectors_count: 0,
flags: FileFlags::empty(),
block_ptrs: BlockPtrs::default(),
acl: Bid::new(0),
@ -2198,13 +2206,10 @@ impl InodeDesc {
}
pub fn num_page_bytes(&self) -> usize {
(self.blocks_count() as usize) * BLOCK_SIZE
(self.size_in_blocks() as usize) * BLOCK_SIZE
}
/// Returns the actual number of blocks utilized, excluding the indirect blocks.
///
/// Ext2 allows the `block_count` to exceed the actual number of blocks utilized.
pub fn blocks_count(&self) -> Ext2Bid {
pub fn size_in_blocks(&self) -> Ext2Bid {
if self.is_fast_symlink() {
return 0;
}
@ -2233,17 +2238,18 @@ impl InodeDesc {
let old_acl_sectors = self.acl_sectors();
self.acl = bid;
let new_acl_sectors = self.acl_sectors();
self.sector_count = self.sector_count - old_acl_sectors + new_acl_sectors;
self.occupied_sectors_count =
self.occupied_sectors_count - old_acl_sectors + new_acl_sectors;
}
/// Returns the number of data sectors, including the indirect blocks.
fn data_sectors(&self) -> u32 {
self.sector_count - self.acl_sectors()
self.occupied_sectors_count - self.acl_sectors()
}
/// Sets the number of data blocks, including the indirect blocks.
fn set_data_blocks(&mut self, block_count: u32) {
self.sector_count = blocks_to_sectors(block_count) + self.acl_sectors();
self.occupied_sectors_count = blocks_to_sectors(block_count) + self.acl_sectors();
}
/// Returns whether the inode is a fast symlink.
@ -2254,8 +2260,8 @@ impl InodeDesc {
}
}
fn sectors_to_blocks(sector_count: u32) -> Ext2Bid {
sector_count.div_ceil((BLOCK_SIZE / SECTOR_SIZE) as u32)
fn sectors_to_blocks(sectors_count: u32) -> Ext2Bid {
sectors_count.div_ceil((BLOCK_SIZE / SECTOR_SIZE) as u32)
}
fn blocks_to_sectors(block_count: u32) -> u32 {
@ -2368,7 +2374,7 @@ pub(super) struct RawInode {
/// Low 16 bits of Group Id.
pub gid: u16,
pub hard_links: u16,
pub sector_count: u32,
pub occupied_sectors_count: u32,
/// File flags.
pub flags: u32,
/// OS dependent Value 1.
@ -2402,7 +2408,7 @@ impl From<&InodeDesc> for RawInode {
dtime: UnixTime::from(inode.dtime),
gid: inode.gid as u16,
hard_links: inode.hard_links,
sector_count: inode.sector_count,
occupied_sectors_count: inode.occupied_sectors_count,
flags: inode.flags.bits(),
block_ptrs: inode.block_ptrs,
file_acl: if inode.type_ == InodeType::File {