aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2017-08-29 10:11:39 -0400
committerDavid Sterba <dsterba@suse.com>2017-09-26 08:54:16 -0400
commit8c6c592831a09a28428448e68fb08c6bbb8b9b8b (patch)
tree9d4fc8af84cb616475a140b0fcebf08ba1bff0d1
parent99c4e3b96c797f047be4e6b7c03cfca01959f146 (diff)
btrfs: log csums for all modified extents
Amir reported a bug discovered by his cleaned up version of my dm-log-writes xfstests where we were missing csums at certain replay points. This is because fsx was doing an msync(), which essentially fsync()'s a specific range of a file. We will log all modified extents, but only search for the checksums in the range we are being asked to sync. We cannot simply log the extents in the range we're being asked because we are logging the inode item as it is currently, which if it has had a i_size update before the msync means we will miss extents when replaying. We could possibly get around this by marking the inode with the transaction that extended the i_size to see if we have this case, but this would be racy and we'd have to lock the whole range of the inode to make sure we didn't have an ordered extent outside of our range that was in the middle of completing. Fix this simply by keeping track of the modified extents range and logging the csums for the entire range of extents that we are logging. This makes the xfstest pass. Reported-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/tree-log.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index ad7f4bab640b..c800d067fcbf 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -4181,6 +4181,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4181 struct extent_map *em, *n; 4181 struct extent_map *em, *n;
4182 struct list_head extents; 4182 struct list_head extents;
4183 struct extent_map_tree *tree = &inode->extent_tree; 4183 struct extent_map_tree *tree = &inode->extent_tree;
4184 u64 logged_start, logged_end;
4184 u64 test_gen; 4185 u64 test_gen;
4185 int ret = 0; 4186 int ret = 0;
4186 int num = 0; 4187 int num = 0;
@@ -4190,10 +4191,11 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4190 down_write(&inode->dio_sem); 4191 down_write(&inode->dio_sem);
4191 write_lock(&tree->lock); 4192 write_lock(&tree->lock);
4192 test_gen = root->fs_info->last_trans_committed; 4193 test_gen = root->fs_info->last_trans_committed;
4194 logged_start = start;
4195 logged_end = end;
4193 4196
4194 list_for_each_entry_safe(em, n, &tree->modified_extents, list) { 4197 list_for_each_entry_safe(em, n, &tree->modified_extents, list) {
4195 list_del_init(&em->list); 4198 list_del_init(&em->list);
4196
4197 /* 4199 /*
4198 * Just an arbitrary number, this can be really CPU intensive 4200 * Just an arbitrary number, this can be really CPU intensive
4199 * once we start getting a lot of extents, and really once we 4201 * once we start getting a lot of extents, and really once we
@@ -4208,6 +4210,12 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4208 4210
4209 if (em->generation <= test_gen) 4211 if (em->generation <= test_gen)
4210 continue; 4212 continue;
4213
4214 if (em->start < logged_start)
4215 logged_start = em->start;
4216 if ((em->start + em->len - 1) > logged_end)
4217 logged_end = em->start + em->len - 1;
4218
4211 /* Need a ref to keep it from getting evicted from cache */ 4219 /* Need a ref to keep it from getting evicted from cache */
4212 refcount_inc(&em->refs); 4220 refcount_inc(&em->refs);
4213 set_bit(EXTENT_FLAG_LOGGING, &em->flags); 4221 set_bit(EXTENT_FLAG_LOGGING, &em->flags);
@@ -4216,7 +4224,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4216 } 4224 }
4217 4225
4218 list_sort(NULL, &extents, extent_cmp); 4226 list_sort(NULL, &extents, extent_cmp);
4219 btrfs_get_logged_extents(inode, logged_list, start, end); 4227 btrfs_get_logged_extents(inode, logged_list, logged_start, logged_end);
4220 /* 4228 /*
4221 * Some ordered extents started by fsync might have completed 4229 * Some ordered extents started by fsync might have completed
4222 * before we could collect them into the list logged_list, which 4230 * before we could collect them into the list logged_list, which