Skip to content

Commit

Permalink
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/tytso/ext4

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: add missing ext4_journal_stop()
  ext4: ext4_find_next_zero_bit needs an aligned address on some arch
  ext4: set EXT4_EXTENTS_FL only for directory and regular files
  ext4: Don't mark filesystem error if fallocate fails
  ext4: Fix BUG when writing to an unitialized extent
  ext4: Don't use ext4_dec_count() if not needed
  ext4: modify block allocation algorithm for the last group
  ext4: Don't claim block from group which has corrupt bitmap
  ext4: Get journal write access before modifying the extent tree
  ext4: Fix memory and buffer head leak in callers to ext4_ext_find_extent()
  ext4: Don't leave behind a half-created inode if ext4_mkdir() fails
  ext4: Fix kernel BUG at fs/ext4/mballoc.c:910!
  ext4: Fix locking hierarchy violation in ext4_fallocate()
  Remove incorrect BKL comments in ext4
  • Loading branch information
Linus Torvalds committed Feb 26, 2008
2 parents 3d6ce33 + 5606bf5 commit adefe11
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 67 deletions.
2 changes: 1 addition & 1 deletion fs/ext4/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const struct file_operations ext4_dir_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
.fsync = ext4_sync_file, /* BKL held */
.fsync = ext4_sync_file,
.release = ext4_release_dir,
};

Expand Down
59 changes: 40 additions & 19 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
{
struct ext4_inode_info *ei = EXT4_I(inode);
ext4_fsblk_t bg_start;
ext4_fsblk_t last_block;
ext4_grpblk_t colour;
int depth;

Expand All @@ -169,8 +170,13 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
/* OK. use inode's group */
bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
colour = (current->pid % 16) *
last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;

if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
else
colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour + block;
}

Expand Down Expand Up @@ -349,7 +355,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
#define ext4_ext_show_leaf(inode,path)
#endif

static void ext4_ext_drop_refs(struct ext4_ext_path *path)
void ext4_ext_drop_refs(struct ext4_ext_path *path)
{
int depth = path->p_depth;
int i;
Expand Down Expand Up @@ -2168,6 +2174,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
newblock = iblock - ee_block + ext_pblock(ex);
ex2 = ex;

err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;

/* ex1: ee_block to iblock - 1 : uninitialized */
if (iblock > ee_block) {
ex1 = ex;
Expand Down Expand Up @@ -2200,16 +2210,20 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
newdepth = ext_depth(inode);
if (newdepth != depth) {
depth = newdepth;
path = ext4_ext_find_extent(inode, iblock, NULL);
ext4_ext_drop_refs(path);
path = ext4_ext_find_extent(inode, iblock, path);
if (IS_ERR(path)) {
err = PTR_ERR(path);
path = NULL;
goto out;
}
eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (ex2 != &newex)
ex2 = ex;

err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;
}
allocated = max_blocks;
}
Expand All @@ -2230,9 +2244,6 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex2->ee_len = cpu_to_le16(allocated);
if (ex2 != ex)
goto insert;
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;
/*
* New (initialized) extent starts from the first block
* in the current extent. i.e., ex2 == ex
Expand Down Expand Up @@ -2276,9 +2287,22 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
}

/*
* Block allocation/map/preallocation routine for extents based files
*
*
* Need to be called with
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
*
* return > 0, number of of blocks already mapped/allocated
* if create == 0 and these are pre-allocated blocks
* buffer head is unmapped
* otherwise blocks are mapped
*
* return = 0, if plain look up failed (blocks have not been allocated)
* buffer head is unmapped
*
* return < 0, error case.
*/
int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock,
Expand Down Expand Up @@ -2623,7 +2647,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
* modify 1 super block, 1 block bitmap and 1 group descriptor.
*/
credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
down_write((&EXT4_I(inode)->i_data_sem));
mutex_lock(&inode->i_mutex);
retry:
while (ret >= 0 && ret < max_blocks) {
block = block + ret;
Expand All @@ -2634,16 +2658,17 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
break;
}

ret = ext4_ext_get_blocks(handle, inode, block,
ret = ext4_get_blocks_wrap(handle, inode, block,
max_blocks, &map_bh,
EXT4_CREATE_UNINITIALIZED_EXT, 0);
WARN_ON(ret <= 0);
if (ret <= 0) {
ext4_error(inode->i_sb, "ext4_fallocate",
"ext4_ext_get_blocks returned error: "
"inode#%lu, block=%u, max_blocks=%lu",
#ifdef EXT4FS_DEBUG
WARN_ON(ret <= 0);
printk(KERN_ERR "%s: ext4_ext_get_blocks "
"returned error inode#%lu, block=%u, "
"max_blocks=%lu", __func__,
inode->i_ino, block, max_blocks);
ret = -EIO;
#endif
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
break;
Expand Down Expand Up @@ -2680,7 +2705,6 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;

up_write((&EXT4_I(inode)->i_data_sem));
/*
* Time to update the file size.
* Update only when preallocation was requested beyond the file size.
Expand All @@ -2692,21 +2716,18 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
* if no error, we assume preallocation succeeded
* completely
*/
mutex_lock(&inode->i_mutex);
i_size_write(inode, offset + len);
EXT4_I(inode)->i_disksize = i_size_read(inode);
mutex_unlock(&inode->i_mutex);
} else if (ret < 0 && nblocks) {
/* Handle partial allocation scenario */
loff_t newsize;

mutex_lock(&inode->i_mutex);
newsize = (nblocks << blkbits) + i_size_read(inode);
i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
EXT4_I(inode)->i_disksize = i_size_read(inode);
mutex_unlock(&inode->i_mutex);
}
}

mutex_unlock(&inode->i_mutex);
return ret > 0 ? ret2 : ret;
}
22 changes: 15 additions & 7 deletions fs/ext4/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,12 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
ei->i_dir_start_lookup = 0;
ei->i_disksize = 0;

ei->i_flags = EXT4_I(dir)->i_flags & ~EXT4_INDEX_FL;
/*
* Don't inherit extent flag from directory. We set extent flag on
* newly created directory and file only if -o extent mount option is
* specified
*/
ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL);
if (S_ISLNK(mode))
ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
/* dirsync only applies to directories */
Expand Down Expand Up @@ -745,12 +750,15 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
goto fail_free_drop;
}
if (test_opt(sb, EXTENTS)) {
EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
ext4_ext_tree_init(handle, inode);
err = ext4_update_incompat_feature(handle, sb,
EXT4_FEATURE_INCOMPAT_EXTENTS);
if (err)
goto fail;
/* set extent flag only for directory and file */
if (S_ISDIR(mode) || S_ISREG(mode)) {
EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
ext4_ext_tree_init(handle, inode);
err = ext4_update_incompat_feature(handle, sb,
EXT4_FEATURE_INCOMPAT_EXTENTS);
if (err)
goto fail;
}
}

ext4_debug("allocating inode %lu\n", inode->i_ino);
Expand Down
56 changes: 51 additions & 5 deletions fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
__le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
__le32 *p;
ext4_fsblk_t bg_start;
ext4_fsblk_t last_block;
ext4_grpblk_t colour;

/* Try to find previous block */
Expand All @@ -420,8 +421,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
* into the same cylinder group then.
*/
bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
colour = (current->pid % 16) *
last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;

if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
else
colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour;
}

Expand Down Expand Up @@ -768,7 +774,6 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
*
* `handle' can be NULL if create == 0.
*
* The BKL may not be held on entry here. Be sure to take it early.
* return > 0, # of blocks mapped or allocated.
* return = 0, if plain lookup failed.
* return < 0, error case.
Expand Down Expand Up @@ -903,11 +908,38 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
*/
#define DIO_CREDITS 25


/*
*
*
* ext4_ext4 get_block() wrapper function
* It will do a look up first, and returns if the blocks already mapped.
* Otherwise it takes the write lock of the i_data_sem and allocate blocks
* and store the allocated blocks in the result buffer head and mark it
* mapped.
*
* If file type is extents based, it will call ext4_ext_get_blocks(),
* Otherwise, call with ext4_get_blocks_handle() to handle indirect mapping
* based files
*
* On success, it returns the number of blocks being mapped or allocate.
* if create==0 and the blocks are pre-allocated and uninitialized block,
* the result buffer head is unmapped. If the create ==1, it will make sure
* the buffer head is mapped.
*
* It returns 0 if plain look up failed (blocks have not been allocated), in
* that casem, buffer head is unmapped
*
* It returns the error in case of allocation failure.
*/
int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
int create, int extend_disksize)
{
int retval;

clear_buffer_mapped(bh);

/*
* Try to see if we can get the block without requesting
* for new file system block.
Expand All @@ -921,12 +953,26 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
inode, block, max_blocks, bh, 0, 0);
}
up_read((&EXT4_I(inode)->i_data_sem));
if (!create || (retval > 0))

/* If it is only a block(s) look up */
if (!create)
return retval;

/*
* Returns if the blocks have already allocated
*
* Note that if blocks have been preallocated
* ext4_ext_get_block() returns th create = 0
* with buffer head unmapped.
*/
if (retval > 0 && buffer_mapped(bh))
return retval;

/*
* We need to allocate new blocks which will result
* in i_data update
* New blocks allocate and/or writing to uninitialized extent
* will possibly result in updating i_data, so we take
* the write lock of i_data_sem, and call get_blocks()
* with create == 1 flag.
*/
down_write((&EXT4_I(inode)->i_data_sem));
/*
Expand Down
Loading

0 comments on commit adefe11

Please sign in to comment.