aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorZheng Liu <wenqing.lz@taobao.com>2012-11-08 21:57:35 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-11-08 21:57:35 -0500
commit7d1b1fbc95ebf41fee246dde437a77921f3bfec5 (patch)
tree542b4cfe57fe4ae81f6359c5db36e0a3e79f9d10 /fs/ext4
parent992e9fdd7b3f656ab8aea895f0038336950774ed (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.h4
-rw-r--r--fs/ext4/ext4_extents.h3
-rw-r--r--fs/ext4/extents.c117
-rw-r--r--fs/ext4/inode.c53
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
2459BUFFER_FNS(Uninit, uninit) 2456BUFFER_FNS(Uninit, uninit)
2460TAS_BUFFER_FNS(Uninit, uninit) 2457TAS_BUFFER_FNS(Uninit, uninit)
2461BUFFER_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 *);
315extern void ext4_ext_drop_refs(struct ext4_ext_path *); 315extern void ext4_ext_drop_refs(struct ext4_ext_path *);
316extern int ext4_ext_check_inode(struct inode *inode); 316extern int ext4_ext_check_inode(struct inode *inode);
317extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk, 317extern 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 */
3474static int ext4_find_delalloc_range(struct inode *inode, 3466static 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));
3544nextpage:
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
3563int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk, 3484int 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 */
489static 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);
671delayed_mapped: 623delayed_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);