aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorKalpak Shah <kalpak@clusterfs.com>2007-07-18 09:19:57 -0400
committerTheodore Ts'o <tytso@mit.edu>2007-07-18 09:19:57 -0400
commit6dd4ee7cab7e3a17c571aebd444f4344c8c4946e (patch)
treeee7b36d3a83ea843746ed3c906a9ad778838b9c6 /fs/ext4/inode.c
parentef7f38359ea8b3e9c7f2cae9a4d4935f55ca9e80 (diff)
ext4: Expand extra_inodes space per the s_{want,min}_extra_isize fields
We need to make sure that existing ext3 filesystems can also avail the new fields that have been added to the ext4 inode. We use s_want_extra_isize and s_min_extra_isize to decide by how much we should expand the inode. If EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE feature is set then we expand the inode by max(s_want_extra_isize, s_min_extra_isize , sizeof(ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE) bytes. Actually it is still an open question about whether users should be able to set s_*_extra_isize smaller than the known fields or not. This patch also adds the functionality to expand inodes to include the newly added fields. We start by trying to expand by s_want_extra_isize bytes and if its fails we try to expand by s_min_extra_isize bytes. This is done by changing the i_extra_isize if enough space is available in the inode and no EAs are present. If EAs are present and there is enough space in the inode then the EAs in the inode are shifted to make space. If enough space is not available in the inode due to the EAs then 1 or more EAs are shifted to the external EA block. In the worst case when even the external EA block does not have enough space we inform the user that some EA would need to be deleted or s_min_extra_isize would have to be reduced. Signed-off-by: Andreas Dilger <adilger@clusterfs.com> Signed-off-by: Kalpak Shah <kalpak@clusterfs.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b83f91edebd1..f6d8528c4f55 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3106,6 +3106,39 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
3106} 3106}
3107 3107
3108/* 3108/*
3109 * Expand an inode by new_extra_isize bytes.
3110 * Returns 0 on success or negative error number on failure.
3111 */
3112int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
3113 struct ext4_iloc iloc, handle_t *handle)
3114{
3115 struct ext4_inode *raw_inode;
3116 struct ext4_xattr_ibody_header *header;
3117 struct ext4_xattr_entry *entry;
3118
3119 if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
3120 return 0;
3121
3122 raw_inode = ext4_raw_inode(&iloc);
3123
3124 header = IHDR(inode, raw_inode);
3125 entry = IFIRST(header);
3126
3127 /* No extended attributes present */
3128 if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
3129 header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
3130 memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
3131 new_extra_isize);
3132 EXT4_I(inode)->i_extra_isize = new_extra_isize;
3133 return 0;
3134 }
3135
3136 /* try to expand with EAs present */
3137 return ext4_expand_extra_isize_ea(inode, new_extra_isize,
3138 raw_inode, handle);
3139}
3140
3141/*
3109 * What we do here is to mark the in-core inode as clean with respect to inode 3142 * What we do here is to mark the in-core inode as clean with respect to inode
3110 * dirtiness (it may still be data-dirty). 3143 * dirtiness (it may still be data-dirty).
3111 * This means that the in-core inode may be reaped by prune_icache 3144 * This means that the in-core inode may be reaped by prune_icache
@@ -3129,10 +3162,38 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
3129int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) 3162int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
3130{ 3163{
3131 struct ext4_iloc iloc; 3164 struct ext4_iloc iloc;
3132 int err; 3165 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3166 static unsigned int mnt_count;
3167 int err, ret;
3133 3168
3134 might_sleep(); 3169 might_sleep();
3135 err = ext4_reserve_inode_write(handle, inode, &iloc); 3170 err = ext4_reserve_inode_write(handle, inode, &iloc);
3171 if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
3172 !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
3173 /*
3174 * We need extra buffer credits since we may write into EA block
3175 * with this same handle. If journal_extend fails, then it will
3176 * only result in a minor loss of functionality for that inode.
3177 * If this is felt to be critical, then e2fsck should be run to
3178 * force a large enough s_min_extra_isize.
3179 */
3180 if ((jbd2_journal_extend(handle,
3181 EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
3182 ret = ext4_expand_extra_isize(inode,
3183 sbi->s_want_extra_isize,
3184 iloc, handle);
3185 if (ret) {
3186 EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
3187 if (mnt_count != sbi->s_es->s_mnt_count) {
3188 ext4_warning(inode->i_sb, __FUNCTION__,
3189 "Unable to expand inode %lu. Delete"
3190 " some EAs or run e2fsck.",
3191 inode->i_ino);
3192 mnt_count = sbi->s_es->s_mnt_count;
3193 }
3194 }
3195 }
3196 }
3136 if (!err) 3197 if (!err)
3137 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 3198 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
3138 return err; 3199 return err;