@@ -433,14 +433,15 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
EXT4_GROUP_INFO_BBITMAP_CORRUPT);
return ERR_PTR(-EFSCORRUPTED);
}
- bh = sb_getblk(sb, bitmap_blk);
+ bh = ext4_sb_getblk_locked(sb, bitmap_blk);
if (unlikely(!bh)) {
ext4_warning(sb, "Cannot get buffer for block bitmap - "
"block_group = %u, block_bitmap = %llu",
block_group, bitmap_blk);
return ERR_PTR(-ENOMEM);
}
-
+ if (!buffer_uptodate(bh))
+ goto submit;
if (bitmap_uptodate(bh))
goto verify;
@@ -449,6 +450,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
unlock_buffer(bh);
goto verify;
}
+submit:
ext4_lock_group(sb, block_group);
if (ext4_has_group_desc_csum(sb) &&
(desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) {
@@ -488,11 +488,12 @@ __read_extent_tree_block(const char *function, unsigned int line,
struct buffer_head *bh;
int err;
- bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS);
+ bh = ext4_sb_getblk_locked_gfp(inode->i_sb, pblk,
+ __GFP_MOVABLE | GFP_NOFS);
if (unlikely(!bh))
return ERR_PTR(-ENOMEM);
- if (!bh_uptodate_or_lock(bh)) {
+ if (!buffer_uptodate(bh)) {
trace_ext4_ext_load_extent(inode, pblk, _RET_IP_);
err = bh_submit_read(bh);
if (err < 0)
@@ -137,13 +137,15 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
EXT4_GROUP_INFO_IBITMAP_CORRUPT);
return ERR_PTR(-EFSCORRUPTED);
}
- bh = sb_getblk(sb, bitmap_blk);
+ bh = ext4_sb_getblk_locked(sb, bitmap_blk);
if (unlikely(!bh)) {
ext4_warning(sb, "Cannot read inode bitmap - "
"block_group = %u, inode_bitmap = %llu",
block_group, bitmap_blk);
return ERR_PTR(-ENOMEM);
}
+ if (!buffer_uptodate(bh))
+ goto submit;
if (bitmap_uptodate(bh))
goto verify;
@@ -152,7 +154,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
unlock_buffer(bh);
goto verify;
}
-
+submit:
ext4_lock_group(sb, block_group);
if (ext4_has_group_desc_csum(sb) &&
(desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) {
@@ -156,13 +156,13 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth,
if (!p->key)
goto no_block;
while (--depth) {
- bh = sb_getblk(sb, le32_to_cpu(p->key));
+ bh = ext4_sb_getblk_locked(sb, le32_to_cpu(p->key));
if (unlikely(!bh)) {
ret = -ENOMEM;
goto failure;
}
- if (!bh_uptodate_or_lock(bh)) {
+ if (!buffer_uptodate(bh)) {
if (bh_submit_read(bh) < 0) {
put_bh(bh);
goto failure;
@@ -4276,27 +4276,10 @@ static int __ext4_get_inode_loc(struct inode *inode,
block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block);
iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb);
- bh = sb_getblk(sb, block);
+ bh = ext4_sb_getblk_locked(sb, block);
if (unlikely(!bh))
return -ENOMEM;
if (!buffer_uptodate(bh)) {
- lock_buffer(bh);
-
- /*
- * If the buffer has the write error flag, we have failed
- * to write out another inode in the same block. In this
- * case, we don't have to read the block because we may
- * read the old inode data successfully.
- */
- if (buffer_write_io_error(bh) && !buffer_uptodate(bh))
- set_buffer_uptodate(bh);
-
- if (buffer_uptodate(bh)) {
- /* someone brought it uptodate while we waited */
- unlock_buffer(bh);
- goto has_buffer;
- }
-
/*
* If we have all information of the inode in memory and this
* is the only valid inode in the block, we need not read the
@@ -4309,7 +4292,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
start = inode_offset & ~(inodes_per_block - 1);
/* Is the inode bitmap in cache? */
- bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp));
+ bitmap_bh = ext4_sb_getblk_locked(sb,
+ ext4_inode_bitmap(sb, gdp));
if (unlikely(!bitmap_bh))
goto make_io;
@@ -4319,6 +4303,7 @@ static int __ext4_get_inode_loc(struct inode *inode,
* of one, so skip it.
*/
if (!buffer_uptodate(bitmap_bh)) {
+ unlock_buffer(bitmap_bh);
brelse(bitmap_bh);
goto make_io;
}
@@ -1239,10 +1239,10 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb,
static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block)
{
- struct buffer_head *bh = sb_getblk(sb, block);
+ struct buffer_head *bh = ext4_sb_getblk_locked(sb, block);
if (unlikely(!bh))
return NULL;
- if (!bh_uptodate_or_lock(bh)) {
+ if (!buffer_uptodate(bh)) {
if (bh_submit_read(bh) < 0) {
brelse(bh);
return NULL;
@@ -202,13 +202,14 @@ __ext4_sb_getblk(struct super_block *sb, sector_t block, bool lock)
struct buffer_head *
ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags)
{
- struct buffer_head *bh = sb_getblk(sb, block);
+ struct buffer_head *bh;
+ bh = ext4_sb_getblk_locked(sb, block);
if (bh == NULL)
return ERR_PTR(-ENOMEM);
- if (ext4_buffer_uptodate(bh))
+ if (buffer_uptodate(bh))
return bh;
- ll_rw_block(REQ_OP_READ, REQ_META | op_flags, 1, &bh);
+ ll_rw_one_block(REQ_OP_READ, REQ_META | op_flags, bh);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
For the read buffer cases, now we invoke sb_getblk() and submit read bio if the buffer is not uptodate, but the uptodate checking is not accurate which may lead to read old metadata from the disk if the buffer has been failed to write out. Replace all sb_getblk() with ext4_sb_getblk_locked(), this function will check and fix the buffer's uptodate flag if it has write io error flag, and lock the buffer if it is actually not uptodate, so the caller don't need to lock the buffer after ext4_sb_getblk_locked() return. Signed-off-by: zhangyi (F) <yi.zhang@huawei.com> --- fs/ext4/balloc.c | 6 ++++-- fs/ext4/extents.c | 5 +++-- fs/ext4/ialloc.c | 6 ++++-- fs/ext4/indirect.c | 4 ++-- fs/ext4/inode.c | 23 ++++------------------- fs/ext4/resize.c | 4 ++-- fs/ext4/super.c | 7 ++++--- 7 files changed, 23 insertions(+), 32 deletions(-)