diff options
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a3c22e16509b..58e93bce3036 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -2089,6 +2089,30 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | |||
2089 | atomic_inc(&root->log_batch); | 2089 | atomic_inc(&root->log_batch); |
2090 | 2090 | ||
2091 | /* | 2091 | /* |
2092 | * Before we acquired the inode's lock, someone may have dirtied more | ||
2093 | * pages in the target range. We need to make sure that writeback for | ||
2094 | * any such pages does not start while we are logging the inode, because | ||
2095 | * if it does, any of the following might happen when we are not doing a | ||
2096 | * full inode sync: | ||
2097 | * | ||
2098 | * 1) We log an extent after its writeback finishes but before its | ||
2099 | * checksums are added to the csum tree, leading to -EIO errors | ||
2100 | * when attempting to read the extent after a log replay. | ||
2101 | * | ||
2102 | * 2) We can end up logging an extent before its writeback finishes. | ||
2103 | * Therefore after the log replay we will have a file extent item | ||
2104 | * pointing to an unwritten extent (and no data checksums as well). | ||
2105 | * | ||
2106 | * So trigger writeback for any eventual new dirty pages and then we | ||
2107 | * wait for all ordered extents to complete below. | ||
2108 | */ | ||
2109 | ret = start_ordered_ops(inode, start, end); | ||
2110 | if (ret) { | ||
2111 | inode_unlock(inode); | ||
2112 | goto out; | ||
2113 | } | ||
2114 | |||
2115 | /* | ||
2092 | * We have to do this here to avoid the priority inversion of waiting on | 2116 | * We have to do this here to avoid the priority inversion of waiting on |
2093 | * IO of a lower priority task while holding a transaciton open. | 2117 | * IO of a lower priority task while holding a transaciton open. |
2094 | */ | 2118 | */ |