aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2008-07-11 19:27:31 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-07-11 19:27:31 -0400
commit7061eba75ceb0835ba61e7cbd757a6f9c1e4af92 (patch)
tree9c70df3078c0543573a9f38bb60c6b0f54608c7a
parent6afd670713c9e7d5c5550e379dfedca8ffab4c90 (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.c36
-rw-r--r--fs/ext4/ext4.h7
-rw-r--r--fs/ext4/extents.c2
-rw-r--r--fs/ext4/inode.c72
-rw-r--r--fs/ext4/xattr.c2
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
1926ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode, 1926ext4_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}
1945ext4_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
1946ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode, 1965ext4_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,
970extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); 970extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group);
971extern unsigned long ext4_bg_num_gdb(struct super_block *sb, 971extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
972 ext4_group_t group); 972 ext4_group_t group);
973extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode, 973extern 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);
975extern ext4_fsblk_t ext4_new_blocks (handle_t *handle, struct inode *inode, 975extern 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);
977extern 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);
977extern ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode, 980extern 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);
979extern void ext4_free_blocks (handle_t *handle, struct inode *inode, 982extern 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 */
510static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, 510static 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 }
584allocated:
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;
555failed_out: 589failed_out:
@@ -584,8 +618,9 @@ failed_out:
584 * as described above and return 0. 618 * as described above and return 0.
585 */ 619 */
586static int ext4_alloc_branch(handle_t *handle, struct inode *inode, 620static 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;