diff options
author | Zheng Liu <wenqing.lz@taobao.com> | 2012-11-08 21:57:35 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-11-08 21:57:35 -0500 |
commit | 7d1b1fbc95ebf41fee246dde437a77921f3bfec5 (patch) | |
tree | 542b4cfe57fe4ae81f6359c5db36e0a3e79f9d10 /fs/ext4 | |
parent | 992e9fdd7b3f656ab8aea895f0038336950774ed (diff) |
ext4: reimplement ext4_find_delay_alloc_range on extent status tree
Signed-off-by: Yongqiang Yang <xiaoqiangnk@gmail.com>
Signed-off-by: Allison Henderson <achender@linux.vnet.ibm.com>
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 4 | ||||
-rw-r--r-- | fs/ext4/ext4_extents.h | 3 | ||||
-rw-r--r-- | fs/ext4/extents.c | 117 | ||||
-rw-r--r-- | fs/ext4/inode.c | 53 |
4 files changed, 20 insertions, 157 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index bcc634b26d46..246e38f3915a 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2451,14 +2451,10 @@ enum ext4_state_bits { | |||
2451 | * never, ever appear in a buffer_head's state | 2451 | * never, ever appear in a buffer_head's state |
2452 | * flag. See EXT4_MAP_FROM_CLUSTER to see where | 2452 | * flag. See EXT4_MAP_FROM_CLUSTER to see where |
2453 | * this is used. */ | 2453 | * this is used. */ |
2454 | BH_Da_Mapped, /* Delayed allocated block that now has a mapping. This | ||
2455 | * flag is set when ext4_map_blocks is called on a | ||
2456 | * delayed allocated block to get its real mapping. */ | ||
2457 | }; | 2454 | }; |
2458 | 2455 | ||
2459 | BUFFER_FNS(Uninit, uninit) | 2456 | BUFFER_FNS(Uninit, uninit) |
2460 | TAS_BUFFER_FNS(Uninit, uninit) | 2457 | TAS_BUFFER_FNS(Uninit, uninit) |
2461 | BUFFER_FNS(Da_Mapped, da_mapped) | ||
2462 | 2458 | ||
2463 | /* | 2459 | /* |
2464 | * Add new method to test wether block and inode bitmaps are properly | 2460 | * Add new method to test wether block and inode bitmaps are properly |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index cb1b2c919963..603bb114735c 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -314,7 +314,6 @@ extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, | |||
314 | struct ext4_ext_path *); | 314 | struct ext4_ext_path *); |
315 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); | 315 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); |
316 | extern int ext4_ext_check_inode(struct inode *inode); | 316 | extern int ext4_ext_check_inode(struct inode *inode); |
317 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk, | 317 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); |
318 | int search_hint_reverse); | ||
319 | #endif /* _EXT4_EXTENTS */ | 318 | #endif /* _EXT4_EXTENTS */ |
320 | 319 | ||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 67660fa2a7e6..e0bedd1a4ac1 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -3461,115 +3461,34 @@ out: | |||
3461 | /** | 3461 | /** |
3462 | * ext4_find_delalloc_range: find delayed allocated block in the given range. | 3462 | * ext4_find_delalloc_range: find delayed allocated block in the given range. |
3463 | * | 3463 | * |
3464 | * Goes through the buffer heads in the range [lblk_start, lblk_end] and returns | 3464 | * Return 1 if there is a delalloc block in the range, otherwise 0. |
3465 | * whether there are any buffers marked for delayed allocation. It returns '1' | ||
3466 | * on the first delalloc'ed buffer head found. If no buffer head in the given | ||
3467 | * range is marked for delalloc, it returns 0. | ||
3468 | * lblk_start should always be <= lblk_end. | ||
3469 | * search_hint_reverse is to indicate that searching in reverse from lblk_end to | ||
3470 | * lblk_start might be more efficient (i.e., we will likely hit the delalloc'ed | ||
3471 | * block sooner). This is useful when blocks are truncated sequentially from | ||
3472 | * lblk_start towards lblk_end. | ||
3473 | */ | 3465 | */ |
3474 | static int ext4_find_delalloc_range(struct inode *inode, | 3466 | static int ext4_find_delalloc_range(struct inode *inode, |
3475 | ext4_lblk_t lblk_start, | 3467 | ext4_lblk_t lblk_start, |
3476 | ext4_lblk_t lblk_end, | 3468 | ext4_lblk_t lblk_end) |
3477 | int search_hint_reverse) | ||
3478 | { | 3469 | { |
3479 | struct address_space *mapping = inode->i_mapping; | 3470 | struct extent_status es; |
3480 | struct buffer_head *head, *bh = NULL; | ||
3481 | struct page *page; | ||
3482 | ext4_lblk_t i, pg_lblk; | ||
3483 | pgoff_t index; | ||
3484 | |||
3485 | if (!test_opt(inode->i_sb, DELALLOC)) | ||
3486 | return 0; | ||
3487 | |||
3488 | /* reverse search wont work if fs block size is less than page size */ | ||
3489 | if (inode->i_blkbits < PAGE_CACHE_SHIFT) | ||
3490 | search_hint_reverse = 0; | ||
3491 | 3471 | ||
3492 | if (search_hint_reverse) | 3472 | es.start = lblk_start; |
3493 | i = lblk_end; | 3473 | ext4_es_find_extent(inode, &es); |
3474 | if (es.len == 0) | ||
3475 | return 0; /* there is no delay extent in this tree */ | ||
3476 | else if (es.start <= lblk_start && lblk_start < es.start + es.len) | ||
3477 | return 1; | ||
3478 | else if (lblk_start <= es.start && es.start <= lblk_end) | ||
3479 | return 1; | ||
3494 | else | 3480 | else |
3495 | i = lblk_start; | 3481 | return 0; |
3496 | |||
3497 | index = i >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
3498 | |||
3499 | while ((i >= lblk_start) && (i <= lblk_end)) { | ||
3500 | page = find_get_page(mapping, index); | ||
3501 | if (!page) | ||
3502 | goto nextpage; | ||
3503 | |||
3504 | if (!page_has_buffers(page)) | ||
3505 | goto nextpage; | ||
3506 | |||
3507 | head = page_buffers(page); | ||
3508 | if (!head) | ||
3509 | goto nextpage; | ||
3510 | |||
3511 | bh = head; | ||
3512 | pg_lblk = index << (PAGE_CACHE_SHIFT - | ||
3513 | inode->i_blkbits); | ||
3514 | do { | ||
3515 | if (unlikely(pg_lblk < lblk_start)) { | ||
3516 | /* | ||
3517 | * This is possible when fs block size is less | ||
3518 | * than page size and our cluster starts/ends in | ||
3519 | * middle of the page. So we need to skip the | ||
3520 | * initial few blocks till we reach the 'lblk' | ||
3521 | */ | ||
3522 | pg_lblk++; | ||
3523 | continue; | ||
3524 | } | ||
3525 | |||
3526 | /* Check if the buffer is delayed allocated and that it | ||
3527 | * is not yet mapped. (when da-buffers are mapped during | ||
3528 | * their writeout, their da_mapped bit is set.) | ||
3529 | */ | ||
3530 | if (buffer_delay(bh) && !buffer_da_mapped(bh)) { | ||
3531 | page_cache_release(page); | ||
3532 | trace_ext4_find_delalloc_range(inode, | ||
3533 | lblk_start, lblk_end, | ||
3534 | search_hint_reverse, | ||
3535 | 1, i); | ||
3536 | return 1; | ||
3537 | } | ||
3538 | if (search_hint_reverse) | ||
3539 | i--; | ||
3540 | else | ||
3541 | i++; | ||
3542 | } while ((i >= lblk_start) && (i <= lblk_end) && | ||
3543 | ((bh = bh->b_this_page) != head)); | ||
3544 | nextpage: | ||
3545 | if (page) | ||
3546 | page_cache_release(page); | ||
3547 | /* | ||
3548 | * Move to next page. 'i' will be the first lblk in the next | ||
3549 | * page. | ||
3550 | */ | ||
3551 | if (search_hint_reverse) | ||
3552 | index--; | ||
3553 | else | ||
3554 | index++; | ||
3555 | i = index << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
3556 | } | ||
3557 | |||
3558 | trace_ext4_find_delalloc_range(inode, lblk_start, lblk_end, | ||
3559 | search_hint_reverse, 0, 0); | ||
3560 | return 0; | ||
3561 | } | 3482 | } |
3562 | 3483 | ||
3563 | int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk, | 3484 | int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk) |
3564 | int search_hint_reverse) | ||
3565 | { | 3485 | { |
3566 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 3486 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
3567 | ext4_lblk_t lblk_start, lblk_end; | 3487 | ext4_lblk_t lblk_start, lblk_end; |
3568 | lblk_start = lblk & (~(sbi->s_cluster_ratio - 1)); | 3488 | lblk_start = lblk & (~(sbi->s_cluster_ratio - 1)); |
3569 | lblk_end = lblk_start + sbi->s_cluster_ratio - 1; | 3489 | lblk_end = lblk_start + sbi->s_cluster_ratio - 1; |
3570 | 3490 | ||
3571 | return ext4_find_delalloc_range(inode, lblk_start, lblk_end, | 3491 | return ext4_find_delalloc_range(inode, lblk_start, lblk_end); |
3572 | search_hint_reverse); | ||
3573 | } | 3492 | } |
3574 | 3493 | ||
3575 | /** | 3494 | /** |
@@ -3630,7 +3549,7 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, | |||
3630 | lblk_from = lblk_start & (~(sbi->s_cluster_ratio - 1)); | 3549 | lblk_from = lblk_start & (~(sbi->s_cluster_ratio - 1)); |
3631 | lblk_to = lblk_from + c_offset - 1; | 3550 | lblk_to = lblk_from + c_offset - 1; |
3632 | 3551 | ||
3633 | if (ext4_find_delalloc_range(inode, lblk_from, lblk_to, 0)) | 3552 | if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) |
3634 | allocated_clusters--; | 3553 | allocated_clusters--; |
3635 | } | 3554 | } |
3636 | 3555 | ||
@@ -3640,7 +3559,7 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, | |||
3640 | lblk_from = lblk_start + num_blks; | 3559 | lblk_from = lblk_start + num_blks; |
3641 | lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1; | 3560 | lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1; |
3642 | 3561 | ||
3643 | if (ext4_find_delalloc_range(inode, lblk_from, lblk_to, 0)) | 3562 | if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) |
3644 | allocated_clusters--; | 3563 | allocated_clusters--; |
3645 | } | 3564 | } |
3646 | 3565 | ||
@@ -3927,7 +3846,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
3927 | if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { | 3846 | if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) { |
3928 | if (!newex.ee_start_lo && !newex.ee_start_hi) { | 3847 | if (!newex.ee_start_lo && !newex.ee_start_hi) { |
3929 | if ((sbi->s_cluster_ratio > 1) && | 3848 | if ((sbi->s_cluster_ratio > 1) && |
3930 | ext4_find_delalloc_cluster(inode, map->m_lblk, 0)) | 3849 | ext4_find_delalloc_cluster(inode, map->m_lblk)) |
3931 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; | 3850 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; |
3932 | 3851 | ||
3933 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { | 3852 | if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { |
@@ -4015,7 +3934,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | |||
4015 | } | 3934 | } |
4016 | 3935 | ||
4017 | if ((sbi->s_cluster_ratio > 1) && | 3936 | if ((sbi->s_cluster_ratio > 1) && |
4018 | ext4_find_delalloc_cluster(inode, map->m_lblk, 0)) | 3937 | ext4_find_delalloc_cluster(inode, map->m_lblk)) |
4019 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; | 3938 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; |
4020 | 3939 | ||
4021 | /* | 3940 | /* |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1e92349272e0..7f9ccc1381a9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -484,49 +484,6 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx, | |||
484 | } | 484 | } |
485 | 485 | ||
486 | /* | 486 | /* |
487 | * Sets the BH_Da_Mapped bit on the buffer heads corresponding to the given map. | ||
488 | */ | ||
489 | static void set_buffers_da_mapped(struct inode *inode, | ||
490 | struct ext4_map_blocks *map) | ||
491 | { | ||
492 | struct address_space *mapping = inode->i_mapping; | ||
493 | struct pagevec pvec; | ||
494 | int i, nr_pages; | ||
495 | pgoff_t index, end; | ||
496 | |||
497 | index = map->m_lblk >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
498 | end = (map->m_lblk + map->m_len - 1) >> | ||
499 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
500 | |||
501 | pagevec_init(&pvec, 0); | ||
502 | while (index <= end) { | ||
503 | nr_pages = pagevec_lookup(&pvec, mapping, index, | ||
504 | min(end - index + 1, | ||
505 | (pgoff_t)PAGEVEC_SIZE)); | ||
506 | if (nr_pages == 0) | ||
507 | break; | ||
508 | for (i = 0; i < nr_pages; i++) { | ||
509 | struct page *page = pvec.pages[i]; | ||
510 | struct buffer_head *bh, *head; | ||
511 | |||
512 | if (unlikely(page->mapping != mapping) || | ||
513 | !PageDirty(page)) | ||
514 | break; | ||
515 | |||
516 | if (page_has_buffers(page)) { | ||
517 | bh = head = page_buffers(page); | ||
518 | do { | ||
519 | set_buffer_da_mapped(bh); | ||
520 | bh = bh->b_this_page; | ||
521 | } while (bh != head); | ||
522 | } | ||
523 | index++; | ||
524 | } | ||
525 | pagevec_release(&pvec); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * The ext4_map_blocks() function tries to look up the requested blocks, | 487 | * The ext4_map_blocks() function tries to look up the requested blocks, |
531 | * and returns if the blocks are already mapped. | 488 | * and returns if the blocks are already mapped. |
532 | * | 489 | * |
@@ -661,13 +618,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
661 | if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { | 618 | if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { |
662 | ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED); | 619 | ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED); |
663 | 620 | ||
664 | /* If we have successfully mapped the delayed allocated blocks, | ||
665 | * set the BH_Da_Mapped bit on them. Its important to do this | ||
666 | * under the protection of i_data_sem. | ||
667 | */ | ||
668 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 621 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { |
669 | int ret; | 622 | int ret; |
670 | set_buffers_da_mapped(inode, map); | ||
671 | delayed_mapped: | 623 | delayed_mapped: |
672 | /* delayed allocation blocks has been allocated */ | 624 | /* delayed allocation blocks has been allocated */ |
673 | ret = ext4_es_remove_extent(inode, map->m_lblk, | 625 | ret = ext4_es_remove_extent(inode, map->m_lblk, |
@@ -1330,7 +1282,6 @@ static void ext4_da_page_release_reservation(struct page *page, | |||
1330 | if ((offset <= curr_off) && (buffer_delay(bh))) { | 1282 | if ((offset <= curr_off) && (buffer_delay(bh))) { |
1331 | to_release++; | 1283 | to_release++; |
1332 | clear_buffer_delay(bh); | 1284 | clear_buffer_delay(bh); |
1333 | clear_buffer_da_mapped(bh); | ||
1334 | } | 1285 | } |
1335 | curr_off = next_off; | 1286 | curr_off = next_off; |
1336 | } while ((bh = bh->b_this_page) != head); | 1287 | } while ((bh = bh->b_this_page) != head); |
@@ -1347,7 +1298,7 @@ static void ext4_da_page_release_reservation(struct page *page, | |||
1347 | lblk = (page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits)) + | 1298 | lblk = (page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits)) + |
1348 | ((num_clusters - 1) << sbi->s_cluster_bits); | 1299 | ((num_clusters - 1) << sbi->s_cluster_bits); |
1349 | if (sbi->s_cluster_ratio == 1 || | 1300 | if (sbi->s_cluster_ratio == 1 || |
1350 | !ext4_find_delalloc_cluster(inode, lblk, 1)) | 1301 | !ext4_find_delalloc_cluster(inode, lblk)) |
1351 | ext4_da_release_space(inode, 1); | 1302 | ext4_da_release_space(inode, 1); |
1352 | 1303 | ||
1353 | num_clusters--; | 1304 | num_clusters--; |
@@ -1453,8 +1404,6 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
1453 | clear_buffer_delay(bh); | 1404 | clear_buffer_delay(bh); |
1454 | bh->b_blocknr = pblock; | 1405 | bh->b_blocknr = pblock; |
1455 | } | 1406 | } |
1456 | if (buffer_da_mapped(bh)) | ||
1457 | clear_buffer_da_mapped(bh); | ||
1458 | if (buffer_unwritten(bh) || | 1407 | if (buffer_unwritten(bh) || |
1459 | buffer_mapped(bh)) | 1408 | buffer_mapped(bh)) |
1460 | BUG_ON(bh->b_blocknr != pblock); | 1409 | BUG_ON(bh->b_blocknr != pblock); |