From c9eb2c856f3b1d2341d78b83faab6f45835b85cf Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 29 Jan 2004 15:43:02 +0000 Subject: [PATCH] - initial implementation of batching block allocator for ext3 lots of tweaking to be done yet --- .../patches/ext3-mballoc-2.4.24.patch | 343 +++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 lustre/kernel_patches/patches/ext3-mballoc-2.4.24.patch diff --git a/lustre/kernel_patches/patches/ext3-mballoc-2.4.24.patch b/lustre/kernel_patches/patches/ext3-mballoc-2.4.24.patch new file mode 100644 index 0000000..a234f96 --- /dev/null +++ b/lustre/kernel_patches/patches/ext3-mballoc-2.4.24.patch @@ -0,0 +1,343 @@ +Index: linux-2.4.24/fs/ext3/balloc.c +=================================================================== +--- linux-2.4.24.orig/fs/ext3/balloc.c 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24/fs/ext3/balloc.c 2004-01-29 17:27:54.000000000 +0300 +@@ -1007,3 +1007,294 @@ + bitmap_count); + } + #endif ++ ++#define MBDEBUG_ ++#ifdef MBDEBUG ++#define mbdebug(fmt,a...) printk(fmt, ##a) ++#else ++#define mbdebug(fmt,a...) ++#endif ++ ++/* ++ * in alloc_status we track allocation: the best found extent, how many ++ * extents we've skipped, etc ++ */ ++struct alloc_status { ++ struct super_block *sb; ++ int goal; /* goal for allocation */ ++ int target_len; /* goal for len */ ++ int start, len; /* the best found extent */ ++ int num; /* number of extent: to limit searching */ ++}; ++ ++/* ++ * ext3_test_extent() compares requested extent with existing in as. ++ * if requested extent is better than that, then replace old one. ++ * then it tries to understand is new extent suitable or not ++ * return 1 if caller can complete searching ++ */ ++inline int ext3_test_extent(struct alloc_status *as, int group, ++ int start, int len) ++{ ++ struct ext3_super_block * es = EXT3_SB(as->sb)->s_es; ++ unsigned long tmp; ++ ++ J_ASSERT(as->target_len >= len); ++ ++ mbdebug("found extent %d:%d\n", start, len); ++ tmp = start + group * EXT3_BLOCKS_PER_GROUP(as->sb) ++ + le32_to_cpu(es->s_first_data_block); ++ ++ /* account requests in order to limit searching */ ++ as->num++; ++ ++ if (as->num == 20) ++ return 1; ++ ++ /* if hit goal, then searching may complete right now */ ++ if (tmp == as->goal) { ++nice: ++ as->start = tmp; ++ as->len = len; ++ return 1; ++ } ++ ++ /* if found extent has lenght we need, return it right now */ ++ if (as->target_len == len) ++ goto nice; ++ ++ /* first, check is found extent better than we have in as */ ++ if (as->len > len) { ++better: ++ as->start = tmp; ++ as->len = len; ++ return 0; ++ } ++ ++ /* FIXME: more checks! */ ++ as->start = tmp; ++ as->len = len; ++ ++ /* 1) closeness to goal */ ++ ++ /* 2) extent lenght */ ++ /* 3) number of tested extent (we check all found extents) */ ++ /* */ ++ return 0; ++} ++ ++/* ++ * this routine tries to find upto *len free contig. blocks ++ * return number of found block (+ lenght of extent in *len) ++ * or -1 if no free blocks at all ++ */ ++int ext3_find_free_extent(struct buffer_head *bh, int goal, int *len, int max) ++{ ++ int i, l = 0; ++ ++repeat: ++ if (goal >= max) ++ return -1; ++ /* find first free block */ ++ i = ext3_find_next_zero_bit(bh->b_data, max, goal); ++ if (i >= max) { ++ /* no free block */ ++ return -1; ++ } ++ /* check upto len block for ability to be allocated */ ++ while (l < *len && i + l < max) { ++ if (!ext3_test_allocatable(i + l, bh)) ++ break; ++ l++; ++ } ++ if (l == 0) { ++ goal = i + 1; ++ goto repeat; ++ } ++ *len = l; ++ return i; ++} ++ ++/* ++ * this routine loops over group, finds free extents and tests them ++ * for some criterias ++ * it may return negative value if group can't be loaded, 0 - if ++ * no good extent can be found, 1 - if good extent found ++ */ ++int ext3_find_extent_in_group(struct alloc_status *as, int group, ++ unsigned long goal, int len) ++{ ++ int k, i, l, bitmap_nr, found = 0; ++ struct super_block *sb = as->sb; ++ int max = EXT3_BLOCKS_PER_GROUP(sb); ++ struct buffer_head *bh, *bmbh; ++ struct ext3_group_desc *gdp; ++ ++ mbdebug("look for %d blocks in group %d starting from %lu\n", ++ len, group, goal); ++ ++ gdp = ext3_get_group_desc(as->sb, group, &bh); ++ if (!gdp) ++ return -EIO; ++ ++ if (le16_to_cpu(gdp->bg_free_blocks_count) == 0) ++ return 0; ++ ++ bitmap_nr = load_block_bitmap(as->sb, group); ++ if (bitmap_nr < 0) ++ return -EIO; ++ ++ bmbh = EXT3_SB(sb)->s_block_bitmap[bitmap_nr]; ++ ++ i = goal; ++ /* scan from goal to the end */ ++repeat: ++ while (i < max) { ++ l = len; ++ k = ext3_find_free_extent(bmbh, i, &l, max); ++ i = k + l; ++ if (k < 0) ++ break; ++ if (ext3_test_extent(as, group, k, l)) { ++ found = 1; ++ goto out; ++ } ++ } ++ ++ if (goal) { ++ /* scan from 0 upto goal */ ++ mbdebug("repeat from %lu in %d\n", goal, group); ++ max = goal - 1; ++ goal = i = 0; ++ goto repeat; ++ } ++out: ++ return found; ++} ++ ++#define check_in_committed(bh,j) \ ++ J_ASSERT_BH((bh), !ext3_test_bit((j), bh2jh((bh))->b_committed_data)) ++ ++int ext3_new_blocks(handle_t *handle, struct inode *inode, int *num, ++ unsigned long goal, int *errp) ++{ ++ struct super_block *sb = inode->i_sb; ++ int first_group, group, bitmap_nr; ++ struct buffer_head *bh, *bmbh; ++ struct ext3_super_block *es; ++ struct ext3_group_desc *gdp; ++ struct alloc_status as; ++ int err, bit, i; ++ ++ int scaned = 0; ++ ++ J_ASSERT(num && *num > 0); ++ ++ if (DQUOT_ALLOC_BLOCK(inode, *num)) { ++ *errp = -EDQUOT; ++ return 0; ++ } ++ ++ es = EXT3_SB(inode->i_sb)->s_es; ++ ++ *errp = 0; ++ as.target_len = *num; ++ as.sb = sb; ++ as.goal = goal; ++ as.start = -1; ++ as.len = 0; ++ as.num = 0; ++ ++ lock_super(sb); ++ first_group = (goal - le32_to_cpu(es->s_first_data_block)) / ++ EXT3_BLOCKS_PER_GROUP(sb); ++ goal = (goal - le32_to_cpu(es->s_first_data_block)) % ++ EXT3_BLOCKS_PER_GROUP(sb); ++ group = first_group; ++ do { ++ scaned++; ++ err = ext3_find_extent_in_group(&as, group, goal, *num); ++ if (err < 0) ++ goto error_out; ++ else if (err) ++ break; ++ ++ /* reset goal for next groups */ ++ goal = 0; ++ ++ /* try next group */ ++ if (++group == EXT3_SB(sb)->s_groups_count) ++ group = 0; ++ } while (group != first_group); ++ ++ if (as.len == 0) { ++ err = -ENOSPC; ++ goto error_out; ++ } ++ ++ /* in the end we've found something, allocate it */ ++ mbdebug("best extent: %u:%u\n", as.start, as.len); ++ ++ group = (as.start - le32_to_cpu(es->s_first_data_block)) / ++ EXT3_BLOCKS_PER_GROUP(sb); ++ bit = (as.start - le32_to_cpu(es->s_first_data_block)) % ++ EXT3_BLOCKS_PER_GROUP(sb); ++ gdp = ext3_get_group_desc(sb, group, &bh); ++ if (!gdp) { ++ err = -EIO; ++ goto error_out; ++ } ++ ++ /* mark block(s) used in bitmap ... */ ++ bitmap_nr = load_block_bitmap(sb, group); ++ if (bitmap_nr < 0) { ++ err = -EIO; ++ goto error_out; ++ } ++ bmbh = EXT3_SB(sb)->s_block_bitmap[bitmap_nr]; ++ err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); ++ if (err) ++ goto error_out; ++ err = ext3_journal_get_write_access(handle, bmbh); ++ if (err) ++ goto error_out; ++ err = ext3_journal_get_write_access(handle, bh); ++ if (err) ++ goto error_out; ++ for (i = 0; i < as.len; i++) { ++ J_ASSERT(!ext3_test_bit(bit + i, bmbh->b_data)); ++ if (buffer_jbd(bmbh) && bh2jh(bmbh)->b_committed_data) ++ check_in_committed(bmbh, bit + i); ++ set_bit(bit + i, bmbh->b_data); ++ } ++ err = ext3_journal_dirty_metadata(handle, bmbh); ++ if (err) ++ goto error_out; ++ ++ /* ... and correct group descriptor */ ++ gdp->bg_free_blocks_count = ++ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - as.len); ++ es->s_free_blocks_count = ++ cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - as.len); ++ err = ext3_journal_dirty_metadata(handle, bmbh); ++ if (err) ++ goto error_out; ++ err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); ++ if (err) ++ goto error_out; ++ sb->s_dirt = 1; ++ ++ if (*num != as.len) ++ DQUOT_FREE_BLOCK(inode, *num - as.len); ++ *num = as.len; ++ ++out: ++ unlock_super(sb); ++ return as.start; ++ ++error_out: ++ as.start = 0; ++ *errp = err; ++ goto out; ++} ++ +Index: linux-2.4.24/fs/ext3/file.c +=================================================================== +--- linux-2.4.24.orig/fs/ext3/file.c 2004-01-12 20:36:32.000000000 +0300 ++++ linux-2.4.24/fs/ext3/file.c 2004-01-29 18:26:23.000000000 +0300 +@@ -69,6 +69,18 @@ + int err; + struct inode *inode = file->f_dentry->d_inode; + ++#if 0 ++ /* allocate all the space to be written */ ++ if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL) { ++ int blocksize = inode->i_sb->s_blocksize; ++ unsigned long start, end; ++ ++ start = (unsigned long) *ppos / blocksize; ++ end = ((unsigned long) *ppos + count + blocksize - 1) ++ / blocksize; ++ ext3_ext_allocate_nblocks(inode, start, end - start); ++ } ++#endif + ret = generic_file_write(file, buf, count, ppos); + + /* Skip file flushing code if there was an error, or if nothing +Index: linux-2.4.24/include/linux/ext3_fs.h +=================================================================== +--- linux-2.4.24.orig/include/linux/ext3_fs.h 2004-01-26 23:17:19.000000000 +0300 ++++ linux-2.4.24/include/linux/ext3_fs.h 2004-01-29 16:29:36.000000000 +0300 +@@ -58,6 +58,8 @@ + #define ext3_debug(f, a...) do {} while (0) + #endif + ++#define EXT3_MULTIBLOCK_ALLOCATOR 1 ++ + /* + * Special inodes numbers + */ +@@ -667,6 +669,7 @@ + extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); ++extern int ext3_new_blocks(handle_t*, struct inode*, int*, unsigned long, int*); + + /* dir.c */ + extern int ext3_check_dir_entry(const char *, struct inode *, -- 1.8.3.1