From: Mingming Cao Moved i_next_alloc_block and i_next_goal_block out from ext3_inod_info, and put it together with the reservation structure into the ext3_block_alloc_info structure, and dynamically allocate that structure whenever need to allocation a block. This is also apply for noreservation mount. Also cleanup ext3_find_goal() code. Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton --- 25-akpm/fs/ext3/balloc.c | 42 +++++++++++++++++++++-------- 25-akpm/fs/ext3/ialloc.c | 4 -- 25-akpm/fs/ext3/inode.c | 54 ++++++++++++++++++-------------------- 25-akpm/fs/ext3/ioctl.c | 14 +++++---- 25-akpm/fs/ext3/super.c | 6 ++-- 25-akpm/include/linux/ext3_fs.h | 2 - 25-akpm/include/linux/ext3_fs_i.h | 36 ++++++++++++++----------- 7 files changed, 91 insertions(+), 67 deletions(-) diff -puN fs/ext3/balloc.c~ext3-move-goal-logical-block-into-block-allocation-info fs/ext3/balloc.c --- 25/fs/ext3/balloc.c~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/fs/ext3/balloc.c 2005-03-23 01:33:53.000000000 -0800 @@ -259,28 +259,47 @@ static inline int rsv_is_empty(struct ex /* a valid reservation end block could not be 0 */ return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED); } -void ext3_alloc_init_reservation(struct inode *inode) +void ext3_init_block_alloc_info(struct inode *inode) { struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_reserve_window_node *rsv = ei->i_rsv_window; + struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; + struct super_block *sb = inode->i_sb; + + block_i = kmalloc(sizeof(*block_i), GFP_NOFS); + if (block_i) { + struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node; - rsv = kmalloc(sizeof(*rsv), GFP_NOFS); - if (rsv) { rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS; + + /* + * if filesystem is mounted with NORESERVATION, the goal + * reservation window size is set to zero to indicate + * block reservation is off + */ + if (!test_opt(sb, RESERVATION)) + rsv->rsv_goal_size = 0; + else + rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS; rsv->rsv_alloc_hit = 0; + block_i->last_alloc_logical_block = 0; + block_i->last_alloc_physical_block = 0; } - ei->i_rsv_window = rsv; + ei->i_block_alloc_info = block_i; } void ext3_discard_reservation(struct inode *inode) { struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_reserve_window_node *rsv = ei->i_rsv_window; + struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; + struct ext3_reserve_window_node *rsv; spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; - if (rsv && !rsv_is_empty(&rsv->rsv_window)) { + if (!block_i) + return; + + rsv = &block_i->rsv_window_node; + if (!rsv_is_empty(&rsv->rsv_window)) { spin_lock(rsv_lock); if (!rsv_is_empty(&rsv->rsv_window)) rsv_window_remove(inode->i_sb, rsv); @@ -1161,7 +1180,7 @@ int ext3_new_block(handle_t *handle, str struct ext3_super_block *es; struct ext3_sb_info *sbi; struct ext3_reserve_window_node *my_rsv = NULL; - struct ext3_reserve_window_node *rsv = EXT3_I(inode)->i_rsv_window; + struct ext3_block_alloc_info *block_i; unsigned short windowsz = 0; #ifdef EXT3FS_DEBUG static int goal_hits, goal_attempts; @@ -1194,8 +1213,9 @@ int ext3_new_block(handle_t *handle, str * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off * reservation on that particular file) */ - if (rsv && ((windowsz = rsv->rsv_goal_size) > 0)) - my_rsv = rsv; + block_i = EXT3_I(inode)->i_block_alloc_info; + if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) + my_rsv = &block_i->rsv_window_node; if (!ext3_has_free_blocks(sbi)) { *errp = -ENOSPC; diff -puN fs/ext3/ialloc.c~ext3-move-goal-logical-block-into-block-allocation-info fs/ext3/ialloc.c --- 25/fs/ext3/ialloc.c~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/fs/ext3/ialloc.c 2005-03-23 01:33:53.000000000 -0800 @@ -562,8 +562,6 @@ got: inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_next_alloc_block = 0; - ei->i_next_alloc_goal = 0; ei->i_dir_start_lookup = 0; ei->i_disksize = 0; @@ -581,7 +579,7 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; - ei->i_rsv_window = NULL; + ei->i_block_alloc_info = NULL; ei->i_block_group = group; ext3_set_inode_flags(inode); diff -puN fs/ext3/inode.c~ext3-move-goal-logical-block-into-block-allocation-info fs/ext3/inode.c --- 25/fs/ext3/inode.c~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/fs/ext3/inode.c 2005-03-23 01:33:53.000000000 -0800 @@ -462,26 +462,22 @@ static unsigned long ext3_find_near(stru static int ext3_find_goal(struct inode *inode, long block, Indirect chain[4], Indirect *partial, unsigned long *goal) { - struct ext3_inode_info *ei = EXT3_I(inode); - /* Writer: ->i_next_alloc* */ - if ((block == ei->i_next_alloc_block + 1)&& ei->i_next_alloc_goal) { - ei->i_next_alloc_block++; - ei->i_next_alloc_goal++; + struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info; + + /* + * try the heuristic for sequential allocation, + * failing that at least try to get decent locality. + */ + if (block_i && (block == block_i->last_alloc_logical_block + 1) + && (block_i->last_alloc_physical_block != 0)) { + *goal = block_i->last_alloc_physical_block + 1; + return 0; } - /* Writer: end */ - /* Reader: pointers, ->i_next_alloc* */ + if (verify_chain(chain, partial)) { - /* - * try the heuristic for sequential allocation, - * failing that at least try to get decent locality. - */ - if (block == ei->i_next_alloc_block) - *goal = ei->i_next_alloc_goal; - if (!*goal) - *goal = ext3_find_near(inode, partial); + *goal = ext3_find_near(inode, partial); return 0; } - /* Reader: end */ return -EAGAIN; } @@ -599,7 +595,7 @@ static int ext3_splice_branch(handle_t * { int i; int err = 0; - struct ext3_inode_info *ei = EXT3_I(inode); + struct ext3_block_alloc_info *block_i = EXT3_I(inode)->i_block_alloc_info; /* * If we're splicing into a [td]indirect block (as opposed to the @@ -614,7 +610,6 @@ static int ext3_splice_branch(handle_t * } /* Verify that place we are splicing to is still there and vacant */ - /* Writer: pointers, ->i_next_alloc* */ if (!verify_chain(chain, where-1) || *where->p) /* Writer: end */ goto changed; @@ -622,9 +617,16 @@ static int ext3_splice_branch(handle_t * /* That's it */ *where->p = where->key; - ei->i_next_alloc_block = block; - ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key); - /* Writer: end */ + + /* + * update the most recently allocated logical & physical block + * in i_block_alloc_info, to assist find the proper goal block for next + * allocation + */ + if (block_i) { + block_i->last_alloc_logical_block = block; + block_i->last_alloc_physical_block = le32_to_cpu(where[num-1].key); + } /* We are done with atomic stuff, now do the rest of housekeeping */ @@ -708,7 +710,6 @@ ext3_get_block_handle(handle_t *handle, int boundary = 0; int depth = ext3_block_to_path(inode, iblock, offsets, &boundary); struct ext3_inode_info *ei = EXT3_I(inode); - struct super_block *sb = inode->i_sb; J_ASSERT(handle != NULL || create == 0); @@ -755,9 +756,8 @@ out: down(&ei->truncate_sem); /* lazy initialize the block allocation info here if necessary */ - if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode) - && (!ei->i_rsv_window)) { - ext3_alloc_init_reservation(inode); + if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) { + ext3_init_block_alloc_info(inode); } if (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) { @@ -2503,7 +2503,7 @@ void ext3_read_inode(struct inode * inod ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif - ei->i_rsv_window = NULL; + ei->i_block_alloc_info = NULL; if (__ext3_get_inode_loc(inode, &iloc, 0)) goto bad_inode; @@ -2524,8 +2524,6 @@ void ext3_read_inode(struct inode * inod inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; ei->i_state = 0; - ei->i_next_alloc_block = 0; - ei->i_next_alloc_goal = 0; ei->i_dir_start_lookup = 0; ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); /* We now have enough fields to check if the inode was active or not. diff -puN fs/ext3/ioctl.c~ext3-move-goal-logical-block-into-block-allocation-info fs/ext3/ioctl.c --- 25/fs/ext3/ioctl.c~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/fs/ext3/ioctl.c 2005-03-23 01:33:53.000000000 -0800 @@ -155,8 +155,8 @@ flags_err: case EXT3_IOC_GETRSVSZ: if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode) - && ei->i_rsv_window) { - rsv_window_size = ei->i_rsv_window->rsv_goal_size; + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; return put_user(rsv_window_size, (int __user *)arg); } return -ENOTTY; @@ -182,11 +182,13 @@ flags_err: * before set the window size */ down(&ei->truncate_sem); - if (!ei->i_rsv_window) - ext3_alloc_init_reservation(inode); + if (!ei->i_block_alloc_info) + ext3_init_block_alloc_info(inode); - if (ei->i_rsv_window) - ei->i_rsv_window->rsv_goal_size = rsv_window_size; + if (ei->i_block_alloc_info){ + struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; + rsv->rsv_goal_size = rsv_window_size; + } up(&ei->truncate_sem); return 0; } diff -puN fs/ext3/super.c~ext3-move-goal-logical-block-into-block-allocation-info fs/ext3/super.c --- 25/fs/ext3/super.c~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/fs/ext3/super.c 2005-03-23 01:33:53.000000000 -0800 @@ -441,7 +441,7 @@ static struct inode *ext3_alloc_inode(st ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif - ei->i_rsv_window = NULL; + ei->i_block_alloc_info = NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode; } @@ -485,7 +485,7 @@ static void destroy_inodecache(void) static void ext3_clear_inode(struct inode *inode) { - struct ext3_reserve_window_node *rsv = EXT3_I(inode)->i_rsv_window; + struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; #ifdef CONFIG_EXT3_FS_POSIX_ACL if (EXT3_I(inode)->i_acl && EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { @@ -499,7 +499,7 @@ static void ext3_clear_inode(struct inod } #endif ext3_discard_reservation(inode); - EXT3_I(inode)->i_rsv_window = NULL; + EXT3_I(inode)->i_block_alloc_info = NULL; kfree(rsv); } diff -puN include/linux/ext3_fs.h~ext3-move-goal-logical-block-into-block-allocation-info include/linux/ext3_fs.h --- 25/include/linux/ext3_fs.h~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/include/linux/ext3_fs.h 2005-03-23 01:33:53.000000000 -0800 @@ -725,7 +725,7 @@ extern struct ext3_group_desc * ext3_get unsigned int block_group, struct buffer_head ** bh); extern int ext3_should_retry_alloc(struct super_block *sb, int *retries); -extern void ext3_alloc_init_reservation(struct inode *); +extern void ext3_init_block_alloc_info(struct inode *); extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv); /* dir.c */ diff -puN include/linux/ext3_fs_i.h~ext3-move-goal-logical-block-into-block-allocation-info include/linux/ext3_fs_i.h --- 25/include/linux/ext3_fs_i.h~ext3-move-goal-logical-block-into-block-allocation-info 2005-03-23 01:33:53.000000000 -0800 +++ 25-akpm/include/linux/ext3_fs_i.h 2005-03-23 01:33:53.000000000 -0800 @@ -32,6 +32,26 @@ struct ext3_reserve_window_node { struct ext3_reserve_window rsv_window; }; +struct ext3_block_alloc_info { + /* information about reservation window */ + struct ext3_reserve_window_node rsv_window_node; + /* + * was i_next_alloc_block in ext3_inode_info + * is the logical (file-relative) number of the + * most-recently-allocated block in this file. + * We use this for detecting linearly ascending allocation requests. + */ + __u32 last_alloc_logical_block; + /* + * Was i_next_alloc_goal in ext3_inode_info + * is the *physical* companion to i_next_alloc_block. + * it the the physical block number of the block which was most-recentl + * allocated to this file. This give us the goal (target) for the next + * allocation when we detect linearly ascending requests. + */ + __u32 last_alloc_physical_block; +}; + #define rsv_start rsv_window._rsv_start #define rsv_end rsv_window._rsv_end @@ -60,22 +80,8 @@ struct ext3_inode_info { __u32 i_block_group; __u32 i_state; /* Dynamic state flags for ext3 */ - /* - * i_next_alloc_block is the logical (file-relative) number of the - * most-recently-allocated block in this file. Yes, it is misnamed. - * We use this for detecting linearly ascending allocation requests. - */ - __u32 i_next_alloc_block; - - /* - * i_next_alloc_goal is the *physical* companion to i_next_alloc_block. - * it the the physical block number of the block which was most-recently - * allocated to this file. This give us the goal (target) for the next - * allocation when we detect linearly ascending requests. - */ - __u32 i_next_alloc_goal; /* block reservation info */ - struct ext3_reserve_window_node *i_rsv_window; + struct ext3_block_alloc_info *i_block_alloc_info; __u32 i_dir_start_lookup; #ifdef CONFIG_EXT3_FS_XATTR _