diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index cfeff1b8dce0..818f7ec8bb0e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -43,6 +43,8 @@ | |||
43 | #include "qgroup.h" | 43 | #include "qgroup.h" |
44 | #include "tree-log.h" | 44 | #include "tree-log.h" |
45 | #include "compression.h" | 45 | #include "compression.h" |
46 | #include "space-info.h" | ||
47 | #include "delalloc-space.h" | ||
46 | 48 | ||
47 | #ifdef CONFIG_64BIT | 49 | #ifdef CONFIG_64BIT |
48 | /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI | 50 | /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI |
@@ -3993,6 +3995,27 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, | |||
3993 | if (!same_inode) | 3995 | if (!same_inode) |
3994 | inode_dio_wait(inode_out); | 3996 | inode_dio_wait(inode_out); |
3995 | 3997 | ||
3998 | /* | ||
3999 | * Workaround to make sure NOCOW buffered write reach disk as NOCOW. | ||
4000 | * | ||
4001 | * Btrfs' back references do not have a block level granularity, they | ||
4002 | * work at the whole extent level. | ||
4003 | * NOCOW buffered write without data space reserved may not be able | ||
4004 | * to fall back to CoW due to lack of data space, thus could cause | ||
4005 | * data loss. | ||
4006 | * | ||
4007 | * Here we take a shortcut by flushing the whole inode, so that all | ||
4008 | * nocow write should reach disk as nocow before we increase the | ||
4009 | * reference of the extent. We could do better by only flushing NOCOW | ||
4010 | * data, but that needs extra accounting. | ||
4011 | * | ||
4012 | * Also we don't need to check ASYNC_EXTENT, as async extent will be | ||
4013 | * CoWed anyway, not affecting nocow part. | ||
4014 | */ | ||
4015 | ret = filemap_flush(inode_in->i_mapping); | ||
4016 | if (ret < 0) | ||
4017 | return ret; | ||
4018 | |||
3996 | ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs), | 4019 | ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs), |
3997 | wb_len); | 4020 | wb_len); |
3998 | if (ret < 0) | 4021 | if (ret < 0) |