From 1f374d8cc10fd9932359bf5928ed04bdbeca97b1 Mon Sep 17 00:00:00 2001 From: Mingming Cao Date: Sun, 3 Apr 2005 17:39:16 -0700 Subject: [PATCH] ext3: dynamic allocation of block reservation info Right now the ext3 reservation structure(ext3_reserve_window_node) is part of the ext3 inode itself. This part of information is only needed for files that need allocate blocks on disk. So, the attached patches reduce the ext3 inode size by dynamically allocating the block allocation/reservation info structure(called struct ext3_block_alloc_info) when it is needed(i.e. only for files who need to allocate blocks) The reservation structure is being allocated and linked to the ext3 inode at ext3_get_block_handle(), and being freed and unlinked at the iput_final->ext3_clear_inode(). The ei->truncate_sem which is currently used to protect concurrent ext3_get_block() and ext3_truncate is used to protect reservation structure allocation and deallocation. Signed-off-by: Mingming Cao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/balloc.c | 34 ++++++++++++++++++++++++++++------ fs/ext3/ialloc.c | 6 +----- fs/ext3/inode.c | 19 ++++++++++++------- fs/ext3/ioctl.c | 24 ++++++++++++++++++++---- fs/ext3/super.c | 5 ++++- include/linux/ext3_fs.h | 1 + include/linux/ext3_fs_i.h | 4 ++-- 7 files changed, 68 insertions(+), 25 deletions(-) diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 6a18447e9dd7f..27f57532cea72 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -259,14 +259,29 @@ static inline int rsv_is_empty(struct ext3_reserve_window *rsv) /* 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) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + struct ext3_reserve_window_node *rsv = ei->i_rsv_window; + + rsv = kmalloc(sizeof(*rsv), GFP_NOFS); + if (rsv) { + rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + atomic_set(&rsv->rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); + atomic_set(&rsv->rsv_alloc_hit, 0); + seqlock_init(&rsv->rsv_seqlock); + } + ei->i_rsv_window = rsv; +} 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_reserve_window_node *rsv = ei->i_rsv_window; spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; - if (!rsv_is_empty(&rsv->rsv_window)) { + if (rsv && !rsv_is_empty(&rsv->rsv_window)) { spin_lock(rsv_lock); if (!rsv_is_empty(&rsv->rsv_window)) rsv_window_remove(inode->i_sb, rsv); @@ -1154,7 +1169,7 @@ int ext3_new_block(handle_t *handle, struct inode *inode, 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_reserve_window_node *rsv = EXT3_I(inode)->i_rsv_window; unsigned short windowsz = 0; #ifdef EXT3FS_DEBUG static int goal_hits, goal_attempts; @@ -1187,10 +1202,9 @@ int ext3_new_block(handle_t *handle, struct inode *inode, * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off * reservation on that particular file) */ - windowsz = atomic_read(&rsv->rsv_goal_size); - if (test_opt(sb, RESERVATION) && - S_ISREG(inode->i_mode) && (windowsz > 0)) + if (rsv && ((windowsz = atomic_read(&rsv->rsv_goal_size)) > 0)) my_rsv = rsv; + if (!ext3_has_free_blocks(sbi)) { *errp = -ENOSPC; goto out; @@ -1211,6 +1225,14 @@ int ext3_new_block(handle_t *handle, struct inode *inode, goal_group = group_no; retry: free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + /* + * if there is not enough free blocks to make a new resevation + * turn off reservation for this allocation + */ + if (my_rsv && (free_blocks < windowsz) + && (rsv_is_empty(&my_rsv->rsv_window))) + my_rsv = NULL; + if (free_blocks > 0) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb)); diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 121ecbe1039e8..bf2cb4e7ff4d3 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c @@ -581,11 +581,7 @@ got: ei->i_file_acl = 0; ei->i_dir_acl = 0; ei->i_dtime = 0; - ei->i_rsv_window.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); - atomic_set(&ei->i_rsv_window.rsv_alloc_hit, 0); - seqlock_init(&ei->i_rsv_window.rsv_seqlock); + ei->i_rsv_window = NULL; ei->i_block_group = group; ext3_set_inode_flags(inode); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 05be496c892f1..55531ed7ea499 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -708,6 +708,7 @@ ext3_get_block_handle(handle_t *handle, struct inode *inode, sector_t iblock, 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); @@ -752,6 +753,13 @@ out: goal = 0; 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 (ext3_find_goal(inode, iblock, chain, partial, &goal) < 0) { up(&ei->truncate_sem); goto changed; @@ -2149,8 +2157,6 @@ void ext3_truncate(struct inode * inode) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - ext3_discard_reservation(inode); - /* * We have to lock the EOF page here, because lock_page() nests * outside journal_start(). @@ -2275,6 +2281,9 @@ do_indirects: case EXT3_TIND_BLOCK: ; } + + ext3_discard_reservation(inode); + up(&ei->truncate_sem); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; ext3_mark_inode_dirty(handle, inode); @@ -2494,7 +2503,7 @@ void ext3_read_inode(struct inode * inode) ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif - ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + ei->i_rsv_window = NULL; if (__ext3_get_inode_loc(inode, &iloc, 0)) goto bad_inode; @@ -2556,10 +2565,6 @@ void ext3_read_inode(struct inode * inode) ei->i_disksize = inode->i_size; inode->i_generation = le32_to_cpu(raw_inode->i_generation); ei->i_block_group = iloc.block_group; - ei->i_rsv_window.rsv_start = 0; - ei->i_rsv_window.rsv_end= 0; - atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS); - seqlock_init(&ei->i_rsv_window.rsv_seqlock); /* * NOTE! The in-memory inode i_data array is in little-endian order * even on big-endian machines: we do NOT byteswap the block numbers! diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index f594e54b95386..34f83dff66dca 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -153,12 +153,15 @@ flags_err: } #endif case EXT3_IOC_GETRSVSZ: - if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) { - rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size); + if (test_opt(inode->i_sb, RESERVATION) + && S_ISREG(inode->i_mode) + && ei->i_rsv_window) { + rsv_window_size = atomic_read(&ei->i_rsv_window->rsv_goal_size); return put_user(rsv_window_size, (int __user *)arg); } return -ENOTTY; - case EXT3_IOC_SETRSVSZ: + case EXT3_IOC_SETRSVSZ: { + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; @@ -173,8 +176,21 @@ flags_err: if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; - atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size); + + /* + * need to allocate reservation structure for this inode + * before set the window size + */ + down(&ei->truncate_sem); + if (!ei->i_rsv_window) + ext3_alloc_init_reservation(inode); + + if (ei->i_rsv_window) + atomic_set(&ei->i_rsv_window->rsv_goal_size, + rsv_window_size); + up(&ei->truncate_sem); return 0; + } case EXT3_IOC_GROUP_EXTEND: { unsigned long n_blocks_count; struct super_block *sb = inode->i_sb; diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 34288e100d957..69a028dd23dc0 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -441,7 +441,7 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) ei->i_acl = EXT3_ACL_NOT_CACHED; ei->i_default_acl = EXT3_ACL_NOT_CACHED; #endif - ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; + ei->i_rsv_window = NULL; ei->vfs_inode.i_version = 1; return &ei->vfs_inode; } @@ -485,6 +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; #ifdef CONFIG_EXT3_FS_POSIX_ACL if (EXT3_I(inode)->i_acl && EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { @@ -498,6 +499,8 @@ static void ext3_clear_inode(struct inode *inode) } #endif ext3_discard_reservation(inode); + EXT3_I(inode)->i_rsv_window = NULL; + kfree(rsv); } #ifdef CONFIG_QUOTA diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 4d478d8b2d069..45d15e5f8a043 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -725,6 +725,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_should_retry_alloc(struct super_block *sb, int *retries); +extern void ext3_alloc_init_reservation(struct inode *); extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv); /* dir.c */ diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h index 5e781aaff4044..f72b7a99438e2 100644 --- a/include/linux/ext3_fs_i.h +++ b/include/linux/ext3_fs_i.h @@ -75,8 +75,8 @@ struct ext3_inode_info { * allocation when we detect linearly ascending requests. */ __u32 i_next_alloc_goal; - /* block reservation window */ - struct ext3_reserve_window_node i_rsv_window; + /* block reservation info */ + struct ext3_reserve_window_node *i_rsv_window; __u32 i_dir_start_lookup; #ifdef CONFIG_EXT3_FS_XATTR -- cgit 1.2.3-korg