Merge tag 'v5.3-rc1' into docs-next
[linux-2.6-block.git] / fs / btrfs / ioctl.c
index cfeff1b8dce000925958930a7f004bd88b44bd9e..818f7ec8bb0ee327b338a7577be98bf4f6b65ff0 100644 (file)
@@ -43,6 +43,8 @@
 #include "qgroup.h"
 #include "tree-log.h"
 #include "compression.h"
+#include "space-info.h"
+#include "delalloc-space.h"
 
 #ifdef CONFIG_64BIT
 /* 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,
        if (!same_inode)
                inode_dio_wait(inode_out);
 
+       /*
+        * Workaround to make sure NOCOW buffered write reach disk as NOCOW.
+        *
+        * Btrfs' back references do not have a block level granularity, they
+        * work at the whole extent level.
+        * NOCOW buffered write without data space reserved may not be able
+        * to fall back to CoW due to lack of data space, thus could cause
+        * data loss.
+        *
+        * Here we take a shortcut by flushing the whole inode, so that all
+        * nocow write should reach disk as nocow before we increase the
+        * reference of the extent. We could do better by only flushing NOCOW
+        * data, but that needs extra accounting.
+        *
+        * Also we don't need to check ASYNC_EXTENT, as async extent will be
+        * CoWed anyway, not affecting nocow part.
+        */
+       ret = filemap_flush(inode_in->i_mapping);
+       if (ret < 0)
+               return ret;
+
        ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs),
                                       wb_len);
        if (ret < 0)