diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-05-15 11:07:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-05-15 11:07:25 -0400 |
commit | 5d41343ac88eeddd25dc4ffb7050c9095c41a70d (patch) | |
tree | bb40dd5493d19276a806bbd35064c44922b11d93 /fs | |
parent | c244450dac6d83be1ceadf29a65a5b49c34ceed8 (diff) | |
parent | 2ec0ae3acec47f628179ee95fe2c4da01b5e9fc4 (diff) |
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
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/extents.c | 19 | ||||
-rw-r--r-- | fs/ext4/inode.c | 26 |
2 files changed, 39 insertions, 6 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e40332158340..e3a55eb8b26a 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1841,11 +1841,13 @@ ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block, | |||
1841 | { | 1841 | { |
1842 | struct ext4_ext_cache *cex; | 1842 | struct ext4_ext_cache *cex; |
1843 | BUG_ON(len == 0); | 1843 | BUG_ON(len == 0); |
1844 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
1844 | cex = &EXT4_I(inode)->i_cached_extent; | 1845 | cex = &EXT4_I(inode)->i_cached_extent; |
1845 | cex->ec_type = type; | 1846 | cex->ec_type = type; |
1846 | cex->ec_block = block; | 1847 | cex->ec_block = block; |
1847 | cex->ec_len = len; | 1848 | cex->ec_len = len; |
1848 | cex->ec_start = start; | 1849 | cex->ec_start = start; |
1850 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
1849 | } | 1851 | } |
1850 | 1852 | ||
1851 | /* | 1853 | /* |
@@ -1902,12 +1904,17 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, | |||
1902 | struct ext4_extent *ex) | 1904 | struct ext4_extent *ex) |
1903 | { | 1905 | { |
1904 | struct ext4_ext_cache *cex; | 1906 | struct ext4_ext_cache *cex; |
1907 | int ret = EXT4_EXT_CACHE_NO; | ||
1905 | 1908 | ||
1909 | /* | ||
1910 | * We borrow i_block_reservation_lock to protect i_cached_extent | ||
1911 | */ | ||
1912 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
1906 | cex = &EXT4_I(inode)->i_cached_extent; | 1913 | cex = &EXT4_I(inode)->i_cached_extent; |
1907 | 1914 | ||
1908 | /* has cache valid data? */ | 1915 | /* has cache valid data? */ |
1909 | if (cex->ec_type == EXT4_EXT_CACHE_NO) | 1916 | if (cex->ec_type == EXT4_EXT_CACHE_NO) |
1910 | return EXT4_EXT_CACHE_NO; | 1917 | goto errout; |
1911 | 1918 | ||
1912 | BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP && | 1919 | BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP && |
1913 | cex->ec_type != EXT4_EXT_CACHE_EXTENT); | 1920 | cex->ec_type != EXT4_EXT_CACHE_EXTENT); |
@@ -1918,11 +1925,11 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block, | |||
1918 | ext_debug("%u cached by %u:%u:%llu\n", | 1925 | ext_debug("%u cached by %u:%u:%llu\n", |
1919 | block, | 1926 | block, |
1920 | cex->ec_block, cex->ec_len, cex->ec_start); | 1927 | cex->ec_block, cex->ec_len, cex->ec_start); |
1921 | return cex->ec_type; | 1928 | ret = cex->ec_type; |
1922 | } | 1929 | } |
1923 | 1930 | errout: | |
1924 | /* not in cache */ | 1931 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
1925 | return EXT4_EXT_CACHE_NO; | 1932 | return ret; |
1926 | } | 1933 | } |
1927 | 1934 | ||
1928 | /* | 1935 | /* |
@@ -2875,6 +2882,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2875 | if (allocated > max_blocks) | 2882 | if (allocated > max_blocks) |
2876 | allocated = max_blocks; | 2883 | allocated = max_blocks; |
2877 | set_buffer_unwritten(bh_result); | 2884 | set_buffer_unwritten(bh_result); |
2885 | bh_result->b_bdev = inode->i_sb->s_bdev; | ||
2886 | bh_result->b_blocknr = newblock; | ||
2878 | goto out2; | 2887 | goto out2; |
2879 | } | 2888 | } |
2880 | 2889 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index e91f978c7f12..2a9ffd528dd1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1149,6 +1149,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, | |||
1149 | int retval; | 1149 | int retval; |
1150 | 1150 | ||
1151 | clear_buffer_mapped(bh); | 1151 | clear_buffer_mapped(bh); |
1152 | clear_buffer_unwritten(bh); | ||
1152 | 1153 | ||
1153 | /* | 1154 | /* |
1154 | * Try to see if we can get the block without requesting | 1155 | * Try to see if we can get the block without requesting |
@@ -1179,6 +1180,18 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, | |||
1179 | return retval; | 1180 | return retval; |
1180 | 1181 | ||
1181 | /* | 1182 | /* |
1183 | * When we call get_blocks without the create flag, the | ||
1184 | * BH_Unwritten flag could have gotten set if the blocks | ||
1185 | * requested were part of a uninitialized extent. We need to | ||
1186 | * clear this flag now that we are committed to convert all or | ||
1187 | * part of the uninitialized extent to be an initialized | ||
1188 | * extent. This is because we need to avoid the combination | ||
1189 | * of BH_Unwritten and BH_Mapped flags being simultaneously | ||
1190 | * set on the buffer_head. | ||
1191 | */ | ||
1192 | clear_buffer_unwritten(bh); | ||
1193 | |||
1194 | /* | ||
1182 | * New blocks allocate and/or writing to uninitialized extent | 1195 | * New blocks allocate and/or writing to uninitialized extent |
1183 | * will possibly result in updating i_data, so we take | 1196 | * will possibly result in updating i_data, so we take |
1184 | * the write lock of i_data_sem, and call get_blocks() | 1197 | * the write lock of i_data_sem, and call get_blocks() |
@@ -2297,6 +2310,10 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, | |||
2297 | struct buffer_head *bh_result, int create) | 2310 | struct buffer_head *bh_result, int create) |
2298 | { | 2311 | { |
2299 | int ret = 0; | 2312 | int ret = 0; |
2313 | sector_t invalid_block = ~((sector_t) 0xffff); | ||
2314 | |||
2315 | if (invalid_block < ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es)) | ||
2316 | invalid_block = ~0; | ||
2300 | 2317 | ||
2301 | BUG_ON(create == 0); | 2318 | BUG_ON(create == 0); |
2302 | BUG_ON(bh_result->b_size != inode->i_sb->s_blocksize); | 2319 | 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, | |||
2318 | /* not enough space to reserve */ | 2335 | /* not enough space to reserve */ |
2319 | return ret; | 2336 | return ret; |
2320 | 2337 | ||
2321 | map_bh(bh_result, inode->i_sb, 0); | 2338 | map_bh(bh_result, inode->i_sb, invalid_block); |
2322 | set_buffer_new(bh_result); | 2339 | set_buffer_new(bh_result); |
2323 | set_buffer_delay(bh_result); | 2340 | set_buffer_delay(bh_result); |
2324 | } else if (ret > 0) { | 2341 | } else if (ret > 0) { |
2325 | bh_result->b_size = (ret << inode->i_blkbits); | 2342 | bh_result->b_size = (ret << inode->i_blkbits); |
2343 | /* | ||
2344 | * With sub-block writes into unwritten extents | ||
2345 | * we also need to mark the buffer as new so that | ||
2346 | * the unwritten parts of the buffer gets correctly zeroed. | ||
2347 | */ | ||
2348 | if (buffer_unwritten(bh_result)) | ||
2349 | set_buffer_new(bh_result); | ||
2326 | ret = 0; | 2350 | ret = 0; |
2327 | } | 2351 | } |
2328 | 2352 | ||