]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/btrfs/inode.c
btrfs: Better csum error message for data csum mismatch
[mirror_ubuntu-bionic-kernel.git] / fs / btrfs / inode.c
index 3944346265e8e646bec2ab71cd1c9039d92b0f4c..175c28a94a576a2cf573d81604e28766f907c2fa 100644 (file)
@@ -71,6 +71,7 @@ struct btrfs_dio_data {
        u64 reserve;
        u64 unsubmitted_oe_range_start;
        u64 unsubmitted_oe_range_end;
+       int overwrite;
 };
 
 static const struct inode_operations btrfs_dir_inode_operations;
@@ -1246,7 +1247,6 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
        struct extent_buffer *leaf;
        struct btrfs_path *path;
        struct btrfs_file_extent_item *fi;
@@ -1282,30 +1282,10 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 
        nolock = btrfs_is_free_space_inode(inode);
 
-       if (nolock)
-               trans = btrfs_join_transaction_nolock(root);
-       else
-               trans = btrfs_join_transaction(root);
-
-       if (IS_ERR(trans)) {
-               extent_clear_unlock_delalloc(inode, start, end, end,
-                                            locked_page,
-                                            EXTENT_LOCKED | EXTENT_DELALLOC |
-                                            EXTENT_DO_ACCOUNTING |
-                                            EXTENT_DEFRAG, PAGE_UNLOCK |
-                                            PAGE_CLEAR_DIRTY |
-                                            PAGE_SET_WRITEBACK |
-                                            PAGE_END_WRITEBACK);
-               btrfs_free_path(path);
-               return PTR_ERR(trans);
-       }
-
-       trans->block_rsv = &fs_info->delalloc_block_rsv;
-
        cow_start = (u64)-1;
        cur_offset = start;
        while (1) {
-               ret = btrfs_lookup_file_extent(trans, root, path, ino,
+               ret = btrfs_lookup_file_extent(NULL, root, path, ino,
                                               cur_offset, 0);
                if (ret < 0)
                        goto error;
@@ -1378,7 +1358,7 @@ next_slot:
                                goto out_check;
                        if (btrfs_extent_readonly(fs_info, disk_bytenr))
                                goto out_check;
-                       if (btrfs_cross_ref_exist(trans, root, ino,
+                       if (btrfs_cross_ref_exist(root, ino,
                                                  found_key.offset -
                                                  extent_offset, disk_bytenr))
                                goto out_check;
@@ -1530,10 +1510,6 @@ out_check:
        }
 
 error:
-       err = btrfs_end_transaction(trans);
-       if (!ret)
-               ret = err;
-
        if (ret && cur_offset < end)
                extent_clear_unlock_delalloc(inode, cur_offset, end, end,
                                             locked_page, EXTENT_LOCKED |
@@ -3110,9 +3086,8 @@ static int __readpage_endio_check(struct inode *inode,
        kunmap_atomic(kaddr);
        return 0;
 zeroit:
-       btrfs_warn_rl(BTRFS_I(inode)->root->fs_info,
-               "csum failed ino %llu off %llu csum %u expected csum %u",
-                  btrfs_ino(BTRFS_I(inode)), start, csum, csum_expected);
+       btrfs_print_data_csum_error(inode, start, csum, csum_expected,
+                                   io_bio->mirror_num);
        memset(kaddr + pgoff, 1, len);
        flush_dcache_page(page);
        kunmap_atomic(kaddr);
@@ -7289,7 +7264,6 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *ram_bytes)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       struct btrfs_trans_handle *trans;
        struct btrfs_path *path;
        int ret;
        struct extent_buffer *leaf;
@@ -7392,15 +7366,9 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
         * look for other files referencing this extent, if we
         * find any we must cow
         */
-       trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans)) {
-               ret = 0;
-               goto out;
-       }
 
-       ret = btrfs_cross_ref_exist(trans, root, btrfs_ino(BTRFS_I(inode)),
+       ret = btrfs_cross_ref_exist(root, btrfs_ino(BTRFS_I(inode)),
                                    key.offset - backref_offset, disk_bytenr);
-       btrfs_end_transaction(trans);
        if (ret) {
                ret = 0;
                goto out;
@@ -7809,7 +7777,7 @@ unlock:
                 * 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))
+               if (!dio_data->overwrite && start + len > i_size_read(inode))
                        i_size_write(inode, start + len);
 
                adjust_dio_outstanding_extents(inode, dio_data, len);
@@ -8685,6 +8653,7 @@ static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
                 * not unlock the i_mutex at this case.
                 */
                if (offset + count <= inode->i_size) {
+                       dio_data.overwrite = 1;
                        inode_unlock(inode);
                        relock = true;
                }
@@ -9036,7 +9005,7 @@ again:
         * we can't set the delalloc bits if there are pending ordered
         * extents.  Drop our locks and wait for them to finish
         */
-       ordered = btrfs_lookup_ordered_range(inode, page_start, page_end);
+       ordered = btrfs_lookup_ordered_range(inode, page_start, PAGE_SIZE);
        if (ordered) {
                unlock_extent_cached(io_tree, page_start, page_end,
                                     &cached_state, GFP_NOFS);
@@ -9060,11 +9029,11 @@ again:
        }
 
        /*
-        * XXX - page_mkwrite gets called every time the page is dirtied, even
-        * if it was already dirty, so for space accounting reasons we need to
-        * clear any delalloc bits for the range we are fixing to save.  There
-        * is probably a better way to do this, but for now keep consistent with
-        * prepare_pages in the normal write path.
+        * page_mkwrite gets called when the page is firstly dirtied after it's
+        * faulted in, but write(2) could also dirty a page and set delalloc
+        * bits, thus in this case for space account reason, we still need to
+        * clear any delalloc bits within this page range since we have to
+        * reserve data&meta space before lock_page() (see above comments).
         */
        clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, end,
                          EXTENT_DIRTY | EXTENT_DELALLOC |