diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-10-03 12:30:02 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-10-03 12:30:02 -0400 |
commit | cb843a6f513a1a91c54951005e60bd9b95bdf973 (patch) | |
tree | 12edfb1154691f1a8aaeeadb97899397574aa785 /fs/btrfs/file.c | |
parent | 323ac95bce442bbde514e3ce57e840402f80d909 (diff) |
Btrfs: O_DIRECT writes via buffered writes + invaldiate
This reworks the btrfs O_DIRECT write code a bit. It had always fallen
back to buffered IO and done an invalidate, but needed to be updated
for the data=ordered code. The invalidate wasn't actually removing pages
because they were still inside an ordered extent.
This also combines the O_DIRECT/O_SYNC paths where possible, and kicks
off IO in the main btrfs_file_write loop to keep the pipe down the the
disk full as we process long writes.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3088a1184483..a03d1bbb19ad 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -905,6 +905,10 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
905 | struct page *pinned[2]; | 905 | struct page *pinned[2]; |
906 | unsigned long first_index; | 906 | unsigned long first_index; |
907 | unsigned long last_index; | 907 | unsigned long last_index; |
908 | int will_write; | ||
909 | |||
910 | will_write = ((file->f_flags & O_SYNC) || IS_SYNC(inode) || | ||
911 | (file->f_flags & O_DIRECT)); | ||
908 | 912 | ||
909 | nrptrs = min((count + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE, | 913 | nrptrs = min((count + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE, |
910 | PAGE_CACHE_SIZE / (sizeof(struct page *))); | 914 | PAGE_CACHE_SIZE / (sizeof(struct page *))); |
@@ -1001,15 +1005,24 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1001 | if (ret) | 1005 | if (ret) |
1002 | goto out; | 1006 | goto out; |
1003 | 1007 | ||
1008 | if (will_write) { | ||
1009 | btrfs_fdatawrite_range(inode->i_mapping, pos, | ||
1010 | pos + write_bytes - 1, | ||
1011 | WB_SYNC_NONE); | ||
1012 | } else { | ||
1013 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, | ||
1014 | num_pages); | ||
1015 | if (num_pages < | ||
1016 | (root->leafsize >> PAGE_CACHE_SHIFT) + 1) | ||
1017 | btrfs_btree_balance_dirty(root, 1); | ||
1018 | btrfs_throttle(root); | ||
1019 | } | ||
1020 | |||
1004 | buf += write_bytes; | 1021 | buf += write_bytes; |
1005 | count -= write_bytes; | 1022 | count -= write_bytes; |
1006 | pos += write_bytes; | 1023 | pos += write_bytes; |
1007 | num_written += write_bytes; | 1024 | num_written += write_bytes; |
1008 | 1025 | ||
1009 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, num_pages); | ||
1010 | if (num_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1) | ||
1011 | btrfs_btree_balance_dirty(root, 1); | ||
1012 | btrfs_throttle(root); | ||
1013 | cond_resched(); | 1026 | cond_resched(); |
1014 | } | 1027 | } |
1015 | out: | 1028 | out: |
@@ -1023,36 +1036,29 @@ out_nolock: | |||
1023 | page_cache_release(pinned[1]); | 1036 | page_cache_release(pinned[1]); |
1024 | *ppos = pos; | 1037 | *ppos = pos; |
1025 | 1038 | ||
1026 | if (num_written > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | 1039 | if (num_written > 0 && will_write) { |
1027 | struct btrfs_trans_handle *trans; | 1040 | struct btrfs_trans_handle *trans; |
1028 | 1041 | ||
1029 | err = btrfs_fdatawrite_range(inode->i_mapping, start_pos, | 1042 | err = btrfs_wait_ordered_range(inode, start_pos, num_written); |
1030 | start_pos + num_written -1, | 1043 | if (err) |
1031 | WB_SYNC_NONE); | ||
1032 | if (err < 0) | ||
1033 | num_written = err; | ||
1034 | |||
1035 | err = btrfs_wait_on_page_writeback_range(inode->i_mapping, | ||
1036 | start_pos, start_pos + num_written - 1); | ||
1037 | if (err < 0) | ||
1038 | num_written = err; | 1044 | num_written = err; |
1039 | 1045 | ||
1040 | trans = btrfs_start_transaction(root, 1); | 1046 | if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { |
1041 | ret = btrfs_log_dentry_safe(trans, root, file->f_dentry); | 1047 | trans = btrfs_start_transaction(root, 1); |
1042 | if (ret == 0) { | 1048 | ret = btrfs_log_dentry_safe(trans, root, |
1043 | btrfs_sync_log(trans, root); | 1049 | file->f_dentry); |
1044 | btrfs_end_transaction(trans, root); | 1050 | if (ret == 0) { |
1045 | } else { | 1051 | btrfs_sync_log(trans, root); |
1046 | btrfs_commit_transaction(trans, root); | 1052 | btrfs_end_transaction(trans, root); |
1053 | } else { | ||
1054 | btrfs_commit_transaction(trans, root); | ||
1055 | } | ||
1056 | } | ||
1057 | if (file->f_flags & O_DIRECT) { | ||
1058 | invalidate_mapping_pages(inode->i_mapping, | ||
1059 | start_pos >> PAGE_CACHE_SHIFT, | ||
1060 | (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT); | ||
1047 | } | 1061 | } |
1048 | } else if (num_written > 0 && (file->f_flags & O_DIRECT)) { | ||
1049 | do_sync_mapping_range(inode->i_mapping, start_pos, | ||
1050 | start_pos + num_written - 1, | ||
1051 | SYNC_FILE_RANGE_WRITE | | ||
1052 | SYNC_FILE_RANGE_WAIT_AFTER); | ||
1053 | invalidate_mapping_pages(inode->i_mapping, | ||
1054 | start_pos >> PAGE_CACHE_SHIFT, | ||
1055 | (start_pos + num_written - 1) >> PAGE_CACHE_SHIFT); | ||
1056 | } | 1062 | } |
1057 | current->backing_dev_info = NULL; | 1063 | current->backing_dev_info = NULL; |
1058 | return num_written ? num_written : err; | 1064 | return num_written ? num_written : err; |