aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ordered-data.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2014-11-21 14:52:38 -0500
committerChris Mason <clm@fb.com>2014-11-21 14:58:32 -0500
commit50d9aa99bd35c77200e0e3dd7a72274f8304701f (patch)
tree346a80fdf2343a5c5e010b57b0213c989eed4ac8 /fs/btrfs/ordered-data.c
parent9dba8cf128ef98257ca719722280c9634e7e9dc7 (diff)
Btrfs: make sure logged extents complete in the current transaction V3
Liu Bo pointed out that my previous fix would lose the generation update in the scenario I described. It is actually much worse than that, we could lose the entire extent if we lose power right after the transaction commits. Consider the following write extent 0-4k log extent in log tree commit transaction < power fail happens here ordered extent completes We would lose the 0-4k extent because it hasn't updated the actual fs tree, and the transaction commit will reset the log so it isn't replayed. If we lose power before the transaction commit we are save, otherwise we are not. Fix this by keeping track of all extents we logged in this transaction. Then when we go to commit the transaction make sure we wait for all of those ordered extents to complete before proceeding. This will make sure that if we lose power after the transaction commit we still have our data. This also fixes the problem of the improperly updated extent generation. Thanks, cc: stable@vger.kernel.org Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/ordered-data.c')
-rw-r--r--fs/btrfs/ordered-data.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 1401b1af4f06..9c28eb4da4dd 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -220,6 +220,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
220 INIT_LIST_HEAD(&entry->work_list); 220 INIT_LIST_HEAD(&entry->work_list);
221 init_completion(&entry->completion); 221 init_completion(&entry->completion);
222 INIT_LIST_HEAD(&entry->log_list); 222 INIT_LIST_HEAD(&entry->log_list);
223 INIT_LIST_HEAD(&entry->trans_list);
223 224
224 trace_btrfs_ordered_extent_add(inode, entry); 225 trace_btrfs_ordered_extent_add(inode, entry);
225 226
@@ -443,6 +444,8 @@ void btrfs_get_logged_extents(struct inode *inode,
443 ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); 444 ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node);
444 if (!list_empty(&ordered->log_list)) 445 if (!list_empty(&ordered->log_list))
445 continue; 446 continue;
447 if (test_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
448 continue;
446 list_add_tail(&ordered->log_list, logged_list); 449 list_add_tail(&ordered->log_list, logged_list);
447 atomic_inc(&ordered->refs); 450 atomic_inc(&ordered->refs);
448 } 451 }
@@ -472,7 +475,8 @@ void btrfs_submit_logged_extents(struct list_head *logged_list,
472 spin_unlock_irq(&log->log_extents_lock[index]); 475 spin_unlock_irq(&log->log_extents_lock[index]);
473} 476}
474 477
475void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid) 478void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans,
479 struct btrfs_root *log, u64 transid)
476{ 480{
477 struct btrfs_ordered_extent *ordered; 481 struct btrfs_ordered_extent *ordered;
478 int index = transid % 2; 482 int index = transid % 2;
@@ -497,7 +501,8 @@ void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid)
497 wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, 501 wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE,
498 &ordered->flags)); 502 &ordered->flags));
499 503
500 btrfs_put_ordered_extent(ordered); 504 if (!test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags))
505 list_add_tail(&ordered->trans_list, &trans->ordered);
501 spin_lock_irq(&log->log_extents_lock[index]); 506 spin_lock_irq(&log->log_extents_lock[index]);
502 } 507 }
503 spin_unlock_irq(&log->log_extents_lock[index]); 508 spin_unlock_irq(&log->log_extents_lock[index]);