[Ocfs2-devel] [PATCH] ocfs2: Fix a bug in direct IO read.
Mark Fasheh
mfasheh at suse.com
Tue Sep 2 18:11:45 PDT 2008
On Tue, Sep 02, 2008 at 08:50:55AM +0800, Tao Ma wrote:
> ocfs2 will become read-only if we try to read the bytes which pass
> the end of i_size. This can be easily reproduced by following steps:
> 1. mkfs a ocfs2 volume with bs=4k cs=4k and nosparse.
> 2. create a small file(say less than 100 bytes) and we will create the file
> which is allocated 1 cluster.
> 3. read 8196 bytes from the kernel using O_DIRECT which exceeds the limit.
> 4. The ocfs2 volume becomes read-only and dmesg shows:
> OCFS2: ERROR (device sda13): ocfs2_direct_IO_get_blocks:
> Inode 66010 has a hole at block 1
> File system is now read-only due to the potential of on-disk corruption.
> Please run fsck.ocfs2 once the file system is unmounted.
>
> I have checked the code of 1.2 and copy the read check there.
> And actually I think even with sparse-enabled, this read check is ok.
Hmm - in this case we're supposed to return a short read. I think actually
the fix is a bit below at this line, where you're hitting the problem:
if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno) {
ocfs2_error(inode->i_sb,
"Inode %llu has a hole at block %llu\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)iblock);
ret = -EROFS;
goto bail;
}
How about changing that to:
if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno && create) {
So that we only check if there's a write (which really *is* something that
shouldn't happen for Ocfs2).
The rest of the code looks like it should handle things by clearing the
mapped bitt, which is correct.
--Mark
>
> Signed-off-by: Tao Ma <tao.ma at oracle.com>
> ---
> fs/ocfs2/aops.c | 8 ++++++++
> 1 files changed, 8 insertions(+), 0 deletions(-)
>
> diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
> index 80fa3fc..f27c1cc 100644
> --- a/fs/ocfs2/aops.c
> +++ b/fs/ocfs2/aops.c
> @@ -576,6 +576,14 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
> inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
>
> /*
> + * For a read which begins past the end of file, we return a hole.
> + */
> + if (!create && (iblock >= inode_blocks)) {
> + ret = 0;
> + goto bail;
> + }
> +
> + /*
> * Any write past EOF is not allowed because we'd be extending.
> */
> if (create && (iblock + max_blocks) > inode_blocks) {
> --
> 1.5.4.GIT
--
Mark Fasheh
More information about the Ocfs2-devel
mailing list