|
@@ -5904,8 +5904,17 @@ map:
|
|
|
bh_result->b_size = len;
|
|
|
bh_result->b_bdev = em->bdev;
|
|
|
set_buffer_mapped(bh_result);
|
|
|
- if (create && !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
|
|
|
- set_buffer_new(bh_result);
|
|
|
+ if (create) {
|
|
|
+ if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
|
|
|
+ set_buffer_new(bh_result);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Need to update the i_size under the extent lock so buffered
|
|
|
+ * readers will get the updated i_size when we unlock.
|
|
|
+ */
|
|
|
+ if (start + len > i_size_read(inode))
|
|
|
+ i_size_write(inode, start + len);
|
|
|
+ }
|
|
|
|
|
|
free_extent_map(em);
|
|
|
|
|
@@ -6388,12 +6397,48 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
|
|
|
*/
|
|
|
ordered = btrfs_lookup_ordered_range(inode, lockstart,
|
|
|
lockend - lockstart + 1);
|
|
|
- if (!ordered)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We need to make sure there are no buffered pages in this
|
|
|
+ * range either, we could have raced between the invalidate in
|
|
|
+ * generic_file_direct_write and locking the extent. The
|
|
|
+ * invalidate needs to happen so that reads after a write do not
|
|
|
+ * get stale data.
|
|
|
+ */
|
|
|
+ if (!ordered && (!writing ||
|
|
|
+ !test_range_bit(&BTRFS_I(inode)->io_tree,
|
|
|
+ lockstart, lockend, EXTENT_UPTODATE, 0,
|
|
|
+ cached_state)))
|
|
|
break;
|
|
|
+
|
|
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
|
|
&cached_state, GFP_NOFS);
|
|
|
- btrfs_start_ordered_extent(inode, ordered, 1);
|
|
|
- btrfs_put_ordered_extent(ordered);
|
|
|
+
|
|
|
+ if (ordered) {
|
|
|
+ btrfs_start_ordered_extent(inode, ordered, 1);
|
|
|
+ btrfs_put_ordered_extent(ordered);
|
|
|
+ } else {
|
|
|
+ /* Screw you mmap */
|
|
|
+ ret = filemap_write_and_wait_range(file->f_mapping,
|
|
|
+ lockstart,
|
|
|
+ lockend);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we found a page that couldn't be invalidated just
|
|
|
+ * fall back to buffered.
|
|
|
+ */
|
|
|
+ ret = invalidate_inode_pages2_range(file->f_mapping,
|
|
|
+ lockstart >> PAGE_CACHE_SHIFT,
|
|
|
+ lockend >> PAGE_CACHE_SHIFT);
|
|
|
+ if (ret) {
|
|
|
+ if (ret == -EBUSY)
|
|
|
+ ret = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
cond_resched();
|
|
|
}
|
|
|
|