diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 128 |
1 files changed, 63 insertions, 65 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 3753ceb0b0dd..95bf4679ac54 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public Licens | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- |
21 | */ | 21 | */ |
@@ -1736,6 +1736,12 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1736 | */ | 1736 | */ |
1737 | if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN) | 1737 | if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN) |
1738 | return 0; | 1738 | return 0; |
1739 | /* | ||
1740 | * The check for IO to unwritten extent is somewhat racy as we | ||
1741 | * increment i_unwritten / set EXT4_STATE_DIO_UNWRITTEN only after | ||
1742 | * dropping i_data_sem. But reserved blocks should save us in that | ||
1743 | * case. | ||
1744 | */ | ||
1739 | if (ext4_ext_is_unwritten(ex1) && | 1745 | if (ext4_ext_is_unwritten(ex1) && |
1740 | (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) || | 1746 | (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) || |
1741 | atomic_read(&EXT4_I(inode)->i_unwritten) || | 1747 | atomic_read(&EXT4_I(inode)->i_unwritten) || |
@@ -2293,59 +2299,69 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
2293 | } | 2299 | } |
2294 | 2300 | ||
2295 | /* | 2301 | /* |
2296 | * ext4_ext_put_gap_in_cache: | 2302 | * ext4_ext_determine_hole - determine hole around given block |
2297 | * calculate boundaries of the gap that the requested block fits into | 2303 | * @inode: inode we lookup in |
2298 | * and cache this gap | 2304 | * @path: path in extent tree to @lblk |
2305 | * @lblk: pointer to logical block around which we want to determine hole | ||
2306 | * | ||
2307 | * Determine hole length (and start if easily possible) around given logical | ||
2308 | * block. We don't try too hard to find the beginning of the hole but @path | ||
2309 | * actually points to extent before @lblk, we provide it. | ||
2310 | * | ||
2311 | * The function returns the length of a hole starting at @lblk. We update @lblk | ||
2312 | * to the beginning of the hole if we managed to find it. | ||
2299 | */ | 2313 | */ |
2300 | static void | 2314 | static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode, |
2301 | ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path, | 2315 | struct ext4_ext_path *path, |
2302 | ext4_lblk_t block) | 2316 | ext4_lblk_t *lblk) |
2303 | { | 2317 | { |
2304 | int depth = ext_depth(inode); | 2318 | int depth = ext_depth(inode); |
2305 | ext4_lblk_t len; | ||
2306 | ext4_lblk_t lblock; | ||
2307 | struct ext4_extent *ex; | 2319 | struct ext4_extent *ex; |
2308 | struct extent_status es; | 2320 | ext4_lblk_t len; |
2309 | 2321 | ||
2310 | ex = path[depth].p_ext; | 2322 | ex = path[depth].p_ext; |
2311 | if (ex == NULL) { | 2323 | if (ex == NULL) { |
2312 | /* there is no extent yet, so gap is [0;-] */ | 2324 | /* there is no extent yet, so gap is [0;-] */ |
2313 | lblock = 0; | 2325 | *lblk = 0; |
2314 | len = EXT_MAX_BLOCKS; | 2326 | len = EXT_MAX_BLOCKS; |
2315 | ext_debug("cache gap(whole file):"); | 2327 | } else if (*lblk < le32_to_cpu(ex->ee_block)) { |
2316 | } else if (block < le32_to_cpu(ex->ee_block)) { | 2328 | len = le32_to_cpu(ex->ee_block) - *lblk; |
2317 | lblock = block; | 2329 | } else if (*lblk >= le32_to_cpu(ex->ee_block) |
2318 | len = le32_to_cpu(ex->ee_block) - block; | ||
2319 | ext_debug("cache gap(before): %u [%u:%u]", | ||
2320 | block, | ||
2321 | le32_to_cpu(ex->ee_block), | ||
2322 | ext4_ext_get_actual_len(ex)); | ||
2323 | } else if (block >= le32_to_cpu(ex->ee_block) | ||
2324 | + ext4_ext_get_actual_len(ex)) { | 2330 | + ext4_ext_get_actual_len(ex)) { |
2325 | ext4_lblk_t next; | 2331 | ext4_lblk_t next; |
2326 | lblock = le32_to_cpu(ex->ee_block) | ||
2327 | + ext4_ext_get_actual_len(ex); | ||
2328 | 2332 | ||
2333 | *lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex); | ||
2329 | next = ext4_ext_next_allocated_block(path); | 2334 | next = ext4_ext_next_allocated_block(path); |
2330 | ext_debug("cache gap(after): [%u:%u] %u", | 2335 | BUG_ON(next == *lblk); |
2331 | le32_to_cpu(ex->ee_block), | 2336 | len = next - *lblk; |
2332 | ext4_ext_get_actual_len(ex), | ||
2333 | block); | ||
2334 | BUG_ON(next == lblock); | ||
2335 | len = next - lblock; | ||
2336 | } else { | 2337 | } else { |
2337 | BUG(); | 2338 | BUG(); |
2338 | } | 2339 | } |
2340 | return len; | ||
2341 | } | ||
2339 | 2342 | ||
2340 | ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es); | 2343 | /* |
2344 | * ext4_ext_put_gap_in_cache: | ||
2345 | * calculate boundaries of the gap that the requested block fits into | ||
2346 | * and cache this gap | ||
2347 | */ | ||
2348 | static void | ||
2349 | ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start, | ||
2350 | ext4_lblk_t hole_len) | ||
2351 | { | ||
2352 | struct extent_status es; | ||
2353 | |||
2354 | ext4_es_find_delayed_extent_range(inode, hole_start, | ||
2355 | hole_start + hole_len - 1, &es); | ||
2341 | if (es.es_len) { | 2356 | if (es.es_len) { |
2342 | /* There's delayed extent containing lblock? */ | 2357 | /* There's delayed extent containing lblock? */ |
2343 | if (es.es_lblk <= lblock) | 2358 | if (es.es_lblk <= hole_start) |
2344 | return; | 2359 | return; |
2345 | len = min(es.es_lblk - lblock, len); | 2360 | hole_len = min(es.es_lblk - hole_start, hole_len); |
2346 | } | 2361 | } |
2347 | ext_debug(" -> %u:%u\n", lblock, len); | 2362 | ext_debug(" -> %u:%u\n", hole_start, hole_len); |
2348 | ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE); | 2363 | ext4_es_insert_extent(inode, hole_start, hole_len, ~0, |
2364 | EXTENT_STATUS_HOLE); | ||
2349 | } | 2365 | } |
2350 | 2366 | ||
2351 | /* | 2367 | /* |
@@ -3927,7 +3943,7 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, | |||
3927 | static int | 3943 | static int |
3928 | convert_initialized_extent(handle_t *handle, struct inode *inode, | 3944 | convert_initialized_extent(handle_t *handle, struct inode *inode, |
3929 | struct ext4_map_blocks *map, | 3945 | struct ext4_map_blocks *map, |
3930 | struct ext4_ext_path **ppath, int flags, | 3946 | struct ext4_ext_path **ppath, |
3931 | unsigned int allocated) | 3947 | unsigned int allocated) |
3932 | { | 3948 | { |
3933 | struct ext4_ext_path *path = *ppath; | 3949 | struct ext4_ext_path *path = *ppath; |
@@ -4007,7 +4023,6 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, | |||
4007 | struct ext4_ext_path *path = *ppath; | 4023 | struct ext4_ext_path *path = *ppath; |
4008 | int ret = 0; | 4024 | int ret = 0; |
4009 | int err = 0; | 4025 | int err = 0; |
4010 | ext4_io_end_t *io = ext4_inode_aio(inode); | ||
4011 | 4026 | ||
4012 | ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical " | 4027 | ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical " |
4013 | "block %llu, max_blocks %u, flags %x, allocated %u\n", | 4028 | "block %llu, max_blocks %u, flags %x, allocated %u\n", |
@@ -4030,15 +4045,6 @@ ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, | |||
4030 | flags | EXT4_GET_BLOCKS_CONVERT); | 4045 | flags | EXT4_GET_BLOCKS_CONVERT); |
4031 | if (ret <= 0) | 4046 | if (ret <= 0) |
4032 | goto out; | 4047 | goto out; |
4033 | /* | ||
4034 | * Flag the inode(non aio case) or end_io struct (aio case) | ||
4035 | * that this IO needs to conversion to written when IO is | ||
4036 | * completed | ||
4037 | */ | ||
4038 | if (io) | ||
4039 | ext4_set_io_unwritten_flag(inode, io); | ||
4040 | else | ||
4041 | ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); | ||
4042 | map->m_flags |= EXT4_MAP_UNWRITTEN; | 4048 | map->m_flags |= EXT4_MAP_UNWRITTEN; |
4043 | goto out; | 4049 | goto out; |
4044 | } | 4050 | } |
@@ -4283,9 +4289,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
4283 | unsigned int allocated = 0, offset = 0; | 4289 | unsigned int allocated = 0, offset = 0; |
4284 | unsigned int allocated_clusters = 0; | 4290 | unsigned int allocated_clusters = 0; |
4285 | struct ext4_allocation_request ar; | 4291 | struct ext4_allocation_request ar; |
4286 | ext4_io_end_t *io = ext4_inode_aio(inode); | ||
4287 | ext4_lblk_t cluster_offset; | 4292 | ext4_lblk_t cluster_offset; |
4288 | int set_unwritten = 0; | ||
4289 | bool map_from_cluster = false; | 4293 | bool map_from_cluster = false; |
4290 | 4294 | ||
4291 | ext_debug("blocks %u/%u requested for inode %lu\n", | 4295 | ext_debug("blocks %u/%u requested for inode %lu\n", |
@@ -4347,7 +4351,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
4347 | (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { | 4351 | (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { |
4348 | allocated = convert_initialized_extent( | 4352 | allocated = convert_initialized_extent( |
4349 | handle, inode, map, &path, | 4353 | handle, inode, map, &path, |
4350 | flags, allocated); | 4354 | allocated); |
4351 | goto out2; | 4355 | goto out2; |
4352 | } else if (!ext4_ext_is_unwritten(ex)) | 4356 | } else if (!ext4_ext_is_unwritten(ex)) |
4353 | goto out; | 4357 | goto out; |
@@ -4368,11 +4372,22 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
4368 | * we couldn't try to create block if create flag is zero | 4372 | * we couldn't try to create block if create flag is zero |
4369 | */ | 4373 | */ |
4370 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { | 4374 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { |
4375 | ext4_lblk_t hole_start, hole_len; | ||
4376 | |||
4377 | hole_start = map->m_lblk; | ||
4378 | hole_len = ext4_ext_determine_hole(inode, path, &hole_start); | ||
4371 | /* | 4379 | /* |
4372 | * put just found gap into cache to speed up | 4380 | * put just found gap into cache to speed up |
4373 | * subsequent requests | 4381 | * subsequent requests |
4374 | */ | 4382 | */ |
4375 | ext4_ext_put_gap_in_cache(inode, path, map->m_lblk); | 4383 | ext4_ext_put_gap_in_cache(inode, hole_start, hole_len); |
4384 | |||
4385 | /* Update hole_len to reflect hole size after map->m_lblk */ | ||
4386 | if (hole_start != map->m_lblk) | ||
4387 | hole_len -= map->m_lblk - hole_start; | ||
4388 | map->m_pblk = 0; | ||
4389 | map->m_len = min_t(unsigned int, map->m_len, hole_len); | ||
4390 | |||
4376 | goto out2; | 4391 | goto out2; |
4377 | } | 4392 | } |
4378 | 4393 | ||
@@ -4482,15 +4497,6 @@ got_allocated_blocks: | |||
4482 | if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){ | 4497 | if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){ |
4483 | ext4_ext_mark_unwritten(&newex); | 4498 | ext4_ext_mark_unwritten(&newex); |
4484 | map->m_flags |= EXT4_MAP_UNWRITTEN; | 4499 | map->m_flags |= EXT4_MAP_UNWRITTEN; |
4485 | /* | ||
4486 | * io_end structure was created for every IO write to an | ||
4487 | * unwritten extent. To avoid unnecessary conversion, | ||
4488 | * here we flag the IO that really needs the conversion. | ||
4489 | * For non asycn direct IO case, flag the inode state | ||
4490 | * that we need to perform conversion when IO is done. | ||
4491 | */ | ||
4492 | if (flags & EXT4_GET_BLOCKS_PRE_IO) | ||
4493 | set_unwritten = 1; | ||
4494 | } | 4500 | } |
4495 | 4501 | ||
4496 | err = 0; | 4502 | err = 0; |
@@ -4501,14 +4507,6 @@ got_allocated_blocks: | |||
4501 | err = ext4_ext_insert_extent(handle, inode, &path, | 4507 | err = ext4_ext_insert_extent(handle, inode, &path, |
4502 | &newex, flags); | 4508 | &newex, flags); |
4503 | 4509 | ||
4504 | if (!err && set_unwritten) { | ||
4505 | if (io) | ||
4506 | ext4_set_io_unwritten_flag(inode, io); | ||
4507 | else | ||
4508 | ext4_set_inode_state(inode, | ||
4509 | EXT4_STATE_DIO_UNWRITTEN); | ||
4510 | } | ||
4511 | |||
4512 | if (err && free_on_err) { | 4510 | if (err && free_on_err) { |
4513 | int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? | 4511 | int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? |
4514 | EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; | 4512 | EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; |