Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 95030
b: refs/heads/master
c: 267e4db
h: refs/heads/master
v: v3
  • Loading branch information
Aneesh Kumar K.V authored and Theodore Ts'o committed Apr 29, 2008
1 parent 35981fe commit a63e001
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3977c965ec35ce1a7eac988ad313f0fc9aee9660
refs/heads/master: 267e4db9ac28a09973476e7ec2cb6807e609d35a
13 changes: 12 additions & 1 deletion trunk/fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,16 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
} else {
retval = ext4_get_blocks_handle(handle, inode, block,
max_blocks, bh, create, extend_disksize);

if (retval > 0 && buffer_new(bh)) {
/*
* We allocated new blocks which will result in
* i_data's format changing. Force the migrate
* to fail by clearing migrate flags
*/
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
~EXT4_EXT_MIGRATE;
}
}
up_write((&EXT4_I(inode)->i_data_sem));
return retval;
Expand Down Expand Up @@ -2976,7 +2986,8 @@ static int ext4_do_update_inode(handle_t *handle,
if (ext4_inode_blocks_set(handle, raw_inode, ei))
goto out_brelse;
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
raw_inode->i_flags = cpu_to_le32(ei->i_flags);
/* clear the migrate flag in the raw_inode */
raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE);
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
cpu_to_le32(EXT4_OS_HURD))
raw_inode->i_file_acl_high =
Expand Down
39 changes: 34 additions & 5 deletions trunk/fs/ext4/migrate.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
}

static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
struct inode *tmp_inode)
struct inode *tmp_inode)
{
int retval;
__le32 i_data[3];
Expand All @@ -339,7 +339,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
* i_data field of the original inode
*/
retval = ext4_journal_extend(handle, 1);
if (retval != 0) {
if (retval) {
retval = ext4_journal_restart(handle, 1);
if (retval)
goto err_out;
Expand All @@ -350,6 +350,18 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
i_data[2] = ei->i_data[EXT4_TIND_BLOCK];

down_write(&EXT4_I(inode)->i_data_sem);
/*
* if EXT4_EXT_MIGRATE is cleared a block allocation
* happened after we started the migrate. We need to
* fail the migrate
*/
if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) {
retval = -EAGAIN;
up_write(&EXT4_I(inode)->i_data_sem);
goto err_out;
} else
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
~EXT4_EXT_MIGRATE;
/*
* We have the extent map build with the tmp inode.
* Now copy the i_data across
Expand Down Expand Up @@ -508,6 +520,17 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp,
* switch the inode format to prevent read.
*/
mutex_lock(&(inode->i_mutex));
/*
* Even though we take i_mutex we can still cause block allocation
* via mmap write to holes. If we have allocated new blocks we fail
* migrate. New block allocation will clear EXT4_EXT_MIGRATE flag.
* The flag is updated with i_data_sem held to prevent racing with
* block allocation.
*/
down_read((&EXT4_I(inode)->i_data_sem));
EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE;
up_read((&EXT4_I(inode)->i_data_sem));

handle = ext4_journal_start(inode, 1);

ei = EXT4_I(inode);
Expand Down Expand Up @@ -559,9 +582,15 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp,
* tmp_inode
*/
free_ext_block(handle, tmp_inode);
else
retval = ext4_ext_swap_inode_data(handle, inode,
tmp_inode);
else {
retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
if (retval)
/*
* if we fail to swap inode data free the extent
* details of the tmp inode
*/
free_ext_block(handle, tmp_inode);
}

/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
if (ext4_journal_extend(handle, 1) != 0)
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/ext4_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ struct ext4_group_desc
#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
#define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */
#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */

#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
Expand Down

0 comments on commit a63e001

Please sign in to comment.