affs_extent_file_ofs() grows OFS mmu_private during write_begin. On allocation failure the error path still set i_size and mmu_private to newsize, so a partially extended hole left a too-large i_size. Set both to the bytes actually extended, and release the previous data block held across the failed getzeroblk_ino(). Signed-off-by: Xixin Liu --- fs/affs/file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/affs/file.c b/fs/affs/file.c index 144b17482d12..3265b6b6bf9f 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -569,6 +569,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize) pr_debug("%s(%llu, %d)\n", __func__, inode->i_ino, newsize); bsize = AFFS_SB(sb)->s_data_blksize; bh = NULL; + prev_bh = NULL; size = AFFS_I(inode)->mmu_private; bidx = size / bsize; boff = size % bsize; @@ -625,7 +626,9 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize) return 0; out: - inode->i_size = AFFS_I(inode)->mmu_private = newsize; + affs_brelse(prev_bh); + /* Keep i_size/mmu_private at how far we actually extended. */ + inode->i_size = AFFS_I(inode)->mmu_private = size; return PTR_ERR(bh); } @@ -662,9 +665,6 @@ static int affs_write_begin_ofs(const struct kiocb *iocb, pr_debug("%s(%llu, %llu, %llu)\n", __func__, inode->i_ino, pos, pos + len); if (pos > AFFS_I(inode)->mmu_private) { - /* XXX: this probably leaves a too-big i_size in case of - * failure. Should really be updating i_size at write_end time - */ err = affs_extent_file_ofs(inode, pos); if (err) return err; -- 2.43.0