diff options
Diffstat (limited to 'fs/ext4/migrate.c')
-rw-r--r-- | fs/ext4/migrate.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index 5c1e27de7755..b9e077ba07e9 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -13,8 +13,8 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/ext4_jbd2.h> | 16 | #include "ext4_jbd2.h" |
17 | #include <linux/ext4_fs_extents.h> | 17 | #include "ext4_extents.h" |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * The contiguous blocks details which can be | 20 | * The contiguous blocks details which can be |
@@ -327,7 +327,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) | |||
327 | } | 327 | } |
328 | 328 | ||
329 | static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, | 329 | static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, |
330 | struct inode *tmp_inode) | 330 | struct inode *tmp_inode) |
331 | { | 331 | { |
332 | int retval; | 332 | int retval; |
333 | __le32 i_data[3]; | 333 | __le32 i_data[3]; |
@@ -339,7 +339,7 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, | |||
339 | * i_data field of the original inode | 339 | * i_data field of the original inode |
340 | */ | 340 | */ |
341 | retval = ext4_journal_extend(handle, 1); | 341 | retval = ext4_journal_extend(handle, 1); |
342 | if (retval != 0) { | 342 | if (retval) { |
343 | retval = ext4_journal_restart(handle, 1); | 343 | retval = ext4_journal_restart(handle, 1); |
344 | if (retval) | 344 | if (retval) |
345 | goto err_out; | 345 | goto err_out; |
@@ -351,6 +351,18 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, | |||
351 | 351 | ||
352 | down_write(&EXT4_I(inode)->i_data_sem); | 352 | down_write(&EXT4_I(inode)->i_data_sem); |
353 | /* | 353 | /* |
354 | * if EXT4_EXT_MIGRATE is cleared a block allocation | ||
355 | * happened after we started the migrate. We need to | ||
356 | * fail the migrate | ||
357 | */ | ||
358 | if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) { | ||
359 | retval = -EAGAIN; | ||
360 | up_write(&EXT4_I(inode)->i_data_sem); | ||
361 | goto err_out; | ||
362 | } else | ||
363 | EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags & | ||
364 | ~EXT4_EXT_MIGRATE; | ||
365 | /* | ||
354 | * We have the extent map build with the tmp inode. | 366 | * We have the extent map build with the tmp inode. |
355 | * Now copy the i_data across | 367 | * Now copy the i_data across |
356 | */ | 368 | */ |
@@ -508,6 +520,17 @@ int ext4_ext_migrate(struct inode *inode, struct file *filp, | |||
508 | * switch the inode format to prevent read. | 520 | * switch the inode format to prevent read. |
509 | */ | 521 | */ |
510 | mutex_lock(&(inode->i_mutex)); | 522 | mutex_lock(&(inode->i_mutex)); |
523 | /* | ||
524 | * Even though we take i_mutex we can still cause block allocation | ||
525 | * via mmap write to holes. If we have allocated new blocks we fail | ||
526 | * migrate. New block allocation will clear EXT4_EXT_MIGRATE flag. | ||
527 | * The flag is updated with i_data_sem held to prevent racing with | ||
528 | * block allocation. | ||
529 | */ | ||
530 | down_read((&EXT4_I(inode)->i_data_sem)); | ||
531 | EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE; | ||
532 | up_read((&EXT4_I(inode)->i_data_sem)); | ||
533 | |||
511 | handle = ext4_journal_start(inode, 1); | 534 | handle = ext4_journal_start(inode, 1); |
512 | 535 | ||
513 | ei = EXT4_I(inode); | 536 | ei = EXT4_I(inode); |
@@ -559,9 +582,15 @@ err_out: | |||
559 | * tmp_inode | 582 | * tmp_inode |
560 | */ | 583 | */ |
561 | free_ext_block(handle, tmp_inode); | 584 | free_ext_block(handle, tmp_inode); |
562 | else | 585 | else { |
563 | retval = ext4_ext_swap_inode_data(handle, inode, | 586 | retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode); |
564 | tmp_inode); | 587 | if (retval) |
588 | /* | ||
589 | * if we fail to swap inode data free the extent | ||
590 | * details of the tmp inode | ||
591 | */ | ||
592 | free_ext_block(handle, tmp_inode); | ||
593 | } | ||
565 | 594 | ||
566 | /* We mark the tmp_inode dirty via ext4_ext_tree_init. */ | 595 | /* We mark the tmp_inode dirty via ext4_ext_tree_init. */ |
567 | if (ext4_journal_extend(handle, 1) != 0) | 596 | if (ext4_journal_extend(handle, 1) != 0) |