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.c80
1 files changed, 62 insertions, 18 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 9e1f2cd5e67a..1d1ba083ca6e 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -94,8 +94,10 @@
94#define LOG_WALK_REPLAY_ALL 3 94#define LOG_WALK_REPLAY_ALL 3
95 95
96static int btrfs_log_inode(struct btrfs_trans_handle *trans, 96static int btrfs_log_inode(struct btrfs_trans_handle *trans,
97 struct btrfs_root *root, struct inode *inode, 97 struct btrfs_root *root, struct inode *inode,
98 int inode_only); 98 int inode_only,
99 const loff_t start,
100 const loff_t end);
99static int link_to_fixup_dir(struct btrfs_trans_handle *trans, 101static int link_to_fixup_dir(struct btrfs_trans_handle *trans,
100 struct btrfs_root *root, 102 struct btrfs_root *root,
101 struct btrfs_path *path, u64 objectid); 103 struct btrfs_path *path, u64 objectid);
@@ -3298,7 +3300,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3298 struct list_head ordered_sums; 3300 struct list_head ordered_sums;
3299 int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; 3301 int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
3300 bool has_extents = false; 3302 bool has_extents = false;
3301 bool need_find_last_extent = (*last_extent == 0); 3303 bool need_find_last_extent = true;
3302 bool done = false; 3304 bool done = false;
3303 3305
3304 INIT_LIST_HEAD(&ordered_sums); 3306 INIT_LIST_HEAD(&ordered_sums);
@@ -3352,8 +3354,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3352 */ 3354 */
3353 if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { 3355 if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) {
3354 has_extents = true; 3356 has_extents = true;
3355 if (need_find_last_extent && 3357 if (first_key.objectid == (u64)-1)
3356 first_key.objectid == (u64)-1)
3357 first_key = ins_keys[i]; 3358 first_key = ins_keys[i];
3358 } else { 3359 } else {
3359 need_find_last_extent = false; 3360 need_find_last_extent = false;
@@ -3427,6 +3428,16 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
3427 if (!has_extents) 3428 if (!has_extents)
3428 return ret; 3429 return ret;
3429 3430
3431 if (need_find_last_extent && *last_extent == first_key.offset) {
3432 /*
3433 * We don't have any leafs between our current one and the one
3434 * we processed before that can have file extent items for our
3435 * inode (and have a generation number smaller than our current
3436 * transaction id).
3437 */
3438 need_find_last_extent = false;
3439 }
3440
3430 /* 3441 /*
3431 * Because we use btrfs_search_forward we could skip leaves that were 3442 * Because we use btrfs_search_forward we could skip leaves that were
3432 * not modified and then assume *last_extent is valid when it really 3443 * not modified and then assume *last_extent is valid when it really
@@ -3537,7 +3548,7 @@ fill_holes:
3537 0, 0); 3548 0, 0);
3538 if (ret) 3549 if (ret)
3539 break; 3550 break;
3540 *last_extent = offset + len; 3551 *last_extent = extent_end;
3541 } 3552 }
3542 /* 3553 /*
3543 * Need to let the callers know we dropped the path so they should 3554 * Need to let the callers know we dropped the path so they should
@@ -3849,8 +3860,10 @@ process:
3849 * This handles both files and directories. 3860 * This handles both files and directories.
3850 */ 3861 */
3851static int btrfs_log_inode(struct btrfs_trans_handle *trans, 3862static int btrfs_log_inode(struct btrfs_trans_handle *trans,
3852 struct btrfs_root *root, struct inode *inode, 3863 struct btrfs_root *root, struct inode *inode,
3853 int inode_only) 3864 int inode_only,
3865 const loff_t start,
3866 const loff_t end)
3854{ 3867{
3855 struct btrfs_path *path; 3868 struct btrfs_path *path;
3856 struct btrfs_path *dst_path; 3869 struct btrfs_path *dst_path;
@@ -3867,6 +3880,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
3867 int ins_nr; 3880 int ins_nr;
3868 bool fast_search = false; 3881 bool fast_search = false;
3869 u64 ino = btrfs_ino(inode); 3882 u64 ino = btrfs_ino(inode);
3883 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
3870 3884
3871 path = btrfs_alloc_path(); 3885 path = btrfs_alloc_path();
3872 if (!path) 3886 if (!path)
@@ -4040,13 +4054,35 @@ log_extents:
4040 goto out_unlock; 4054 goto out_unlock;
4041 } 4055 }
4042 } else if (inode_only == LOG_INODE_ALL) { 4056 } else if (inode_only == LOG_INODE_ALL) {
4043 struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
4044 struct extent_map *em, *n; 4057 struct extent_map *em, *n;
4045 4058
4046 write_lock(&tree->lock); 4059 write_lock(&em_tree->lock);
4047 list_for_each_entry_safe(em, n, &tree->modified_extents, list) 4060 /*
4048 list_del_init(&em->list); 4061 * We can't just remove every em if we're called for a ranged
4049 write_unlock(&tree->lock); 4062 * fsync - that is, one that doesn't cover the whole possible
4063 * file range (0 to LLONG_MAX). This is because we can have
4064 * em's that fall outside the range we're logging and therefore
4065 * their ordered operations haven't completed yet
4066 * (btrfs_finish_ordered_io() not invoked yet). This means we
4067 * didn't get their respective file extent item in the fs/subvol
4068 * tree yet, and need to let the next fast fsync (one which
4069 * consults the list of modified extent maps) find the em so
4070 * that it logs a matching file extent item and waits for the
4071 * respective ordered operation to complete (if it's still
4072 * running).
4073 *
4074 * Removing every em outside the range we're logging would make
4075 * the next fast fsync not log their matching file extent items,
4076 * therefore making us lose data after a log replay.
4077 */
4078 list_for_each_entry_safe(em, n, &em_tree->modified_extents,
4079 list) {
4080 const u64 mod_end = em->mod_start + em->mod_len - 1;
4081
4082 if (em->mod_start >= start && mod_end <= end)
4083 list_del_init(&em->list);
4084 }
4085 write_unlock(&em_tree->lock);
4050 } 4086 }
4051 4087
4052 if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { 4088 if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
@@ -4056,6 +4092,7 @@ log_extents:
4056 goto out_unlock; 4092 goto out_unlock;
4057 } 4093 }
4058 } 4094 }
4095
4059 BTRFS_I(inode)->logged_trans = trans->transid; 4096 BTRFS_I(inode)->logged_trans = trans->transid;
4060 BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; 4097 BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans;
4061out_unlock: 4098out_unlock:
@@ -4152,7 +4189,10 @@ out:
4152 */ 4189 */
4153static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, 4190static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4154 struct btrfs_root *root, struct inode *inode, 4191 struct btrfs_root *root, struct inode *inode,
4155 struct dentry *parent, int exists_only, 4192 struct dentry *parent,
4193 const loff_t start,
4194 const loff_t end,
4195 int exists_only,
4156 struct btrfs_log_ctx *ctx) 4196 struct btrfs_log_ctx *ctx)
4157{ 4197{
4158 int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; 4198 int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
@@ -4198,7 +4238,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4198 if (ret) 4238 if (ret)
4199 goto end_no_trans; 4239 goto end_no_trans;
4200 4240
4201 ret = btrfs_log_inode(trans, root, inode, inode_only); 4241 ret = btrfs_log_inode(trans, root, inode, inode_only, start, end);
4202 if (ret) 4242 if (ret)
4203 goto end_trans; 4243 goto end_trans;
4204 4244
@@ -4226,7 +4266,8 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4226 4266
4227 if (BTRFS_I(inode)->generation > 4267 if (BTRFS_I(inode)->generation >
4228 root->fs_info->last_trans_committed) { 4268 root->fs_info->last_trans_committed) {
4229 ret = btrfs_log_inode(trans, root, inode, inode_only); 4269 ret = btrfs_log_inode(trans, root, inode, inode_only,
4270 0, LLONG_MAX);
4230 if (ret) 4271 if (ret)
4231 goto end_trans; 4272 goto end_trans;
4232 } 4273 }
@@ -4260,13 +4301,15 @@ end_no_trans:
4260 */ 4301 */
4261int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, 4302int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
4262 struct btrfs_root *root, struct dentry *dentry, 4303 struct btrfs_root *root, struct dentry *dentry,
4304 const loff_t start,
4305 const loff_t end,
4263 struct btrfs_log_ctx *ctx) 4306 struct btrfs_log_ctx *ctx)
4264{ 4307{
4265 struct dentry *parent = dget_parent(dentry); 4308 struct dentry *parent = dget_parent(dentry);
4266 int ret; 4309 int ret;
4267 4310
4268 ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 4311 ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent,
4269 0, ctx); 4312 start, end, 0, ctx);
4270 dput(parent); 4313 dput(parent);
4271 4314
4272 return ret; 4315 return ret;
@@ -4503,6 +4546,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
4503 root->fs_info->last_trans_committed)) 4546 root->fs_info->last_trans_committed))
4504 return 0; 4547 return 0;
4505 4548
4506 return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL); 4549 return btrfs_log_inode_parent(trans, root, inode, parent, 0,
4550 LLONG_MAX, 1, NULL);
4507} 4551}
4508 4552