16cbd5570SChris Mason /* 26cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 36cbd5570SChris Mason * 46cbd5570SChris Mason * This program is free software; you can redistribute it and/or 56cbd5570SChris Mason * modify it under the terms of the GNU General Public 66cbd5570SChris Mason * License v2 as published by the Free Software Foundation. 76cbd5570SChris Mason * 86cbd5570SChris Mason * This program is distributed in the hope that it will be useful, 96cbd5570SChris Mason * but WITHOUT ANY WARRANTY; without even the implied warranty of 106cbd5570SChris Mason * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 116cbd5570SChris Mason * General Public License for more details. 126cbd5570SChris Mason * 136cbd5570SChris Mason * You should have received a copy of the GNU General Public 146cbd5570SChris Mason * License along with this program; if not, write to the 156cbd5570SChris Mason * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 166cbd5570SChris Mason * Boston, MA 021110-1307, USA. 176cbd5570SChris Mason */ 186cbd5570SChris Mason 19065631f6SChris Mason #include <linux/bio.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 21065631f6SChris Mason #include <linux/pagemap.h> 22065631f6SChris Mason #include <linux/highmem.h> 231e1d2701SChris Mason #include "ctree.h" 24dee26a9fSChris Mason #include "disk-io.h" 259f5fae2fSChris Mason #include "transaction.h" 261de037a4SChris Mason #include "print-tree.h" 271e1d2701SChris Mason 28607d432dSJosef Bacik #define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \ 29a429e513SChris Mason sizeof(struct btrfs_item) * 2) / \ 30607d432dSJosef Bacik size) - 1)) 3107d400a6SYan Zheng 3207d400a6SYan Zheng #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ 3307d400a6SYan Zheng sizeof(struct btrfs_ordered_sum)) / \ 3407d400a6SYan Zheng sizeof(struct btrfs_sector_sum) * \ 3507d400a6SYan Zheng (r)->sectorsize - (r)->sectorsize) 3607d400a6SYan Zheng 37b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 38dee26a9fSChris Mason struct btrfs_root *root, 39b18c6685SChris Mason u64 objectid, u64 pos, 40f2eb0a24SSage Weil u64 disk_offset, u64 disk_num_bytes, 41c8b97818SChris Mason u64 num_bytes, u64 offset, u64 ram_bytes, 42c8b97818SChris Mason u8 compression, u8 encryption, u16 other_encoding) 439f5fae2fSChris Mason { 44dee26a9fSChris Mason int ret = 0; 45dee26a9fSChris Mason struct btrfs_file_extent_item *item; 46dee26a9fSChris Mason struct btrfs_key file_key; 475caf2a00SChris Mason struct btrfs_path *path; 485f39d397SChris Mason struct extent_buffer *leaf; 49dee26a9fSChris Mason 505caf2a00SChris Mason path = btrfs_alloc_path(); 51db5b493aSTsutomu Itoh if (!path) 52db5b493aSTsutomu Itoh return -ENOMEM; 53dee26a9fSChris Mason file_key.objectid = objectid; 54b18c6685SChris Mason file_key.offset = pos; 55dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 56dee26a9fSChris Mason 57b9473439SChris Mason path->leave_spinning = 1; 585caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 59dee26a9fSChris Mason sizeof(*item)); 6054aa1f4dSChris Mason if (ret < 0) 6154aa1f4dSChris Mason goto out; 62*79787eaaSJeff Mahoney BUG_ON(ret); /* Can't happen */ 635f39d397SChris Mason leaf = path->nodes[0]; 645f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], 65dee26a9fSChris Mason struct btrfs_file_extent_item); 66f2eb0a24SSage Weil btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); 67db94535dSChris Mason btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 68f2eb0a24SSage Weil btrfs_set_file_extent_offset(leaf, item, offset); 69db94535dSChris Mason btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 70c8b97818SChris Mason btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); 715f39d397SChris Mason btrfs_set_file_extent_generation(leaf, item, trans->transid); 725f39d397SChris Mason btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 73c8b97818SChris Mason btrfs_set_file_extent_compression(leaf, item, compression); 74c8b97818SChris Mason btrfs_set_file_extent_encryption(leaf, item, encryption); 75c8b97818SChris Mason btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); 76c8b97818SChris Mason 775f39d397SChris Mason btrfs_mark_buffer_dirty(leaf); 7854aa1f4dSChris Mason out: 795caf2a00SChris Mason btrfs_free_path(path); 8054aa1f4dSChris Mason return ret; 819f5fae2fSChris Mason } 82dee26a9fSChris Mason 83b18c6685SChris Mason struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, 84b18c6685SChris Mason struct btrfs_root *root, 856567e837SChris Mason struct btrfs_path *path, 86d20f7043SChris Mason u64 bytenr, int cow) 876567e837SChris Mason { 886567e837SChris Mason int ret; 896567e837SChris Mason struct btrfs_key file_key; 906567e837SChris Mason struct btrfs_key found_key; 916567e837SChris Mason struct btrfs_csum_item *item; 925f39d397SChris Mason struct extent_buffer *leaf; 936567e837SChris Mason u64 csum_offset = 0; 946c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 95a429e513SChris Mason int csums_in_item; 966567e837SChris Mason 97d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 98d20f7043SChris Mason file_key.offset = bytenr; 99d20f7043SChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); 100b18c6685SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 1016567e837SChris Mason if (ret < 0) 1026567e837SChris Mason goto fail; 1035f39d397SChris Mason leaf = path->nodes[0]; 1046567e837SChris Mason if (ret > 0) { 1056567e837SChris Mason ret = 1; 10670b2befdSChris Mason if (path->slots[0] == 0) 1076567e837SChris Mason goto fail; 1086567e837SChris Mason path->slots[0]--; 1095f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 110d20f7043SChris Mason if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) 1116567e837SChris Mason goto fail; 112d20f7043SChris Mason 113d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 1146567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 1155f39d397SChris Mason csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 116607d432dSJosef Bacik csums_in_item /= csum_size; 117a429e513SChris Mason 118a429e513SChris Mason if (csum_offset >= csums_in_item) { 119a429e513SChris Mason ret = -EFBIG; 1206567e837SChris Mason goto fail; 1216567e837SChris Mason } 1226567e837SChris Mason } 1236567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 124509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 125607d432dSJosef Bacik csum_offset * csum_size); 1266567e837SChris Mason return item; 1276567e837SChris Mason fail: 1286567e837SChris Mason if (ret > 0) 129b18c6685SChris Mason ret = -ENOENT; 1306567e837SChris Mason return ERR_PTR(ret); 1316567e837SChris Mason } 1326567e837SChris Mason 1336567e837SChris Mason 134dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 135dee26a9fSChris Mason struct btrfs_root *root, 136dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1379773a788SChris Mason u64 offset, int mod) 138dee26a9fSChris Mason { 139dee26a9fSChris Mason int ret; 140dee26a9fSChris Mason struct btrfs_key file_key; 141dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 142dee26a9fSChris Mason int cow = mod != 0; 143dee26a9fSChris Mason 144dee26a9fSChris Mason file_key.objectid = objectid; 14570b2befdSChris Mason file_key.offset = offset; 146dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 147dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 148dee26a9fSChris Mason return ret; 149dee26a9fSChris Mason } 150f254e52cSChris Mason 15117d217feSYan Zheng 1524b46fce2SJosef Bacik static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 1534b46fce2SJosef Bacik struct inode *inode, struct bio *bio, 1544b46fce2SJosef Bacik u64 logical_offset, u32 *dst, int dio) 15561b49440SChris Mason { 15661b49440SChris Mason u32 sum; 15761b49440SChris Mason struct bio_vec *bvec = bio->bi_io_vec; 15861b49440SChris Mason int bio_index = 0; 1594b46fce2SJosef Bacik u64 offset = 0; 16061b49440SChris Mason u64 item_start_offset = 0; 16161b49440SChris Mason u64 item_last_offset = 0; 162d20f7043SChris Mason u64 disk_bytenr; 16361b49440SChris Mason u32 diff; 1646c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 16561b49440SChris Mason int ret; 16661b49440SChris Mason struct btrfs_path *path; 16761b49440SChris Mason struct btrfs_csum_item *item = NULL; 16861b49440SChris Mason struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 16961b49440SChris Mason 17061b49440SChris Mason path = btrfs_alloc_path(); 171c2db1073STsutomu Itoh if (!path) 172c2db1073STsutomu Itoh return -ENOMEM; 1734d1b5fb4SChris Mason if (bio->bi_size > PAGE_CACHE_SIZE * 8) 1744d1b5fb4SChris Mason path->reada = 2; 17561b49440SChris Mason 17661b49440SChris Mason WARN_ON(bio->bi_vcnt <= 0); 17761b49440SChris Mason 1782cf8572dSChris Mason /* 1792cf8572dSChris Mason * the free space stuff is only read when it hasn't been 1802cf8572dSChris Mason * updated in the current transaction. So, we can safely 1812cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 1822cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 1832cf8572dSChris Mason */ 184ddf23b3fSJosef Bacik if (btrfs_is_free_space_inode(root, inode)) { 1852cf8572dSChris Mason path->search_commit_root = 1; 186ddf23b3fSJosef Bacik path->skip_locking = 1; 187ddf23b3fSJosef Bacik } 1882cf8572dSChris Mason 189d20f7043SChris Mason disk_bytenr = (u64)bio->bi_sector << 9; 1904b46fce2SJosef Bacik if (dio) 1914b46fce2SJosef Bacik offset = logical_offset; 19261b49440SChris Mason while (bio_index < bio->bi_vcnt) { 1934b46fce2SJosef Bacik if (!dio) 19461b49440SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 195d20f7043SChris Mason ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); 19661b49440SChris Mason if (ret == 0) 19761b49440SChris Mason goto found; 19861b49440SChris Mason 199d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 200d20f7043SChris Mason disk_bytenr >= item_last_offset) { 20161b49440SChris Mason struct btrfs_key found_key; 20261b49440SChris Mason u32 item_size; 20361b49440SChris Mason 20461b49440SChris Mason if (item) 205b3b4aa74SDavid Sterba btrfs_release_path(path); 206d20f7043SChris Mason item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, 207d20f7043SChris Mason path, disk_bytenr, 0); 20861b49440SChris Mason if (IS_ERR(item)) { 20961b49440SChris Mason ret = PTR_ERR(item); 21061b49440SChris Mason if (ret == -ENOENT || ret == -EFBIG) 21161b49440SChris Mason ret = 0; 21261b49440SChris Mason sum = 0; 21317d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 21417d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 21517d217feSYan Zheng set_extent_bits(io_tree, offset, 21617d217feSYan Zheng offset + bvec->bv_len - 1, 21717d217feSYan Zheng EXTENT_NODATASUM, GFP_NOFS); 21817d217feSYan Zheng } else { 219d397712bSChris Mason printk(KERN_INFO "btrfs no csum found " 22033345d01SLi Zefan "for inode %llu start %llu\n", 22133345d01SLi Zefan (unsigned long long) 22233345d01SLi Zefan btrfs_ino(inode), 22361b49440SChris Mason (unsigned long long)offset); 22417d217feSYan Zheng } 2256dab8157SChris Mason item = NULL; 226b3b4aa74SDavid Sterba btrfs_release_path(path); 22761b49440SChris Mason goto found; 22861b49440SChris Mason } 22961b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 23061b49440SChris Mason path->slots[0]); 23161b49440SChris Mason 23261b49440SChris Mason item_start_offset = found_key.offset; 23361b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 23461b49440SChris Mason path->slots[0]); 23561b49440SChris Mason item_last_offset = item_start_offset + 236607d432dSJosef Bacik (item_size / csum_size) * 23761b49440SChris Mason root->sectorsize; 23861b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 23961b49440SChris Mason struct btrfs_csum_item); 24061b49440SChris Mason } 24161b49440SChris Mason /* 24261b49440SChris Mason * this byte range must be able to fit inside 24361b49440SChris Mason * a single leaf so it will also fit inside a u32 24461b49440SChris Mason */ 245d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 24661b49440SChris Mason diff = diff / root->sectorsize; 247607d432dSJosef Bacik diff = diff * csum_size; 24861b49440SChris Mason 24961b49440SChris Mason read_extent_buffer(path->nodes[0], &sum, 2503de9d6b6SChris Mason ((unsigned long)item) + diff, 251607d432dSJosef Bacik csum_size); 25261b49440SChris Mason found: 253d20f7043SChris Mason if (dst) 254d20f7043SChris Mason *dst++ = sum; 255d20f7043SChris Mason else 25661b49440SChris Mason set_state_private(io_tree, offset, sum); 257d20f7043SChris Mason disk_bytenr += bvec->bv_len; 2584b46fce2SJosef Bacik offset += bvec->bv_len; 25961b49440SChris Mason bio_index++; 26061b49440SChris Mason bvec++; 26161b49440SChris Mason } 26261b49440SChris Mason btrfs_free_path(path); 26361b49440SChris Mason return 0; 26461b49440SChris Mason } 26561b49440SChris Mason 2664b46fce2SJosef Bacik int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 2674b46fce2SJosef Bacik struct bio *bio, u32 *dst) 2684b46fce2SJosef Bacik { 2694b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); 2704b46fce2SJosef Bacik } 2714b46fce2SJosef Bacik 2724b46fce2SJosef Bacik int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 2734b46fce2SJosef Bacik struct bio *bio, u64 offset, u32 *dst) 2744b46fce2SJosef Bacik { 2754b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, offset, dst, 1); 2764b46fce2SJosef Bacik } 2774b46fce2SJosef Bacik 27817d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 279a2de733cSArne Jansen struct list_head *list, int search_commit) 28017d217feSYan Zheng { 28117d217feSYan Zheng struct btrfs_key key; 28217d217feSYan Zheng struct btrfs_path *path; 28317d217feSYan Zheng struct extent_buffer *leaf; 28417d217feSYan Zheng struct btrfs_ordered_sum *sums; 28517d217feSYan Zheng struct btrfs_sector_sum *sector_sum; 28617d217feSYan Zheng struct btrfs_csum_item *item; 2870678b618SMark Fasheh LIST_HEAD(tmplist); 28817d217feSYan Zheng unsigned long offset; 28917d217feSYan Zheng int ret; 29017d217feSYan Zheng size_t size; 29117d217feSYan Zheng u64 csum_end; 2926c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 29317d217feSYan Zheng 29417d217feSYan Zheng path = btrfs_alloc_path(); 295d8926bb3SMark Fasheh if (!path) 296d8926bb3SMark Fasheh return -ENOMEM; 29717d217feSYan Zheng 298a2de733cSArne Jansen if (search_commit) { 299a2de733cSArne Jansen path->skip_locking = 1; 300a2de733cSArne Jansen path->reada = 2; 301a2de733cSArne Jansen path->search_commit_root = 1; 302a2de733cSArne Jansen } 303a2de733cSArne Jansen 30417d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 30517d217feSYan Zheng key.offset = start; 30617d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 30717d217feSYan Zheng 30807d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 30917d217feSYan Zheng if (ret < 0) 31017d217feSYan Zheng goto fail; 31117d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 31217d217feSYan Zheng leaf = path->nodes[0]; 31317d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 31417d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 31517d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 31617d217feSYan Zheng offset = (start - key.offset) >> 31717d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 31817d217feSYan Zheng if (offset * csum_size < 31917d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 32017d217feSYan Zheng path->slots[0]--; 32117d217feSYan Zheng } 32217d217feSYan Zheng } 32317d217feSYan Zheng 32417d217feSYan Zheng while (start <= end) { 32517d217feSYan Zheng leaf = path->nodes[0]; 32617d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 32707d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 32817d217feSYan Zheng if (ret < 0) 32917d217feSYan Zheng goto fail; 33017d217feSYan Zheng if (ret > 0) 33117d217feSYan Zheng break; 33217d217feSYan Zheng leaf = path->nodes[0]; 33317d217feSYan Zheng } 33417d217feSYan Zheng 33517d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 33617d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 33717d217feSYan Zheng key.type != BTRFS_EXTENT_CSUM_KEY) 33817d217feSYan Zheng break; 33917d217feSYan Zheng 34017d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 34117d217feSYan Zheng if (key.offset > end) 34217d217feSYan Zheng break; 34317d217feSYan Zheng 34417d217feSYan Zheng if (key.offset > start) 34517d217feSYan Zheng start = key.offset; 34617d217feSYan Zheng 34717d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 34817d217feSYan Zheng csum_end = key.offset + (size / csum_size) * root->sectorsize; 34987b29b20SYan Zheng if (csum_end <= start) { 35087b29b20SYan Zheng path->slots[0]++; 35187b29b20SYan Zheng continue; 35287b29b20SYan Zheng } 35317d217feSYan Zheng 35407d400a6SYan Zheng csum_end = min(csum_end, end + 1); 35507d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 35607d400a6SYan Zheng struct btrfs_csum_item); 35707d400a6SYan Zheng while (start < csum_end) { 35807d400a6SYan Zheng size = min_t(size_t, csum_end - start, 35907d400a6SYan Zheng MAX_ORDERED_SUM_BYTES(root)); 36007d400a6SYan Zheng sums = kzalloc(btrfs_ordered_sum_size(root, size), 36107d400a6SYan Zheng GFP_NOFS); 3620678b618SMark Fasheh if (!sums) { 3630678b618SMark Fasheh ret = -ENOMEM; 3640678b618SMark Fasheh goto fail; 3650678b618SMark Fasheh } 36617d217feSYan Zheng 36717d217feSYan Zheng sector_sum = sums->sums; 36817d217feSYan Zheng sums->bytenr = start; 36917d217feSYan Zheng sums->len = size; 37017d217feSYan Zheng 37117d217feSYan Zheng offset = (start - key.offset) >> 37217d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 37317d217feSYan Zheng offset *= csum_size; 37417d217feSYan Zheng 37517d217feSYan Zheng while (size > 0) { 37607d400a6SYan Zheng read_extent_buffer(path->nodes[0], 37707d400a6SYan Zheng §or_sum->sum, 37807d400a6SYan Zheng ((unsigned long)item) + 37907d400a6SYan Zheng offset, csum_size); 38017d217feSYan Zheng sector_sum->bytenr = start; 38117d217feSYan Zheng 38217d217feSYan Zheng size -= root->sectorsize; 38317d217feSYan Zheng start += root->sectorsize; 38417d217feSYan Zheng offset += csum_size; 38517d217feSYan Zheng sector_sum++; 38617d217feSYan Zheng } 3870678b618SMark Fasheh list_add_tail(&sums->list, &tmplist); 38807d400a6SYan Zheng } 38917d217feSYan Zheng path->slots[0]++; 39017d217feSYan Zheng } 39117d217feSYan Zheng ret = 0; 39217d217feSYan Zheng fail: 3930678b618SMark Fasheh while (ret < 0 && !list_empty(&tmplist)) { 3940678b618SMark Fasheh sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); 3950678b618SMark Fasheh list_del(&sums->list); 3960678b618SMark Fasheh kfree(sums); 3970678b618SMark Fasheh } 3980678b618SMark Fasheh list_splice_tail(&tmplist, list); 3990678b618SMark Fasheh 40017d217feSYan Zheng btrfs_free_path(path); 40117d217feSYan Zheng return ret; 40217d217feSYan Zheng } 40317d217feSYan Zheng 4043edf7d33SChris Mason int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 405d20f7043SChris Mason struct bio *bio, u64 file_start, int contig) 406e015640fSChris Mason { 407e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums; 408e6dcd2dcSChris Mason struct btrfs_sector_sum *sector_sum; 4093edf7d33SChris Mason struct btrfs_ordered_extent *ordered; 410e015640fSChris Mason char *data; 411e015640fSChris Mason struct bio_vec *bvec = bio->bi_io_vec; 412e015640fSChris Mason int bio_index = 0; 4133edf7d33SChris Mason unsigned long total_bytes = 0; 4143edf7d33SChris Mason unsigned long this_sum_bytes = 0; 4153edf7d33SChris Mason u64 offset; 416d20f7043SChris Mason u64 disk_bytenr; 417e015640fSChris Mason 418e6dcd2dcSChris Mason WARN_ON(bio->bi_vcnt <= 0); 419e6dcd2dcSChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); 420e015640fSChris Mason if (!sums) 421e015640fSChris Mason return -ENOMEM; 4223edf7d33SChris Mason 423ed98b56aSChris Mason sector_sum = sums->sums; 424d20f7043SChris Mason disk_bytenr = (u64)bio->bi_sector << 9; 425e6dcd2dcSChris Mason sums->len = bio->bi_size; 426e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 427d20f7043SChris Mason 428d20f7043SChris Mason if (contig) 429d20f7043SChris Mason offset = file_start; 430d20f7043SChris Mason else 431d20f7043SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 432d20f7043SChris Mason 433d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 434*79787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 435d20f7043SChris Mason sums->bytenr = ordered->start; 436e015640fSChris Mason 437e015640fSChris Mason while (bio_index < bio->bi_vcnt) { 438d20f7043SChris Mason if (!contig) 4393edf7d33SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 440d20f7043SChris Mason 441d20f7043SChris Mason if (!contig && (offset >= ordered->file_offset + ordered->len || 442d20f7043SChris Mason offset < ordered->file_offset)) { 4433edf7d33SChris Mason unsigned long bytes_left; 4443edf7d33SChris Mason sums->len = this_sum_bytes; 4453edf7d33SChris Mason this_sum_bytes = 0; 4463edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4473edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4483edf7d33SChris Mason 4493edf7d33SChris Mason bytes_left = bio->bi_size - total_bytes; 4503edf7d33SChris Mason 4513edf7d33SChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), 4523edf7d33SChris Mason GFP_NOFS); 453*79787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 454ed98b56aSChris Mason sector_sum = sums->sums; 4553edf7d33SChris Mason sums->len = bytes_left; 456d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 457*79787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 458d20f7043SChris Mason sums->bytenr = ordered->start; 4593edf7d33SChris Mason } 4603edf7d33SChris Mason 461e015640fSChris Mason data = kmap_atomic(bvec->bv_page, KM_USER0); 462e6dcd2dcSChris Mason sector_sum->sum = ~(u32)0; 463e6dcd2dcSChris Mason sector_sum->sum = btrfs_csum_data(root, 464e6dcd2dcSChris Mason data + bvec->bv_offset, 465e6dcd2dcSChris Mason sector_sum->sum, 466e6dcd2dcSChris Mason bvec->bv_len); 467e015640fSChris Mason kunmap_atomic(data, KM_USER0); 468e6dcd2dcSChris Mason btrfs_csum_final(sector_sum->sum, 469e6dcd2dcSChris Mason (char *)§or_sum->sum); 470d20f7043SChris Mason sector_sum->bytenr = disk_bytenr; 471ed98b56aSChris Mason 472e6dcd2dcSChris Mason sector_sum++; 473e015640fSChris Mason bio_index++; 4743edf7d33SChris Mason total_bytes += bvec->bv_len; 4753edf7d33SChris Mason this_sum_bytes += bvec->bv_len; 476d20f7043SChris Mason disk_bytenr += bvec->bv_len; 477d20f7043SChris Mason offset += bvec->bv_len; 478e015640fSChris Mason bvec++; 479e015640fSChris Mason } 480ed98b56aSChris Mason this_sum_bytes = 0; 4813edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4823edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 483e015640fSChris Mason return 0; 484e015640fSChris Mason } 485e015640fSChris Mason 486459931ecSChris Mason /* 487459931ecSChris Mason * helper function for csum removal, this expects the 488459931ecSChris Mason * key to describe the csum pointed to by the path, and it expects 489459931ecSChris Mason * the csum to overlap the range [bytenr, len] 490459931ecSChris Mason * 491459931ecSChris Mason * The csum should not be entirely contained in the range and the 492459931ecSChris Mason * range should not be entirely contained in the csum. 493459931ecSChris Mason * 494459931ecSChris Mason * This calls btrfs_truncate_item with the correct args based on the 495459931ecSChris Mason * overlap, and fixes up the key as required. 496459931ecSChris Mason */ 497143bede5SJeff Mahoney static noinline void truncate_one_csum(struct btrfs_trans_handle *trans, 498459931ecSChris Mason struct btrfs_root *root, 499459931ecSChris Mason struct btrfs_path *path, 500459931ecSChris Mason struct btrfs_key *key, 501459931ecSChris Mason u64 bytenr, u64 len) 502459931ecSChris Mason { 503459931ecSChris Mason struct extent_buffer *leaf; 5046c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 505459931ecSChris Mason u64 csum_end; 506459931ecSChris Mason u64 end_byte = bytenr + len; 507459931ecSChris Mason u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; 508459931ecSChris Mason 509459931ecSChris Mason leaf = path->nodes[0]; 510459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 511459931ecSChris Mason csum_end <<= root->fs_info->sb->s_blocksize_bits; 512459931ecSChris Mason csum_end += key->offset; 513459931ecSChris Mason 514459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 515459931ecSChris Mason /* 516459931ecSChris Mason * [ bytenr - len ] 517459931ecSChris Mason * [ ] 518459931ecSChris Mason * [csum ] 519459931ecSChris Mason * A simple truncate off the end of the item 520459931ecSChris Mason */ 521459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 522459931ecSChris Mason new_size *= csum_size; 523143bede5SJeff Mahoney btrfs_truncate_item(trans, root, path, new_size, 1); 524459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 525459931ecSChris Mason end_byte > key->offset) { 526459931ecSChris Mason /* 527459931ecSChris Mason * [ bytenr - len ] 528459931ecSChris Mason * [ ] 529459931ecSChris Mason * [csum ] 530459931ecSChris Mason * we need to truncate from the beginning of the csum 531459931ecSChris Mason */ 532459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 533459931ecSChris Mason new_size *= csum_size; 534459931ecSChris Mason 535143bede5SJeff Mahoney btrfs_truncate_item(trans, root, path, new_size, 0); 536459931ecSChris Mason 537459931ecSChris Mason key->offset = end_byte; 538143bede5SJeff Mahoney btrfs_set_item_key_safe(trans, root, path, key); 539459931ecSChris Mason } else { 540459931ecSChris Mason BUG(); 541459931ecSChris Mason } 542459931ecSChris Mason } 543459931ecSChris Mason 544459931ecSChris Mason /* 545459931ecSChris Mason * deletes the csum items from the csum tree for a given 546459931ecSChris Mason * range of bytes. 547459931ecSChris Mason */ 548459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 549459931ecSChris Mason struct btrfs_root *root, u64 bytenr, u64 len) 550459931ecSChris Mason { 551459931ecSChris Mason struct btrfs_path *path; 552459931ecSChris Mason struct btrfs_key key; 553459931ecSChris Mason u64 end_byte = bytenr + len; 554459931ecSChris Mason u64 csum_end; 555459931ecSChris Mason struct extent_buffer *leaf; 556459931ecSChris Mason int ret; 5576c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 558459931ecSChris Mason int blocksize_bits = root->fs_info->sb->s_blocksize_bits; 559459931ecSChris Mason 560459931ecSChris Mason root = root->fs_info->csum_root; 561459931ecSChris Mason 562459931ecSChris Mason path = btrfs_alloc_path(); 5632a29edc6Sliubo if (!path) 5642a29edc6Sliubo return -ENOMEM; 565459931ecSChris Mason 566459931ecSChris Mason while (1) { 567459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 568459931ecSChris Mason key.offset = end_byte - 1; 569459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 570459931ecSChris Mason 571b9473439SChris Mason path->leave_spinning = 1; 572459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 573459931ecSChris Mason if (ret > 0) { 574459931ecSChris Mason if (path->slots[0] == 0) 57565a246c5STsutomu Itoh break; 576459931ecSChris Mason path->slots[0]--; 577ad0397a7SJosef Bacik } else if (ret < 0) { 57865a246c5STsutomu Itoh break; 579459931ecSChris Mason } 580ad0397a7SJosef Bacik 581459931ecSChris Mason leaf = path->nodes[0]; 582459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 583459931ecSChris Mason 584459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 585459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 586459931ecSChris Mason break; 587459931ecSChris Mason } 588459931ecSChris Mason 589459931ecSChris Mason if (key.offset >= end_byte) 590459931ecSChris Mason break; 591459931ecSChris Mason 592459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 593459931ecSChris Mason csum_end <<= blocksize_bits; 594459931ecSChris Mason csum_end += key.offset; 595459931ecSChris Mason 596459931ecSChris Mason /* this csum ends before we start, we're done */ 597459931ecSChris Mason if (csum_end <= bytenr) 598459931ecSChris Mason break; 599459931ecSChris Mason 600459931ecSChris Mason /* delete the entire item, it is inside our range */ 601459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 602459931ecSChris Mason ret = btrfs_del_item(trans, root, path); 60365a246c5STsutomu Itoh if (ret) 60465a246c5STsutomu Itoh goto out; 605dcbdd4dcSChris Mason if (key.offset == bytenr) 606dcbdd4dcSChris Mason break; 607459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 608459931ecSChris Mason unsigned long offset; 609459931ecSChris Mason unsigned long shift_len; 610459931ecSChris Mason unsigned long item_offset; 611459931ecSChris Mason /* 612459931ecSChris Mason * [ bytenr - len ] 613459931ecSChris Mason * [csum ] 614459931ecSChris Mason * 615459931ecSChris Mason * Our bytes are in the middle of the csum, 616459931ecSChris Mason * we need to split this item and insert a new one. 617459931ecSChris Mason * 618459931ecSChris Mason * But we can't drop the path because the 619459931ecSChris Mason * csum could change, get removed, extended etc. 620459931ecSChris Mason * 621459931ecSChris Mason * The trick here is the max size of a csum item leaves 622459931ecSChris Mason * enough room in the tree block for a single 623459931ecSChris Mason * item header. So, we split the item in place, 624459931ecSChris Mason * adding a new header pointing to the existing 625459931ecSChris Mason * bytes. Then we loop around again and we have 626459931ecSChris Mason * a nicely formed csum item that we can neatly 627459931ecSChris Mason * truncate. 628459931ecSChris Mason */ 629459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 630459931ecSChris Mason offset *= csum_size; 631459931ecSChris Mason 632459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 633459931ecSChris Mason 634459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 635459931ecSChris Mason path->slots[0]); 636459931ecSChris Mason 637459931ecSChris Mason memset_extent_buffer(leaf, 0, item_offset + offset, 638459931ecSChris Mason shift_len); 639459931ecSChris Mason key.offset = bytenr; 640459931ecSChris Mason 641459931ecSChris Mason /* 642459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 643459931ecSChris Mason * item changed size or key 644459931ecSChris Mason */ 645459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 646*79787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 647*79787eaaSJeff Mahoney btrfs_abort_transaction(trans, root, ret); 648*79787eaaSJeff Mahoney goto out; 649*79787eaaSJeff Mahoney } 650459931ecSChris Mason 651459931ecSChris Mason key.offset = end_byte - 1; 652459931ecSChris Mason } else { 653143bede5SJeff Mahoney truncate_one_csum(trans, root, path, &key, bytenr, len); 654dcbdd4dcSChris Mason if (key.offset < bytenr) 655dcbdd4dcSChris Mason break; 656459931ecSChris Mason } 657b3b4aa74SDavid Sterba btrfs_release_path(path); 658459931ecSChris Mason } 65965a246c5STsutomu Itoh ret = 0; 660459931ecSChris Mason out: 661459931ecSChris Mason btrfs_free_path(path); 66265a246c5STsutomu Itoh return ret; 663459931ecSChris Mason } 664459931ecSChris Mason 665065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 666d20f7043SChris Mason struct btrfs_root *root, 667e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 668f254e52cSChris Mason { 669d20f7043SChris Mason u64 bytenr; 670f254e52cSChris Mason int ret; 671f254e52cSChris Mason struct btrfs_key file_key; 6726567e837SChris Mason struct btrfs_key found_key; 673065631f6SChris Mason u64 next_offset; 674e6dcd2dcSChris Mason u64 total_bytes = 0; 675065631f6SChris Mason int found_next; 6765caf2a00SChris Mason struct btrfs_path *path; 677f254e52cSChris Mason struct btrfs_csum_item *item; 678065631f6SChris Mason struct btrfs_csum_item *item_end; 679ff79f819SChris Mason struct extent_buffer *leaf = NULL; 6806567e837SChris Mason u64 csum_offset; 681e6dcd2dcSChris Mason struct btrfs_sector_sum *sector_sum; 682f578d4bdSChris Mason u32 nritems; 683f578d4bdSChris Mason u32 ins_size; 6846c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 6856e92f5e6SChris Mason 6865caf2a00SChris Mason path = btrfs_alloc_path(); 687d8926bb3SMark Fasheh if (!path) 688d8926bb3SMark Fasheh return -ENOMEM; 689d8926bb3SMark Fasheh 690ed98b56aSChris Mason sector_sum = sums->sums; 691065631f6SChris Mason again: 692065631f6SChris Mason next_offset = (u64)-1; 693065631f6SChris Mason found_next = 0; 694d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 695d20f7043SChris Mason file_key.offset = sector_sum->bytenr; 696d20f7043SChris Mason bytenr = sector_sum->bytenr; 697d20f7043SChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); 698a429e513SChris Mason 699d20f7043SChris Mason item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1); 700ff79f819SChris Mason if (!IS_ERR(item)) { 701ff79f819SChris Mason leaf = path->nodes[0]; 702639cb586SChris Mason ret = 0; 703a429e513SChris Mason goto found; 704ff79f819SChris Mason } 705a429e513SChris Mason ret = PTR_ERR(item); 7064a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7074a500fd1SYan, Zheng goto fail_unlock; 7084a500fd1SYan, Zheng 709a429e513SChris Mason if (ret == -EFBIG) { 710a429e513SChris Mason u32 item_size; 711a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7125f39d397SChris Mason leaf = path->nodes[0]; 7135f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 714607d432dSJosef Bacik if ((item_size / csum_size) >= 715607d432dSJosef Bacik MAX_CSUM_ITEMS(root, csum_size)) { 716a429e513SChris Mason /* already at max size, make a new one */ 717a429e513SChris Mason goto insert; 718a429e513SChris Mason } 719a429e513SChris Mason } else { 720f578d4bdSChris Mason int slot = path->slots[0] + 1; 721a429e513SChris Mason /* we didn't find a csum item, insert one */ 722f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 723f578d4bdSChris Mason if (path->slots[0] >= nritems - 1) { 724f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 725b56baf5bSYan if (ret == 1) 726f578d4bdSChris Mason found_next = 1; 727b56baf5bSYan if (ret != 0) 728f578d4bdSChris Mason goto insert; 729b56baf5bSYan slot = 0; 730f578d4bdSChris Mason } 731f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 732d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 733d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 734f578d4bdSChris Mason found_next = 1; 735f578d4bdSChris Mason goto insert; 736f578d4bdSChris Mason } 737f578d4bdSChris Mason next_offset = found_key.offset; 738f578d4bdSChris Mason found_next = 1; 739a429e513SChris Mason goto insert; 740a429e513SChris Mason } 741a429e513SChris Mason 742a429e513SChris Mason /* 743a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 744a429e513SChris Mason * enough yet to put our csum in. Grow it 745a429e513SChris Mason */ 746b3b4aa74SDavid Sterba btrfs_release_path(path); 7476567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 748607d432dSJosef Bacik csum_size, 1); 7496567e837SChris Mason if (ret < 0) 75053863232SChris Mason goto fail_unlock; 751459931ecSChris Mason 752459931ecSChris Mason if (ret > 0) { 753459931ecSChris Mason if (path->slots[0] == 0) 7546567e837SChris Mason goto insert; 7556567e837SChris Mason path->slots[0]--; 756459931ecSChris Mason } 757459931ecSChris Mason 7585f39d397SChris Mason leaf = path->nodes[0]; 7595f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 760d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 7616567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 762459931ecSChris Mason 763d20f7043SChris Mason if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || 764d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 765607d432dSJosef Bacik csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { 7666567e837SChris Mason goto insert; 7676567e837SChris Mason } 768459931ecSChris Mason 7695f39d397SChris Mason if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / 770607d432dSJosef Bacik csum_size) { 771607d432dSJosef Bacik u32 diff = (csum_offset + 1) * csum_size; 772459931ecSChris Mason 773459931ecSChris Mason /* 774459931ecSChris Mason * is the item big enough already? we dropped our lock 775459931ecSChris Mason * before and need to recheck 776459931ecSChris Mason */ 777459931ecSChris Mason if (diff < btrfs_item_size_nr(leaf, path->slots[0])) 778459931ecSChris Mason goto csum; 779459931ecSChris Mason 7805f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 781d397712bSChris Mason if (diff != csum_size) 7823a686375SChris Mason goto insert; 783459931ecSChris Mason 784143bede5SJeff Mahoney btrfs_extend_item(trans, root, path, diff); 7856567e837SChris Mason goto csum; 7866567e837SChris Mason } 7876567e837SChris Mason 7886567e837SChris Mason insert: 789b3b4aa74SDavid Sterba btrfs_release_path(path); 7906567e837SChris Mason csum_offset = 0; 791f578d4bdSChris Mason if (found_next) { 792d20f7043SChris Mason u64 tmp = total_bytes + root->sectorsize; 793d20f7043SChris Mason u64 next_sector = sector_sum->bytenr; 794d20f7043SChris Mason struct btrfs_sector_sum *next = sector_sum + 1; 795d20f7043SChris Mason 796d20f7043SChris Mason while (tmp < sums->len) { 797d20f7043SChris Mason if (next_sector + root->sectorsize != next->bytenr) 798d20f7043SChris Mason break; 799d20f7043SChris Mason tmp += root->sectorsize; 800d20f7043SChris Mason next_sector = next->bytenr; 801d20f7043SChris Mason next++; 802d20f7043SChris Mason } 803d20f7043SChris Mason tmp = min(tmp, next_offset - file_key.offset); 804f578d4bdSChris Mason tmp >>= root->fs_info->sb->s_blocksize_bits; 805f578d4bdSChris Mason tmp = max((u64)1, tmp); 806607d432dSJosef Bacik tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); 807607d432dSJosef Bacik ins_size = csum_size * tmp; 808f578d4bdSChris Mason } else { 809607d432dSJosef Bacik ins_size = csum_size; 810f578d4bdSChris Mason } 811b9473439SChris Mason path->leave_spinning = 1; 8125caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 813f578d4bdSChris Mason ins_size); 814b9473439SChris Mason path->leave_spinning = 0; 81554aa1f4dSChris Mason if (ret < 0) 81653863232SChris Mason goto fail_unlock; 817a429e513SChris Mason if (ret != 0) { 818a429e513SChris Mason WARN_ON(1); 81953863232SChris Mason goto fail_unlock; 820a429e513SChris Mason } 8216567e837SChris Mason csum: 8225f39d397SChris Mason leaf = path->nodes[0]; 8235f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 824f254e52cSChris Mason ret = 0; 825509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 826607d432dSJosef Bacik csum_offset * csum_size); 827b18c6685SChris Mason found: 828065631f6SChris Mason item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 829065631f6SChris Mason item_end = (struct btrfs_csum_item *)((unsigned char *)item_end + 830065631f6SChris Mason btrfs_item_size_nr(leaf, path->slots[0])); 831e6dcd2dcSChris Mason next_sector: 832aadfeb6eSChris Mason 833a6591715SChris Mason write_extent_buffer(leaf, §or_sum->sum, (unsigned long)item, csum_size); 8347f3c74fbSChris Mason 835e6dcd2dcSChris Mason total_bytes += root->sectorsize; 836e6dcd2dcSChris Mason sector_sum++; 837e6dcd2dcSChris Mason if (total_bytes < sums->len) { 8386e92f5e6SChris Mason item = (struct btrfs_csum_item *)((char *)item + 839607d432dSJosef Bacik csum_size); 840d20f7043SChris Mason if (item < item_end && bytenr + PAGE_CACHE_SIZE == 841d20f7043SChris Mason sector_sum->bytenr) { 842d20f7043SChris Mason bytenr = sector_sum->bytenr; 843e6dcd2dcSChris Mason goto next_sector; 844065631f6SChris Mason } 8452e1a992eSChris Mason } 846a6591715SChris Mason 8475caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 848e6dcd2dcSChris Mason if (total_bytes < sums->len) { 849b3b4aa74SDavid Sterba btrfs_release_path(path); 850b9473439SChris Mason cond_resched(); 851065631f6SChris Mason goto again; 852065631f6SChris Mason } 85353863232SChris Mason out: 8545caf2a00SChris Mason btrfs_free_path(path); 855f254e52cSChris Mason return ret; 85653863232SChris Mason 85753863232SChris Mason fail_unlock: 85853863232SChris Mason goto out; 859f254e52cSChris Mason } 860