Merge branch 'nowait-aio-btrfs-fixup' of git://git.kernel.org/pub/scm/linux/kernel...
[muen/linux.git] / fs / btrfs / file.c
index ad53832838b50a705c402d0575c3c3ae02c4a93c..9e75d8a39aacf7dbcfdd961dd41ddd71e924a3a3 100644 (file)
@@ -1581,6 +1581,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct page **pages = NULL;
        struct extent_state *cached_state = NULL;
+       struct extent_changeset *data_reserved = NULL;
        u64 release_bytes = 0;
        u64 lockstart;
        u64 lockend;
@@ -1628,7 +1629,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                reserve_bytes = round_up(write_bytes + sector_offset,
                                fs_info->sectorsize);
 
-               ret = btrfs_check_data_free_space(inode, pos, write_bytes);
+               extent_changeset_release(data_reserved);
+               ret = btrfs_check_data_free_space(inode, &data_reserved, pos,
+                                                 write_bytes);
                if (ret < 0) {
                        if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
                                                      BTRFS_INODE_PREALLOC)) &&
@@ -1657,8 +1660,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                                reserve_bytes);
                if (ret) {
                        if (!only_release_metadata)
-                               btrfs_free_reserved_data_space(inode, pos,
-                                                              write_bytes);
+                               btrfs_free_reserved_data_space(inode,
+                                               data_reserved, pos,
+                                               write_bytes);
                        else
                                btrfs_end_write_no_snapshoting(root);
                        break;
@@ -1740,8 +1744,9 @@ again:
                                __pos = round_down(pos,
                                                   fs_info->sectorsize) +
                                        (dirty_pages << PAGE_SHIFT);
-                               btrfs_delalloc_release_space(inode, __pos,
-                                                            release_bytes);
+                               btrfs_delalloc_release_space(inode,
+                                               data_reserved, __pos,
+                                               release_bytes);
                        }
                }
 
@@ -1796,12 +1801,13 @@ again:
                        btrfs_delalloc_release_metadata(BTRFS_I(inode),
                                        release_bytes);
                } else {
-                       btrfs_delalloc_release_space(inode,
-                                               round_down(pos, fs_info->sectorsize),
-                                               release_bytes);
+                       btrfs_delalloc_release_space(inode, data_reserved,
+                                       round_down(pos, fs_info->sectorsize),
+                                       release_bytes);
                }
        }
 
+       extent_changeset_free(data_reserved);
        return num_written ? num_written : ret;
 }
 
@@ -2028,7 +2034,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
        struct btrfs_log_ctx ctx;
-       int ret = 0;
+       int ret = 0, err;
        bool full_sync = 0;
        u64 len;
 
@@ -2047,7 +2053,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         */
        ret = start_ordered_ops(inode, start, end);
        if (ret)
-               return ret;
+               goto out;
 
        inode_lock(inode);
        atomic_inc(&root->log_batch);
@@ -2152,10 +2158,10 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                 * An ordered extent might have started before and completed
                 * already with io errors, in which case the inode was not
                 * updated and we end up here. So check the inode's mapping
-                * flags for any errors that might have happened while doing
-                * writeback of file data.
+                * for any errors that might have happened since we last
+                * checked called fsync.
                 */
-               ret = filemap_check_errors(inode->i_mapping);
+               ret = filemap_check_wb_err(inode->i_mapping, file->f_wb_err);
                inode_unlock(inode);
                goto out;
        }
@@ -2244,6 +2250,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                ret = btrfs_end_transaction(trans);
        }
 out:
+       err = file_check_and_advance_wb_err(file);
+       if (!ret)
+               ret = err;
        return ret > 0 ? -EIO : ret;
 }
 
@@ -2407,10 +2416,13 @@ out:
  */
 static int find_first_non_hole(struct inode *inode, u64 *start, u64 *len)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct extent_map *em;
        int ret = 0;
 
-       em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, *start, *len, 0);
+       em = btrfs_get_extent(BTRFS_I(inode), NULL, 0,
+                             round_down(*start, fs_info->sectorsize),
+                             round_up(*len, fs_info->sectorsize), 0);
        if (IS_ERR(em))
                return PTR_ERR(em);
 
@@ -2786,6 +2798,7 @@ static long btrfs_fallocate(struct file *file, int mode,
 {
        struct inode *inode = file_inode(file);
        struct extent_state *cached_state = NULL;
+       struct extent_changeset *data_reserved = NULL;
        struct falloc_range *range;
        struct falloc_range *tmp;
        struct list_head reserve_list;
@@ -2915,8 +2928,8 @@ static long btrfs_fallocate(struct file *file, int mode,
                                free_extent_map(em);
                                break;
                        }
-                       ret = btrfs_qgroup_reserve_data(inode, cur_offset,
-                                       last_byte - cur_offset);
+                       ret = btrfs_qgroup_reserve_data(inode, &data_reserved,
+                                       cur_offset, last_byte - cur_offset);
                        if (ret < 0) {
                                free_extent_map(em);
                                break;
@@ -2927,8 +2940,8 @@ static long btrfs_fallocate(struct file *file, int mode,
                         * range, free reserved data space first, otherwise
                         * it'll result in false ENOSPC error.
                         */
-                       btrfs_free_reserved_data_space(inode, cur_offset,
-                               last_byte - cur_offset);
+                       btrfs_free_reserved_data_space(inode, data_reserved,
+                                       cur_offset, last_byte - cur_offset);
                }
                free_extent_map(em);
                cur_offset = last_byte;
@@ -2947,8 +2960,9 @@ static long btrfs_fallocate(struct file *file, int mode,
                                        range->len, i_blocksize(inode),
                                        offset + len, &alloc_hint);
                else
-                       btrfs_free_reserved_data_space(inode, range->start,
-                                                      range->len);
+                       btrfs_free_reserved_data_space(inode,
+                                       data_reserved, range->start,
+                                       range->len);
                list_del(&range->list);
                kfree(range);
        }
@@ -2986,8 +3000,9 @@ out:
        inode_unlock(inode);
        /* Let go of our reservation. */
        if (ret != 0)
-               btrfs_free_reserved_data_space(inode, alloc_start,
-                                      alloc_end - cur_offset);
+               btrfs_free_reserved_data_space(inode, data_reserved,
+                               alloc_start, alloc_end - cur_offset);
+       extent_changeset_free(data_reserved);
        return ret;
 }