diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2008-07-11 19:27:31 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-07-11 19:27:31 -0400 |
commit | 7061eba75ceb0835ba61e7cbd757a6f9c1e4af92 (patch) | |
tree | 9c70df3078c0543573a9f38bb60c6b0f54608c7a | |
parent | 6afd670713c9e7d5c5550e379dfedca8ffab4c90 (diff) |
ext4: Use inode preallocation with -o noextents
When mballoc is enabled, block allocation for old block-based
files are allocated using mballoc allocator instead of old
block-based allocator. The old ext3 block reservation is turned
off when mballoc is turned on.
However, the in-core preallocation is not enabled for block-based/
non-extent based file block allocation. This result in performance
regression, as now we don't have "reservation" ore in-core preallocation
to prevent interleaved fragmentation in multiple writes workload.
This patch fix this by enable per inode in-core preallocation
for non extent files when mballoc is used.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/balloc.c | 36 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 7 | ||||
-rw-r--r-- | fs/ext4/extents.c | 2 | ||||
-rw-r--r-- | fs/ext4/inode.c | 72 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 2 |
5 files changed, 95 insertions, 24 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 1327ac3a04de..816f1dbaeb3c 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -1923,7 +1923,7 @@ out: | |||
1923 | return 0; | 1923 | return 0; |
1924 | } | 1924 | } |
1925 | 1925 | ||
1926 | ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode, | 1926 | ext4_fsblk_t ext4_new_meta_block(handle_t *handle, struct inode *inode, |
1927 | ext4_fsblk_t goal, int *errp) | 1927 | ext4_fsblk_t goal, int *errp) |
1928 | { | 1928 | { |
1929 | struct ext4_allocation_request ar; | 1929 | struct ext4_allocation_request ar; |
@@ -1942,9 +1942,29 @@ ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode, | |||
1942 | ret = ext4_mb_new_blocks(handle, &ar, errp); | 1942 | ret = ext4_mb_new_blocks(handle, &ar, errp); |
1943 | return ret; | 1943 | return ret; |
1944 | } | 1944 | } |
1945 | ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, | ||
1946 | ext4_fsblk_t goal, unsigned long *count, int *errp) | ||
1947 | { | ||
1948 | struct ext4_allocation_request ar; | ||
1949 | ext4_fsblk_t ret; | ||
1950 | |||
1951 | if (!test_opt(inode->i_sb, MBALLOC)) { | ||
1952 | ret = ext4_new_blocks_old(handle, inode, goal, count, errp); | ||
1953 | return ret; | ||
1954 | } | ||
1955 | |||
1956 | memset(&ar, 0, sizeof(ar)); | ||
1957 | ar.inode = inode; | ||
1958 | ar.goal = goal; | ||
1959 | ar.len = *count; | ||
1960 | ret = ext4_mb_new_blocks(handle, &ar, errp); | ||
1961 | *count = ar.len; | ||
1962 | return ret; | ||
1963 | } | ||
1945 | 1964 | ||
1946 | ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | 1965 | ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, |
1947 | ext4_fsblk_t goal, unsigned long *count, int *errp) | 1966 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
1967 | unsigned long *count, int *errp) | ||
1948 | { | 1968 | { |
1949 | struct ext4_allocation_request ar; | 1969 | struct ext4_allocation_request ar; |
1950 | ext4_fsblk_t ret; | 1970 | ext4_fsblk_t ret; |
@@ -1955,9 +1975,21 @@ ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | |||
1955 | } | 1975 | } |
1956 | 1976 | ||
1957 | memset(&ar, 0, sizeof(ar)); | 1977 | memset(&ar, 0, sizeof(ar)); |
1978 | /* Fill with neighbour allocated blocks */ | ||
1979 | ar.lleft = 0; | ||
1980 | ar.pleft = 0; | ||
1981 | ar.lright = 0; | ||
1982 | ar.pright = 0; | ||
1983 | |||
1958 | ar.inode = inode; | 1984 | ar.inode = inode; |
1959 | ar.goal = goal; | 1985 | ar.goal = goal; |
1960 | ar.len = *count; | 1986 | ar.len = *count; |
1987 | ar.logical = iblock; | ||
1988 | if (S_ISREG(inode->i_mode)) | ||
1989 | ar.flags = EXT4_MB_HINT_DATA; | ||
1990 | else | ||
1991 | /* disable in-core preallocation for non-regular files */ | ||
1992 | ar.flags = 0; | ||
1961 | ret = ext4_mb_new_blocks(handle, &ar, errp); | 1993 | ret = ext4_mb_new_blocks(handle, &ar, errp); |
1962 | *count = ar.len; | 1994 | *count = ar.len; |
1963 | return ret; | 1995 | return ret; |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0bfeae18f1a2..d44a7fb6a7b1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -970,10 +970,13 @@ extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, | |||
970 | extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); | 970 | extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); |
971 | extern unsigned long ext4_bg_num_gdb(struct super_block *sb, | 971 | extern unsigned long ext4_bg_num_gdb(struct super_block *sb, |
972 | ext4_group_t group); | 972 | ext4_group_t group); |
973 | extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode, | 973 | extern ext4_fsblk_t ext4_new_meta_block(handle_t *handle, struct inode *inode, |
974 | ext4_fsblk_t goal, int *errp); | 974 | ext4_fsblk_t goal, int *errp); |
975 | extern ext4_fsblk_t ext4_new_blocks (handle_t *handle, struct inode *inode, | 975 | extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, |
976 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 976 | ext4_fsblk_t goal, unsigned long *count, int *errp); |
977 | extern ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, | ||
978 | ext4_lblk_t iblock, ext4_fsblk_t goal, | ||
979 | unsigned long *count, int *errp); | ||
977 | extern ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode, | 980 | extern ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode, |
978 | ext4_fsblk_t goal, unsigned long *count, int *errp); | 981 | ext4_fsblk_t goal, unsigned long *count, int *errp); |
979 | extern void ext4_free_blocks (handle_t *handle, struct inode *inode, | 982 | extern void ext4_free_blocks (handle_t *handle, struct inode *inode, |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 17ea8bb12aa5..c729b3507b46 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -187,7 +187,7 @@ ext4_ext_new_block(handle_t *handle, struct inode *inode, | |||
187 | ext4_fsblk_t goal, newblock; | 187 | ext4_fsblk_t goal, newblock; |
188 | 188 | ||
189 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); | 189 | goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); |
190 | newblock = ext4_new_block(handle, inode, goal, err); | 190 | newblock = ext4_new_meta_block(handle, inode, goal, err); |
191 | return newblock; | 191 | return newblock; |
192 | } | 192 | } |
193 | 193 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7cce96a6935e..bc950562b5ba 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -508,11 +508,12 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks, | |||
508 | * direct blocks | 508 | * direct blocks |
509 | */ | 509 | */ |
510 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | 510 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, |
511 | ext4_fsblk_t goal, int indirect_blks, int blks, | 511 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
512 | ext4_fsblk_t new_blocks[4], int *err) | 512 | int indirect_blks, int blks, |
513 | ext4_fsblk_t new_blocks[4], int *err) | ||
513 | { | 514 | { |
514 | int target, i; | 515 | int target, i; |
515 | unsigned long count = 0; | 516 | unsigned long count = 0, blk_allocated = 0; |
516 | int index = 0; | 517 | int index = 0; |
517 | ext4_fsblk_t current_block = 0; | 518 | ext4_fsblk_t current_block = 0; |
518 | int ret = 0; | 519 | int ret = 0; |
@@ -525,12 +526,13 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
525 | * the first direct block of this branch. That's the | 526 | * the first direct block of this branch. That's the |
526 | * minimum number of blocks need to allocate(required) | 527 | * minimum number of blocks need to allocate(required) |
527 | */ | 528 | */ |
528 | target = blks + indirect_blks; | 529 | /* first we try to allocate the indirect blocks */ |
529 | 530 | target = indirect_blks; | |
530 | while (1) { | 531 | while (target > 0) { |
531 | count = target; | 532 | count = target; |
532 | /* allocating blocks for indirect blocks and direct blocks */ | 533 | /* allocating blocks for indirect blocks and direct blocks */ |
533 | current_block = ext4_new_blocks(handle,inode,goal,&count,err); | 534 | current_block = ext4_new_meta_blocks(handle, inode, |
535 | goal, &count, err); | ||
534 | if (*err) | 536 | if (*err) |
535 | goto failed_out; | 537 | goto failed_out; |
536 | 538 | ||
@@ -540,16 +542,48 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
540 | new_blocks[index++] = current_block++; | 542 | new_blocks[index++] = current_block++; |
541 | count--; | 543 | count--; |
542 | } | 544 | } |
543 | 545 | if (count > 0) { | |
544 | if (count > 0) | 546 | /* |
547 | * save the new block number | ||
548 | * for the first direct block | ||
549 | */ | ||
550 | new_blocks[index] = current_block; | ||
551 | printk(KERN_INFO "%s returned more blocks than " | ||
552 | "requested\n", __func__); | ||
553 | WARN_ON(1); | ||
545 | break; | 554 | break; |
555 | } | ||
546 | } | 556 | } |
547 | 557 | ||
548 | /* save the new block number for the first direct block */ | 558 | target = blks - count ; |
549 | new_blocks[index] = current_block; | 559 | blk_allocated = count; |
550 | 560 | if (!target) | |
561 | goto allocated; | ||
562 | /* Now allocate data blocks */ | ||
563 | count = target; | ||
564 | /* allocating blocks for indirect blocks and direct blocks */ | ||
565 | current_block = ext4_new_blocks(handle, inode, iblock, | ||
566 | goal, &count, err); | ||
567 | if (*err && (target == blks)) { | ||
568 | /* | ||
569 | * if the allocation failed and we didn't allocate | ||
570 | * any blocks before | ||
571 | */ | ||
572 | goto failed_out; | ||
573 | } | ||
574 | if (!*err) { | ||
575 | if (target == blks) { | ||
576 | /* | ||
577 | * save the new block number | ||
578 | * for the first direct block | ||
579 | */ | ||
580 | new_blocks[index] = current_block; | ||
581 | } | ||
582 | blk_allocated += count; | ||
583 | } | ||
584 | allocated: | ||
551 | /* total number of blocks allocated for direct blocks */ | 585 | /* total number of blocks allocated for direct blocks */ |
552 | ret = count; | 586 | ret = blk_allocated; |
553 | *err = 0; | 587 | *err = 0; |
554 | return ret; | 588 | return ret; |
555 | failed_out: | 589 | failed_out: |
@@ -584,8 +618,9 @@ failed_out: | |||
584 | * as described above and return 0. | 618 | * as described above and return 0. |
585 | */ | 619 | */ |
586 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | 620 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, |
587 | int indirect_blks, int *blks, ext4_fsblk_t goal, | 621 | ext4_lblk_t iblock, int indirect_blks, |
588 | ext4_lblk_t *offsets, Indirect *branch) | 622 | int *blks, ext4_fsblk_t goal, |
623 | ext4_lblk_t *offsets, Indirect *branch) | ||
589 | { | 624 | { |
590 | int blocksize = inode->i_sb->s_blocksize; | 625 | int blocksize = inode->i_sb->s_blocksize; |
591 | int i, n = 0; | 626 | int i, n = 0; |
@@ -595,7 +630,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
595 | ext4_fsblk_t new_blocks[4]; | 630 | ext4_fsblk_t new_blocks[4]; |
596 | ext4_fsblk_t current_block; | 631 | ext4_fsblk_t current_block; |
597 | 632 | ||
598 | num = ext4_alloc_blocks(handle, inode, goal, indirect_blks, | 633 | num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks, |
599 | *blks, new_blocks, &err); | 634 | *blks, new_blocks, &err); |
600 | if (err) | 635 | if (err) |
601 | return err; | 636 | return err; |
@@ -855,8 +890,9 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
855 | /* | 890 | /* |
856 | * Block out ext4_truncate while we alter the tree | 891 | * Block out ext4_truncate while we alter the tree |
857 | */ | 892 | */ |
858 | err = ext4_alloc_branch(handle, inode, indirect_blks, &count, goal, | 893 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, |
859 | offsets + (partial - chain), partial); | 894 | &count, goal, |
895 | offsets + (partial - chain), partial); | ||
860 | 896 | ||
861 | /* | 897 | /* |
862 | * The ext4_splice_branch call will free and forget any buffers | 898 | * The ext4_splice_branch call will free and forget any buffers |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index ff08633f398e..93c5fdcdad2e 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -810,7 +810,7 @@ inserted: | |||
810 | /* We need to allocate a new block */ | 810 | /* We need to allocate a new block */ |
811 | ext4_fsblk_t goal = ext4_group_first_block_no(sb, | 811 | ext4_fsblk_t goal = ext4_group_first_block_no(sb, |
812 | EXT4_I(inode)->i_block_group); | 812 | EXT4_I(inode)->i_block_group); |
813 | ext4_fsblk_t block = ext4_new_block(handle, inode, | 813 | ext4_fsblk_t block = ext4_new_meta_block(handle, inode, |
814 | goal, &error); | 814 | goal, &error); |
815 | if (error) | 815 | if (error) |
816 | goto cleanup; | 816 | goto cleanup; |