Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4: Fix race in ext4_inode_info.i_cached_extent ext4: Clear the unwritten buffer_head flag after the extent is initialized ext4: Use a fake block number for delayed new buffer_head ext4: Fix sub-block zeroing for writes into preallocated extents
This commit is contained in:
commit
5d41343ac8
2 changed files with 39 additions and 6 deletions
|
@ -1841,11 +1841,13 @@ ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block,
|
||||||
{
|
{
|
||||||
struct ext4_ext_cache *cex;
|
struct ext4_ext_cache *cex;
|
||||||
BUG_ON(len == 0);
|
BUG_ON(len == 0);
|
||||||
|
spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||||
cex = &EXT4_I(inode)->i_cached_extent;
|
cex = &EXT4_I(inode)->i_cached_extent;
|
||||||
cex->ec_type = type;
|
cex->ec_type = type;
|
||||||
cex->ec_block = block;
|
cex->ec_block = block;
|
||||||
cex->ec_len = len;
|
cex->ec_len = len;
|
||||||
cex->ec_start = start;
|
cex->ec_start = start;
|
||||||
|
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1902,12 +1904,17 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
|
||||||
struct ext4_extent *ex)
|
struct ext4_extent *ex)
|
||||||
{
|
{
|
||||||
struct ext4_ext_cache *cex;
|
struct ext4_ext_cache *cex;
|
||||||
|
int ret = EXT4_EXT_CACHE_NO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We borrow i_block_reservation_lock to protect i_cached_extent
|
||||||
|
*/
|
||||||
|
spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||||
cex = &EXT4_I(inode)->i_cached_extent;
|
cex = &EXT4_I(inode)->i_cached_extent;
|
||||||
|
|
||||||
/* has cache valid data? */
|
/* has cache valid data? */
|
||||||
if (cex->ec_type == EXT4_EXT_CACHE_NO)
|
if (cex->ec_type == EXT4_EXT_CACHE_NO)
|
||||||
return EXT4_EXT_CACHE_NO;
|
goto errout;
|
||||||
|
|
||||||
BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
|
BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
|
||||||
cex->ec_type != EXT4_EXT_CACHE_EXTENT);
|
cex->ec_type != EXT4_EXT_CACHE_EXTENT);
|
||||||
|
@ -1918,11 +1925,11 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
|
||||||
ext_debug("%u cached by %u:%u:%llu\n",
|
ext_debug("%u cached by %u:%u:%llu\n",
|
||||||
block,
|
block,
|
||||||
cex->ec_block, cex->ec_len, cex->ec_start);
|
cex->ec_block, cex->ec_len, cex->ec_start);
|
||||||
return cex->ec_type;
|
ret = cex->ec_type;
|
||||||
}
|
}
|
||||||
|
errout:
|
||||||
/* not in cache */
|
spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
|
||||||
return EXT4_EXT_CACHE_NO;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2875,6 +2882,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
|
||||||
if (allocated > max_blocks)
|
if (allocated > max_blocks)
|
||||||
allocated = max_blocks;
|
allocated = max_blocks;
|
||||||
set_buffer_unwritten(bh_result);
|
set_buffer_unwritten(bh_result);
|
||||||
|
bh_result->b_bdev = inode->i_sb->s_bdev;
|
||||||
|
bh_result->b_blocknr = newblock;
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1149,6 +1149,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
clear_buffer_mapped(bh);
|
clear_buffer_mapped(bh);
|
||||||
|
clear_buffer_unwritten(bh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to see if we can get the block without requesting
|
* Try to see if we can get the block without requesting
|
||||||
|
@ -1178,6 +1179,18 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
|
||||||
if (retval > 0 && buffer_mapped(bh))
|
if (retval > 0 && buffer_mapped(bh))
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we call get_blocks without the create flag, the
|
||||||
|
* BH_Unwritten flag could have gotten set if the blocks
|
||||||
|
* requested were part of a uninitialized extent. We need to
|
||||||
|
* clear this flag now that we are committed to convert all or
|
||||||
|
* part of the uninitialized extent to be an initialized
|
||||||
|
* extent. This is because we need to avoid the combination
|
||||||
|
* of BH_Unwritten and BH_Mapped flags being simultaneously
|
||||||
|
* set on the buffer_head.
|
||||||
|
*/
|
||||||
|
clear_buffer_unwritten(bh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* New blocks allocate and/or writing to uninitialized extent
|
* New blocks allocate and/or writing to uninitialized extent
|
||||||
* will possibly result in updating i_data, so we take
|
* will possibly result in updating i_data, so we take
|
||||||
|
@ -2297,6 +2310,10 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
|
||||||
struct buffer_head *bh_result, int create)
|
struct buffer_head *bh_result, int create)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
sector_t invalid_block = ~((sector_t) 0xffff);
|
||||||
|
|
||||||
|
if (invalid_block < ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es))
|
||||||
|
invalid_block = ~0;
|
||||||
|
|
||||||
BUG_ON(create == 0);
|
BUG_ON(create == 0);
|
||||||
BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
|
BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize);
|
||||||
|
@ -2318,11 +2335,18 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
|
||||||
/* not enough space to reserve */
|
/* not enough space to reserve */
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
map_bh(bh_result, inode->i_sb, 0);
|
map_bh(bh_result, inode->i_sb, invalid_block);
|
||||||
set_buffer_new(bh_result);
|
set_buffer_new(bh_result);
|
||||||
set_buffer_delay(bh_result);
|
set_buffer_delay(bh_result);
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
bh_result->b_size = (ret << inode->i_blkbits);
|
bh_result->b_size = (ret << inode->i_blkbits);
|
||||||
|
/*
|
||||||
|
* With sub-block writes into unwritten extents
|
||||||
|
* we also need to mark the buffer as new so that
|
||||||
|
* the unwritten parts of the buffer gets correctly zeroed.
|
||||||
|
*/
|
||||||
|
if (buffer_unwritten(bh_result))
|
||||||
|
set_buffer_new(bh_result);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue