aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c40
1 files changed, 37 insertions, 3 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 3fc8d854d7fb..6c8297bcfeb7 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3323,6 +3323,30 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
3323} 3323}
3324 3324
3325/* 3325/*
3326 * Check if an inode was logged in the current transaction. We can't always rely
3327 * on an inode's logged_trans value, because it's an in-memory only field and
3328 * therefore not persisted. This means that its value is lost if the inode gets
3329 * evicted and loaded again from disk (in which case it has a value of 0, and
3330 * certainly it is smaller then any possible transaction ID), when that happens
3331 * the full_sync flag is set in the inode's runtime flags, so on that case we
3332 * assume eviction happened and ignore the logged_trans value, assuming the
3333 * worst case, that the inode was logged before in the current transaction.
3334 */
3335static bool inode_logged(struct btrfs_trans_handle *trans,
3336 struct btrfs_inode *inode)
3337{
3338 if (inode->logged_trans == trans->transid)
3339 return true;
3340
3341 if (inode->last_trans == trans->transid &&
3342 test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags) &&
3343 !test_bit(BTRFS_FS_LOG_RECOVERING, &trans->fs_info->flags))
3344 return true;
3345
3346 return false;
3347}
3348
3349/*
3326 * If both a file and directory are logged, and unlinks or renames are 3350 * If both a file and directory are logged, and unlinks or renames are
3327 * mixed in, we have a few interesting corners: 3351 * mixed in, we have a few interesting corners:
3328 * 3352 *
@@ -3356,7 +3380,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
3356 int bytes_del = 0; 3380 int bytes_del = 0;
3357 u64 dir_ino = btrfs_ino(dir); 3381 u64 dir_ino = btrfs_ino(dir);
3358 3382
3359 if (dir->logged_trans < trans->transid) 3383 if (!inode_logged(trans, dir))
3360 return 0; 3384 return 0;
3361 3385
3362 ret = join_running_log_trans(root); 3386 ret = join_running_log_trans(root);
@@ -3460,7 +3484,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
3460 u64 index; 3484 u64 index;
3461 int ret; 3485 int ret;
3462 3486
3463 if (inode->logged_trans < trans->transid) 3487 if (!inode_logged(trans, inode))
3464 return 0; 3488 return 0;
3465 3489
3466 ret = join_running_log_trans(root); 3490 ret = join_running_log_trans(root);
@@ -5420,9 +5444,19 @@ log_extents:
5420 } 5444 }
5421 } 5445 }
5422 5446
5447 /*
5448 * Don't update last_log_commit if we logged that an inode exists after
5449 * it was loaded to memory (full_sync bit set).
5450 * This is to prevent data loss when we do a write to the inode, then
5451 * the inode gets evicted after all delalloc was flushed, then we log
5452 * it exists (due to a rename for example) and then fsync it. This last
5453 * fsync would do nothing (not logging the extents previously written).
5454 */
5423 spin_lock(&inode->lock); 5455 spin_lock(&inode->lock);
5424 inode->logged_trans = trans->transid; 5456 inode->logged_trans = trans->transid;
5425 inode->last_log_commit = inode->last_sub_trans; 5457 if (inode_only != LOG_INODE_EXISTS ||
5458 !test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags))
5459 inode->last_log_commit = inode->last_sub_trans;
5426 spin_unlock(&inode->lock); 5460 spin_unlock(&inode->lock);
5427out_unlock: 5461out_unlock:
5428 mutex_unlock(&inode->log_mutex); 5462 mutex_unlock(&inode->log_mutex);