aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMingming Cao <cmm@us.ibm.com>2005-04-03 17:39:16 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-03 17:39:16 -0700
commit1f374d8cc10fd9932359bf5928ed04bdbeca97b1 (patch)
tree4d2dd97da5af8989d150f76a98fff2e3203945bb
parentd0091e60a7e122b3e70658bf6e1148a389f71e90 (diff)
downloadhistory-1f374d8cc10fd9932359bf5928ed04bdbeca97b1.tar.gz
[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 <cmm@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/ext3/balloc.c34
-rw-r--r--fs/ext3/ialloc.c6
-rw-r--r--fs/ext3/inode.c19
-rw-r--r--fs/ext3/ioctl.c24
-rw-r--r--fs/ext3/super.c5
-rw-r--r--include/linux/ext3_fs.h1
-rw-r--r--include/linux/ext3_fs_i.h4
7 files changed, 68 insertions, 25 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 6a18447e9dd7fc..27f57532cea728 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 121ecbe1039e85..bf2cb4e7ff4d3f 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 05be496c892f17..55531ed7ea4996 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 f594e54b953869..34f83dff66dcaa 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 34288e100d957f..69a028dd23dc0e 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 4d478d8b2d0697..45d15e5f8a0432 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 5e781aaff40444..f72b7a99438e20 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