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-02-06 11:05:42.000000000 +0300 @@ -11,6 +11,7 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ +#include #include #include #include @@ -1007,3 +1008,303 @@ 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 inode *inode; + 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 length 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 length */ + /* 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 (+ length 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; + + 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.inode = inode; + as.goal = goal; + as.start = -1; + as.len = 0; + as.num = 0; + + if (goal < le32_to_cpu(es->s_first_data_block) || + goal >= le32_to_cpu(es->s_blocks_count)) + goal = le32_to_cpu(es->s_first_data_block); + + 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 { + 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]; + /* Make sure we use undo access for the bitmap, because it is + critical that we do the frozen_data COW on bitmap buffers in + all cases even if the buffer is in BJ_Forget state in the + committing transaction. */ + err = ext3_journal_get_undo_access(handle, bmbh); + if (err) + goto error_out; + err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); + 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; +} + +EXPORT_SYMBOL(ext3_new_blocks); + Index: linux-2.4.24/fs/ext3/file.c =================================================================== --- linux-2.4.24.orig/fs/ext3/file.c 2004-01-31 02:06:18.000000000 +0300 +++ linux-2.4.24/fs/ext3/file.c 2004-02-06 10:20:46.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/fs/ext3/Makefile =================================================================== --- linux-2.4.24.orig/fs/ext3/Makefile 2004-02-05 18:44:25.000000000 +0300 +++ linux-2.4.24/fs/ext3/Makefile 2004-02-06 10:20:46.000000000 +0300 @@ -14,7 +14,7 @@ obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \ ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o \ xattr_trusted.o extents.o -export-objs += extents.o +export-objs += extents.o balloc.o obj-m := $(O_TARGET) Index: linux-2.4.24/include/linux/ext3_fs.h =================================================================== --- linux-2.4.24.orig/include/linux/ext3_fs.h 2004-01-30 00:09:37.000000000 +0300 +++ linux-2.4.24/include/linux/ext3_fs.h 2004-02-06 10:20:46.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 *,