diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/tree-log.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 67e5bf709dca..60e1d0083faa 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -4273,6 +4273,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4273 | struct dentry *old_parent = NULL; | 4273 | struct dentry *old_parent = NULL; |
4274 | int ret = 0; | 4274 | int ret = 0; |
4275 | u64 last_committed = root->fs_info->last_trans_committed; | 4275 | u64 last_committed = root->fs_info->last_trans_committed; |
4276 | const struct dentry * const first_parent = parent; | ||
4277 | const bool did_unlink = (BTRFS_I(inode)->last_unlink_trans > | ||
4278 | last_committed); | ||
4276 | 4279 | ||
4277 | sb = inode->i_sb; | 4280 | sb = inode->i_sb; |
4278 | 4281 | ||
@@ -4328,7 +4331,6 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4328 | goto end_trans; | 4331 | goto end_trans; |
4329 | } | 4332 | } |
4330 | 4333 | ||
4331 | inode_only = LOG_INODE_EXISTS; | ||
4332 | while (1) { | 4334 | while (1) { |
4333 | if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb) | 4335 | if (!parent || !parent->d_inode || sb != parent->d_inode->i_sb) |
4334 | break; | 4336 | break; |
@@ -4337,8 +4339,22 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, | |||
4337 | if (root != BTRFS_I(inode)->root) | 4339 | if (root != BTRFS_I(inode)->root) |
4338 | break; | 4340 | break; |
4339 | 4341 | ||
4342 | /* | ||
4343 | * On unlink we must make sure our immediate parent directory | ||
4344 | * inode is fully logged. This is to prevent leaving dangling | ||
4345 | * directory index entries and a wrong directory inode's i_size. | ||
4346 | * Not doing so can result in a directory being impossible to | ||
4347 | * delete after log replay (rmdir will always fail with error | ||
4348 | * -ENOTEMPTY). | ||
4349 | */ | ||
4350 | if (did_unlink && parent == first_parent) | ||
4351 | inode_only = LOG_INODE_ALL; | ||
4352 | else | ||
4353 | inode_only = LOG_INODE_EXISTS; | ||
4354 | |||
4340 | if (BTRFS_I(inode)->generation > | 4355 | if (BTRFS_I(inode)->generation > |
4341 | root->fs_info->last_trans_committed) { | 4356 | root->fs_info->last_trans_committed || |
4357 | inode_only == LOG_INODE_ALL) { | ||
4342 | ret = btrfs_log_inode(trans, root, inode, inode_only, | 4358 | ret = btrfs_log_inode(trans, root, inode, inode_only, |
4343 | 0, LLONG_MAX, ctx); | 4359 | 0, LLONG_MAX, ctx); |
4344 | if (ret) | 4360 | if (ret) |