Btrfs: correctly flush compressed data before/after direct IO
authorFilipe Manana <fdmanana@suse.com>
Thu, 9 Oct 2014 20:18:55 +0000 (21:18 +0100)
committerChris Mason <clm@fb.com>
Fri, 21 Nov 2014 01:14:27 +0000 (17:14 -0800)
For compressed writes, after doing the first filemap_fdatawrite_range() we
don't get the pages tagged for writeback immediately. Instead we create
a workqueue task, which is run by other kthread, and keep the pages locked.
That other kthread compresses data, creates the respective ordered extent/s,
tags the pages for writeback and unlocks them. Therefore we need a second
call to filemap_fdatawrite_range() if we have compressed writes, as this
second call will wait for the pages to become unlocked, then see they became
tagged for writeback and finally wait for the writeback to finish.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/file.c
fs/btrfs/inode.c

index a18ceabd99a87978f785e2ef0b6318eab3b80ab9..f5a868ab60f3fd4b9736780d43efaffda255d013 100644 (file)
@@ -1692,8 +1692,18 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb,
                err = written_buffered;
                goto out;
        }
+       /*
+        * Ensure all data is persisted. We want the next direct IO read to be
+        * able to read what was just written.
+        */
        endbyte = pos + written_buffered - 1;
-       err = filemap_write_and_wait_range(file->f_mapping, pos, endbyte);
+       err = filemap_fdatawrite_range(file->f_mapping, pos, endbyte);
+       if (!err && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+                            &BTRFS_I(file_inode(file))->runtime_flags))
+               err = filemap_fdatawrite_range(file->f_mapping, pos, endbyte);
+       if (err)
+               goto out;
+       err = filemap_fdatawait_range(file->f_mapping, pos, endbyte);
        if (err)
                goto out;
        written += written_buffered;
index 5a8a749b7e6b6d7e94250f55e4fd4ecbe775b50b..01d223e22bb146c6d310e47da0cbdb6eed7268b8 100644 (file)
@@ -7015,9 +7015,19 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
                        btrfs_put_ordered_extent(ordered);
                } else {
                        /* Screw you mmap */
-                       ret = filemap_write_and_wait_range(inode->i_mapping,
-                                                          lockstart,
-                                                          lockend);
+                       ret = filemap_fdatawrite_range(inode->i_mapping,
+                                                      lockstart,
+                                                      lockend);
+                       if (!ret && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
+                                            &BTRFS_I(inode)->runtime_flags))
+                               ret = filemap_fdatawrite_range(inode->i_mapping,
+                                                              lockstart,
+                                                              lockend);
+                       if (ret)
+                               break;
+                       ret = filemap_fdatawait_range(inode->i_mapping,
+                                                     lockstart,
+                                                     lockend);
                        if (ret)
                                break;