Commit 25baf2da authored by Mark Fasheh's avatar Mark Fasheh

ocfs2: Teach ocfs2_get_block() about holes

ocfs2_get_block() didn't understand sparse files, fix that. Also remove some
code that isn't really useful anymore. We can fix up
ocfs2_direct_IO_get_blocks() at the same time.
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent 5069120b
...@@ -137,6 +137,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, ...@@ -137,6 +137,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
{ {
int err = 0; int err = 0;
u64 p_blkno, past_eof; u64 p_blkno, past_eof;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode, mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode,
(unsigned long long)iblock, bh_result, create); (unsigned long long)iblock, bh_result, create);
...@@ -151,15 +152,6 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, ...@@ -151,15 +152,6 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
goto bail; goto bail;
} }
/* this can happen if another node truncs after our extend! */
spin_lock(&OCFS2_I(inode)->ip_lock);
if (iblock >= ocfs2_clusters_to_blocks(inode->i_sb,
OCFS2_I(inode)->ip_clusters))
err = -EIO;
spin_unlock(&OCFS2_I(inode)->ip_lock);
if (err)
goto bail;
err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL); err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL);
if (err) { if (err) {
mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, " mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, "
...@@ -168,22 +160,38 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, ...@@ -168,22 +160,38 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock,
goto bail; goto bail;
} }
map_bh(bh_result, inode->i_sb, p_blkno); /*
* ocfs2 never allocates in this function - the only time we
if (bh_result->b_blocknr == 0) { * need to use BH_New is when we're extending i_size on a file
err = -EIO; * system which doesn't support holes, in which case BH_New
mlog(ML_ERROR, "iblock = %llu p_blkno = %llu blkno=(%llu)\n", * allows block_prepare_write() to zero.
(unsigned long long)iblock, */
(unsigned long long)p_blkno, mlog_bug_on_msg(create && p_blkno == 0 && ocfs2_sparse_alloc(osb),
(unsigned long long)OCFS2_I(inode)->ip_blkno); "ino %lu, iblock %llu\n", inode->i_ino,
} (unsigned long long)iblock);
if (p_blkno)
map_bh(bh_result, inode->i_sb, p_blkno);
if (!ocfs2_sparse_alloc(osb)) {
if (p_blkno == 0) {
err = -EIO;
mlog(ML_ERROR,
"iblock = %llu p_blkno = %llu blkno=(%llu)\n",
(unsigned long long)iblock,
(unsigned long long)p_blkno,
(unsigned long long)OCFS2_I(inode)->ip_blkno);
mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters);
dump_stack();
}
past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino, mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
(unsigned long long)past_eof); (unsigned long long)past_eof);
if (create && (iblock >= past_eof)) if (create && (iblock >= past_eof))
set_buffer_new(bh_result); set_buffer_new(bh_result);
}
bail: bail:
if (err < 0) if (err < 0)
...@@ -436,28 +444,15 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -436,28 +444,15 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
* nicely aligned and of the right size, so there's no need * nicely aligned and of the right size, so there's no need
* for us to check any of that. */ * for us to check any of that. */
spin_lock(&OCFS2_I(inode)->ip_lock); inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
inode_blocks = ocfs2_clusters_to_blocks(inode->i_sb,
OCFS2_I(inode)->ip_clusters);
/*
* For a read which begins past the end of file, we return a hole.
*/
if (!create && (iblock >= inode_blocks)) {
spin_unlock(&OCFS2_I(inode)->ip_lock);
ret = 0;
goto bail;
}
/* /*
* Any write past EOF is not allowed because we'd be extending. * Any write past EOF is not allowed because we'd be extending.
*/ */
if (create && (iblock + max_blocks) > inode_blocks) { if (create && (iblock + max_blocks) > inode_blocks) {
spin_unlock(&OCFS2_I(inode)->ip_lock);
ret = -EIO; ret = -EIO;
goto bail; goto bail;
} }
spin_unlock(&OCFS2_I(inode)->ip_lock);
/* This figures out the size of the next contiguous block, and /* This figures out the size of the next contiguous block, and
* our logical offset */ * our logical offset */
...@@ -470,7 +465,35 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ...@@ -470,7 +465,35 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock,
goto bail; goto bail;
} }
map_bh(bh_result, inode->i_sb, p_blkno); 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;
}
/*
* get_more_blocks() expects us to describe a hole by clearing
* the mapped bit on bh_result().
*/
if (p_blkno)
map_bh(bh_result, inode->i_sb, p_blkno);
else {
/*
* ocfs2_prepare_inode_for_write() should have caught
* the case where we'd be filling a hole and triggered
* a buffered write instead.
*/
if (create) {
ret = -EIO;
mlog_errno(ret);
goto bail;
}
clear_buffer_mapped(bh_result);
}
/* make sure we don't map more than max_blocks blocks here as /* make sure we don't map more than max_blocks blocks here as
that's all the kernel will handle at this point. */ that's all the kernel will handle at this point. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment