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 28995e01b7SJan Schmidt #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ 29a429e513SChris Mason sizeof(struct btrfs_item) * 2) / \ 30607d432dSJosef Bacik size) - 1)) 3107d400a6SYan Zheng 32221b8318SZach Brown #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ 33221b8318SZach Brown PAGE_CACHE_SIZE)) 347ca4be45SChris Mason 3507d400a6SYan Zheng #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ 3607d400a6SYan Zheng sizeof(struct btrfs_ordered_sum)) / \ 37*f51a4a18SMiao Xie sizeof(u32) * (r)->sectorsize) 3807d400a6SYan Zheng 39b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 40dee26a9fSChris Mason struct btrfs_root *root, 41b18c6685SChris Mason u64 objectid, u64 pos, 42f2eb0a24SSage Weil u64 disk_offset, u64 disk_num_bytes, 43c8b97818SChris Mason u64 num_bytes, u64 offset, u64 ram_bytes, 44c8b97818SChris Mason u8 compression, u8 encryption, u16 other_encoding) 459f5fae2fSChris Mason { 46dee26a9fSChris Mason int ret = 0; 47dee26a9fSChris Mason struct btrfs_file_extent_item *item; 48dee26a9fSChris Mason struct btrfs_key file_key; 495caf2a00SChris Mason struct btrfs_path *path; 505f39d397SChris Mason struct extent_buffer *leaf; 51dee26a9fSChris Mason 525caf2a00SChris Mason path = btrfs_alloc_path(); 53db5b493aSTsutomu Itoh if (!path) 54db5b493aSTsutomu Itoh return -ENOMEM; 55dee26a9fSChris Mason file_key.objectid = objectid; 56b18c6685SChris Mason file_key.offset = pos; 57dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 58dee26a9fSChris Mason 59b9473439SChris Mason path->leave_spinning = 1; 605caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 61dee26a9fSChris Mason sizeof(*item)); 6254aa1f4dSChris Mason if (ret < 0) 6354aa1f4dSChris Mason goto out; 6479787eaaSJeff Mahoney BUG_ON(ret); /* Can't happen */ 655f39d397SChris Mason leaf = path->nodes[0]; 665f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], 67dee26a9fSChris Mason struct btrfs_file_extent_item); 68f2eb0a24SSage Weil btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); 69db94535dSChris Mason btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 70f2eb0a24SSage Weil btrfs_set_file_extent_offset(leaf, item, offset); 71db94535dSChris Mason btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 72c8b97818SChris Mason btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); 735f39d397SChris Mason btrfs_set_file_extent_generation(leaf, item, trans->transid); 745f39d397SChris Mason btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 75c8b97818SChris Mason btrfs_set_file_extent_compression(leaf, item, compression); 76c8b97818SChris Mason btrfs_set_file_extent_encryption(leaf, item, encryption); 77c8b97818SChris Mason btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); 78c8b97818SChris Mason 795f39d397SChris Mason btrfs_mark_buffer_dirty(leaf); 8054aa1f4dSChris Mason out: 815caf2a00SChris Mason btrfs_free_path(path); 8254aa1f4dSChris Mason return ret; 839f5fae2fSChris Mason } 84dee26a9fSChris Mason 8548a3b636SEric Sandeen static struct btrfs_csum_item * 8648a3b636SEric Sandeen btrfs_lookup_csum(struct btrfs_trans_handle *trans, 87b18c6685SChris Mason struct btrfs_root *root, 886567e837SChris Mason struct btrfs_path *path, 89d20f7043SChris Mason u64 bytenr, int cow) 906567e837SChris Mason { 916567e837SChris Mason int ret; 926567e837SChris Mason struct btrfs_key file_key; 936567e837SChris Mason struct btrfs_key found_key; 946567e837SChris Mason struct btrfs_csum_item *item; 955f39d397SChris Mason struct extent_buffer *leaf; 966567e837SChris Mason u64 csum_offset = 0; 976c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 98a429e513SChris Mason int csums_in_item; 996567e837SChris Mason 100d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 101d20f7043SChris Mason file_key.offset = bytenr; 102d20f7043SChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); 103b18c6685SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 1046567e837SChris Mason if (ret < 0) 1056567e837SChris Mason goto fail; 1065f39d397SChris Mason leaf = path->nodes[0]; 1076567e837SChris Mason if (ret > 0) { 1086567e837SChris Mason ret = 1; 10970b2befdSChris Mason if (path->slots[0] == 0) 1106567e837SChris Mason goto fail; 1116567e837SChris Mason path->slots[0]--; 1125f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 113d20f7043SChris Mason if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY) 1146567e837SChris Mason goto fail; 115d20f7043SChris Mason 116d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 1176567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 1185f39d397SChris Mason csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 119607d432dSJosef Bacik csums_in_item /= csum_size; 120a429e513SChris Mason 12182d130ffSMiao Xie if (csum_offset == csums_in_item) { 122a429e513SChris Mason ret = -EFBIG; 1236567e837SChris Mason goto fail; 12482d130ffSMiao Xie } else if (csum_offset > csums_in_item) { 12582d130ffSMiao Xie goto fail; 1266567e837SChris Mason } 1276567e837SChris Mason } 1286567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 129509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 130607d432dSJosef Bacik csum_offset * csum_size); 1316567e837SChris Mason return item; 1326567e837SChris Mason fail: 1336567e837SChris Mason if (ret > 0) 134b18c6685SChris Mason ret = -ENOENT; 1356567e837SChris Mason return ERR_PTR(ret); 1366567e837SChris Mason } 1376567e837SChris Mason 138dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 139dee26a9fSChris Mason struct btrfs_root *root, 140dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1419773a788SChris Mason u64 offset, int mod) 142dee26a9fSChris Mason { 143dee26a9fSChris Mason int ret; 144dee26a9fSChris Mason struct btrfs_key file_key; 145dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 146dee26a9fSChris Mason int cow = mod != 0; 147dee26a9fSChris Mason 148dee26a9fSChris Mason file_key.objectid = objectid; 14970b2befdSChris Mason file_key.offset = offset; 150dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 151dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 152dee26a9fSChris Mason return ret; 153dee26a9fSChris Mason } 154f254e52cSChris Mason 1554b46fce2SJosef Bacik static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 1564b46fce2SJosef Bacik struct inode *inode, struct bio *bio, 1574b46fce2SJosef Bacik u64 logical_offset, u32 *dst, int dio) 15861b49440SChris Mason { 159e4100d98SMiao Xie u32 sum[16]; 160e4100d98SMiao Xie int len; 16161b49440SChris Mason struct bio_vec *bvec = bio->bi_io_vec; 16261b49440SChris Mason int bio_index = 0; 1634b46fce2SJosef Bacik u64 offset = 0; 16461b49440SChris Mason u64 item_start_offset = 0; 16561b49440SChris Mason u64 item_last_offset = 0; 166d20f7043SChris Mason u64 disk_bytenr; 16761b49440SChris Mason u32 diff; 1686c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 169e4100d98SMiao Xie int count; 17061b49440SChris Mason struct btrfs_path *path; 17161b49440SChris Mason struct btrfs_csum_item *item = NULL; 17261b49440SChris Mason struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 17361b49440SChris Mason 17461b49440SChris Mason path = btrfs_alloc_path(); 175c2db1073STsutomu Itoh if (!path) 176c2db1073STsutomu Itoh return -ENOMEM; 1774d1b5fb4SChris Mason if (bio->bi_size > PAGE_CACHE_SIZE * 8) 1784d1b5fb4SChris Mason path->reada = 2; 17961b49440SChris Mason 18061b49440SChris Mason WARN_ON(bio->bi_vcnt <= 0); 18161b49440SChris Mason 1822cf8572dSChris Mason /* 1832cf8572dSChris Mason * the free space stuff is only read when it hasn't been 1842cf8572dSChris Mason * updated in the current transaction. So, we can safely 1852cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 1862cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 1872cf8572dSChris Mason */ 18883eea1f1SLiu Bo if (btrfs_is_free_space_inode(inode)) { 1892cf8572dSChris Mason path->search_commit_root = 1; 190ddf23b3fSJosef Bacik path->skip_locking = 1; 191ddf23b3fSJosef Bacik } 1922cf8572dSChris Mason 193d20f7043SChris Mason disk_bytenr = (u64)bio->bi_sector << 9; 1944b46fce2SJosef Bacik if (dio) 1954b46fce2SJosef Bacik offset = logical_offset; 19661b49440SChris Mason while (bio_index < bio->bi_vcnt) { 197e4100d98SMiao Xie len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index); 1984b46fce2SJosef Bacik if (!dio) 19961b49440SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 200e4100d98SMiao Xie count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum, 201e4100d98SMiao Xie len); 202e4100d98SMiao Xie if (count) 20361b49440SChris Mason goto found; 20461b49440SChris Mason 205d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 206d20f7043SChris Mason disk_bytenr >= item_last_offset) { 20761b49440SChris Mason struct btrfs_key found_key; 20861b49440SChris Mason u32 item_size; 20961b49440SChris Mason 21061b49440SChris Mason if (item) 211b3b4aa74SDavid Sterba btrfs_release_path(path); 212d20f7043SChris Mason item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, 213d20f7043SChris Mason path, disk_bytenr, 0); 21461b49440SChris Mason if (IS_ERR(item)) { 215e4100d98SMiao Xie count = 1; 216e4100d98SMiao Xie sum[0] = 0; 21717d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 21817d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 21917d217feSYan Zheng set_extent_bits(io_tree, offset, 22017d217feSYan Zheng offset + bvec->bv_len - 1, 22117d217feSYan Zheng EXTENT_NODATASUM, GFP_NOFS); 22217d217feSYan Zheng } else { 223d397712bSChris Mason printk(KERN_INFO "btrfs no csum found " 22433345d01SLi Zefan "for inode %llu start %llu\n", 22533345d01SLi Zefan (unsigned long long) 22633345d01SLi Zefan btrfs_ino(inode), 22761b49440SChris Mason (unsigned long long)offset); 22817d217feSYan Zheng } 2296dab8157SChris Mason item = NULL; 230b3b4aa74SDavid Sterba btrfs_release_path(path); 23161b49440SChris Mason goto found; 23261b49440SChris Mason } 23361b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 23461b49440SChris Mason path->slots[0]); 23561b49440SChris Mason 23661b49440SChris Mason item_start_offset = found_key.offset; 23761b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 23861b49440SChris Mason path->slots[0]); 23961b49440SChris Mason item_last_offset = item_start_offset + 240607d432dSJosef Bacik (item_size / csum_size) * 24161b49440SChris Mason root->sectorsize; 24261b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 24361b49440SChris Mason struct btrfs_csum_item); 24461b49440SChris Mason } 24561b49440SChris Mason /* 24661b49440SChris Mason * this byte range must be able to fit inside 24761b49440SChris Mason * a single leaf so it will also fit inside a u32 24861b49440SChris Mason */ 249d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 25061b49440SChris Mason diff = diff / root->sectorsize; 251607d432dSJosef Bacik diff = diff * csum_size; 252e4100d98SMiao Xie count = min_t(int, len, (item_last_offset - disk_bytenr) >> 253e4100d98SMiao Xie inode->i_sb->s_blocksize_bits); 254e4100d98SMiao Xie read_extent_buffer(path->nodes[0], sum, 2553de9d6b6SChris Mason ((unsigned long)item) + diff, 256e4100d98SMiao Xie csum_size * count); 25761b49440SChris Mason found: 258e4100d98SMiao Xie if (dst) { 259e4100d98SMiao Xie memcpy(dst, sum, count * csum_size); 260e4100d98SMiao Xie dst += count; 261e4100d98SMiao Xie } else { 262e4100d98SMiao Xie if (dio) 263e4100d98SMiao Xie extent_cache_csums_dio(io_tree, offset, sum, 264e4100d98SMiao Xie count); 265d20f7043SChris Mason else 266e4100d98SMiao Xie extent_cache_csums(io_tree, bio, bio_index, sum, 267e4100d98SMiao Xie count); 268e4100d98SMiao Xie } 269e4100d98SMiao Xie while (count--) { 270d20f7043SChris Mason disk_bytenr += bvec->bv_len; 2714b46fce2SJosef Bacik offset += bvec->bv_len; 27261b49440SChris Mason bio_index++; 27361b49440SChris Mason bvec++; 27461b49440SChris Mason } 275e4100d98SMiao Xie } 27661b49440SChris Mason btrfs_free_path(path); 27761b49440SChris Mason return 0; 27861b49440SChris Mason } 27961b49440SChris Mason 2804b46fce2SJosef Bacik int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 2814b46fce2SJosef Bacik struct bio *bio, u32 *dst) 2824b46fce2SJosef Bacik { 2834b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); 2844b46fce2SJosef Bacik } 2854b46fce2SJosef Bacik 2864b46fce2SJosef Bacik int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 287c329861dSJosef Bacik struct bio *bio, u64 offset) 2884b46fce2SJosef Bacik { 289c329861dSJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); 2904b46fce2SJosef Bacik } 2914b46fce2SJosef Bacik 29217d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 293a2de733cSArne Jansen struct list_head *list, int search_commit) 29417d217feSYan Zheng { 29517d217feSYan Zheng struct btrfs_key key; 29617d217feSYan Zheng struct btrfs_path *path; 29717d217feSYan Zheng struct extent_buffer *leaf; 29817d217feSYan Zheng struct btrfs_ordered_sum *sums; 29917d217feSYan Zheng struct btrfs_csum_item *item; 3000678b618SMark Fasheh LIST_HEAD(tmplist); 30117d217feSYan Zheng unsigned long offset; 30217d217feSYan Zheng int ret; 30317d217feSYan Zheng size_t size; 30417d217feSYan Zheng u64 csum_end; 3056c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 30617d217feSYan Zheng 30717d217feSYan Zheng path = btrfs_alloc_path(); 308d8926bb3SMark Fasheh if (!path) 309d8926bb3SMark Fasheh return -ENOMEM; 31017d217feSYan Zheng 311a2de733cSArne Jansen if (search_commit) { 312a2de733cSArne Jansen path->skip_locking = 1; 313a2de733cSArne Jansen path->reada = 2; 314a2de733cSArne Jansen path->search_commit_root = 1; 315a2de733cSArne Jansen } 316a2de733cSArne Jansen 31717d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 31817d217feSYan Zheng key.offset = start; 31917d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 32017d217feSYan Zheng 32107d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 32217d217feSYan Zheng if (ret < 0) 32317d217feSYan Zheng goto fail; 32417d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 32517d217feSYan Zheng leaf = path->nodes[0]; 32617d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 32717d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 32817d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 32917d217feSYan Zheng offset = (start - key.offset) >> 33017d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 33117d217feSYan Zheng if (offset * csum_size < 33217d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 33317d217feSYan Zheng path->slots[0]--; 33417d217feSYan Zheng } 33517d217feSYan Zheng } 33617d217feSYan Zheng 33717d217feSYan Zheng while (start <= end) { 33817d217feSYan Zheng leaf = path->nodes[0]; 33917d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 34007d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 34117d217feSYan Zheng if (ret < 0) 34217d217feSYan Zheng goto fail; 34317d217feSYan Zheng if (ret > 0) 34417d217feSYan Zheng break; 34517d217feSYan Zheng leaf = path->nodes[0]; 34617d217feSYan Zheng } 34717d217feSYan Zheng 34817d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 34917d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 350628c8282SZhi Yong Wu key.type != BTRFS_EXTENT_CSUM_KEY || 351628c8282SZhi Yong Wu key.offset > end) 35217d217feSYan Zheng break; 35317d217feSYan Zheng 35417d217feSYan Zheng if (key.offset > start) 35517d217feSYan Zheng start = key.offset; 35617d217feSYan Zheng 35717d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 35817d217feSYan Zheng csum_end = key.offset + (size / csum_size) * root->sectorsize; 35987b29b20SYan Zheng if (csum_end <= start) { 36087b29b20SYan Zheng path->slots[0]++; 36187b29b20SYan Zheng continue; 36287b29b20SYan Zheng } 36317d217feSYan Zheng 36407d400a6SYan Zheng csum_end = min(csum_end, end + 1); 36507d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 36607d400a6SYan Zheng struct btrfs_csum_item); 36707d400a6SYan Zheng while (start < csum_end) { 36807d400a6SYan Zheng size = min_t(size_t, csum_end - start, 36907d400a6SYan Zheng MAX_ORDERED_SUM_BYTES(root)); 37007d400a6SYan Zheng sums = kzalloc(btrfs_ordered_sum_size(root, size), 37107d400a6SYan Zheng GFP_NOFS); 3720678b618SMark Fasheh if (!sums) { 3730678b618SMark Fasheh ret = -ENOMEM; 3740678b618SMark Fasheh goto fail; 3750678b618SMark Fasheh } 37617d217feSYan Zheng 37717d217feSYan Zheng sums->bytenr = start; 378*f51a4a18SMiao Xie sums->len = (int)size; 37917d217feSYan Zheng 38017d217feSYan Zheng offset = (start - key.offset) >> 38117d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 38217d217feSYan Zheng offset *= csum_size; 383*f51a4a18SMiao Xie size >>= root->fs_info->sb->s_blocksize_bits; 38417d217feSYan Zheng 38507d400a6SYan Zheng read_extent_buffer(path->nodes[0], 386*f51a4a18SMiao Xie sums->sums, 387*f51a4a18SMiao Xie ((unsigned long)item) + offset, 388*f51a4a18SMiao Xie csum_size * size); 38917d217feSYan Zheng 390*f51a4a18SMiao Xie start += root->sectorsize * size; 3910678b618SMark Fasheh list_add_tail(&sums->list, &tmplist); 39207d400a6SYan Zheng } 39317d217feSYan Zheng path->slots[0]++; 39417d217feSYan Zheng } 39517d217feSYan Zheng ret = 0; 39617d217feSYan Zheng fail: 3970678b618SMark Fasheh while (ret < 0 && !list_empty(&tmplist)) { 3980678b618SMark Fasheh sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); 3990678b618SMark Fasheh list_del(&sums->list); 4000678b618SMark Fasheh kfree(sums); 4010678b618SMark Fasheh } 4020678b618SMark Fasheh list_splice_tail(&tmplist, list); 4030678b618SMark Fasheh 40417d217feSYan Zheng btrfs_free_path(path); 40517d217feSYan Zheng return ret; 40617d217feSYan Zheng } 40717d217feSYan Zheng 4083edf7d33SChris Mason int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 409d20f7043SChris Mason struct bio *bio, u64 file_start, int contig) 410e015640fSChris Mason { 411e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums; 4123edf7d33SChris Mason struct btrfs_ordered_extent *ordered; 413e015640fSChris Mason char *data; 414e015640fSChris Mason struct bio_vec *bvec = bio->bi_io_vec; 415e015640fSChris Mason int bio_index = 0; 416*f51a4a18SMiao Xie int index; 4173edf7d33SChris Mason unsigned long total_bytes = 0; 4183edf7d33SChris Mason unsigned long this_sum_bytes = 0; 4193edf7d33SChris Mason u64 offset; 420e015640fSChris Mason 421e6dcd2dcSChris Mason WARN_ON(bio->bi_vcnt <= 0); 422e6dcd2dcSChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); 423e015640fSChris Mason if (!sums) 424e015640fSChris Mason return -ENOMEM; 4253edf7d33SChris Mason 426e6dcd2dcSChris Mason sums->len = bio->bi_size; 427e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 428d20f7043SChris Mason 429d20f7043SChris Mason if (contig) 430d20f7043SChris Mason offset = file_start; 431d20f7043SChris Mason else 432d20f7043SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 433d20f7043SChris Mason 434d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 43579787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 436*f51a4a18SMiao Xie sums->bytenr = (u64)bio->bi_sector << 9; 437*f51a4a18SMiao Xie index = 0; 438e015640fSChris Mason 439e015640fSChris Mason while (bio_index < bio->bi_vcnt) { 440d20f7043SChris Mason if (!contig) 4413edf7d33SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 442d20f7043SChris Mason 443e58dd74bSJosef Bacik if (offset >= ordered->file_offset + ordered->len || 444e58dd74bSJosef Bacik offset < ordered->file_offset) { 4453edf7d33SChris Mason unsigned long bytes_left; 4463edf7d33SChris Mason sums->len = this_sum_bytes; 4473edf7d33SChris Mason this_sum_bytes = 0; 4483edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4493edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4503edf7d33SChris Mason 4513edf7d33SChris Mason bytes_left = bio->bi_size - total_bytes; 4523edf7d33SChris Mason 4533edf7d33SChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), 4543edf7d33SChris Mason GFP_NOFS); 45579787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 4563edf7d33SChris Mason sums->len = bytes_left; 457d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 45879787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 459*f51a4a18SMiao Xie sums->bytenr = ((u64)bio->bi_sector << 9) + 460*f51a4a18SMiao Xie total_bytes; 461*f51a4a18SMiao Xie index = 0; 4623edf7d33SChris Mason } 4633edf7d33SChris Mason 4647ac687d9SCong Wang data = kmap_atomic(bvec->bv_page); 465*f51a4a18SMiao Xie sums->sums[index] = ~(u32)0; 466*f51a4a18SMiao Xie sums->sums[index] = btrfs_csum_data(data + bvec->bv_offset, 467*f51a4a18SMiao Xie sums->sums[index], 468e6dcd2dcSChris Mason bvec->bv_len); 4697ac687d9SCong Wang kunmap_atomic(data); 470*f51a4a18SMiao Xie btrfs_csum_final(sums->sums[index], 471*f51a4a18SMiao Xie (char *)(sums->sums + index)); 472ed98b56aSChris Mason 473e015640fSChris Mason bio_index++; 474*f51a4a18SMiao Xie index++; 4753edf7d33SChris Mason total_bytes += bvec->bv_len; 4763edf7d33SChris Mason this_sum_bytes += 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 */ 497afe5fea7STsutomu Itoh static noinline void truncate_one_csum(struct btrfs_root *root, 498459931ecSChris Mason struct btrfs_path *path, 499459931ecSChris Mason struct btrfs_key *key, 500459931ecSChris Mason u64 bytenr, u64 len) 501459931ecSChris Mason { 502459931ecSChris Mason struct extent_buffer *leaf; 5036c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 504459931ecSChris Mason u64 csum_end; 505459931ecSChris Mason u64 end_byte = bytenr + len; 506459931ecSChris Mason u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; 507459931ecSChris Mason 508459931ecSChris Mason leaf = path->nodes[0]; 509459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 510459931ecSChris Mason csum_end <<= root->fs_info->sb->s_blocksize_bits; 511459931ecSChris Mason csum_end += key->offset; 512459931ecSChris Mason 513459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 514459931ecSChris Mason /* 515459931ecSChris Mason * [ bytenr - len ] 516459931ecSChris Mason * [ ] 517459931ecSChris Mason * [csum ] 518459931ecSChris Mason * A simple truncate off the end of the item 519459931ecSChris Mason */ 520459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 521459931ecSChris Mason new_size *= csum_size; 522afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 1); 523459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 524459931ecSChris Mason end_byte > key->offset) { 525459931ecSChris Mason /* 526459931ecSChris Mason * [ bytenr - len ] 527459931ecSChris Mason * [ ] 528459931ecSChris Mason * [csum ] 529459931ecSChris Mason * we need to truncate from the beginning of the csum 530459931ecSChris Mason */ 531459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 532459931ecSChris Mason new_size *= csum_size; 533459931ecSChris Mason 534afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 0); 535459931ecSChris Mason 536459931ecSChris Mason key->offset = end_byte; 537afe5fea7STsutomu Itoh btrfs_set_item_key_safe(root, path, key); 538459931ecSChris Mason } else { 539459931ecSChris Mason BUG(); 540459931ecSChris Mason } 541459931ecSChris Mason } 542459931ecSChris Mason 543459931ecSChris Mason /* 544459931ecSChris Mason * deletes the csum items from the csum tree for a given 545459931ecSChris Mason * range of bytes. 546459931ecSChris Mason */ 547459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 548459931ecSChris Mason struct btrfs_root *root, u64 bytenr, u64 len) 549459931ecSChris Mason { 550459931ecSChris Mason struct btrfs_path *path; 551459931ecSChris Mason struct btrfs_key key; 552459931ecSChris Mason u64 end_byte = bytenr + len; 553459931ecSChris Mason u64 csum_end; 554459931ecSChris Mason struct extent_buffer *leaf; 555459931ecSChris Mason int ret; 5566c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 557459931ecSChris Mason int blocksize_bits = root->fs_info->sb->s_blocksize_bits; 558459931ecSChris Mason 559459931ecSChris Mason root = root->fs_info->csum_root; 560459931ecSChris Mason 561459931ecSChris Mason path = btrfs_alloc_path(); 5622a29edc6Sliubo if (!path) 5632a29edc6Sliubo return -ENOMEM; 564459931ecSChris Mason 565459931ecSChris Mason while (1) { 566459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 567459931ecSChris Mason key.offset = end_byte - 1; 568459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 569459931ecSChris Mason 570b9473439SChris Mason path->leave_spinning = 1; 571459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 572459931ecSChris Mason if (ret > 0) { 573459931ecSChris Mason if (path->slots[0] == 0) 57465a246c5STsutomu Itoh break; 575459931ecSChris Mason path->slots[0]--; 576ad0397a7SJosef Bacik } else if (ret < 0) { 57765a246c5STsutomu Itoh break; 578459931ecSChris Mason } 579ad0397a7SJosef Bacik 580459931ecSChris Mason leaf = path->nodes[0]; 581459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 582459931ecSChris Mason 583459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 584459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 585459931ecSChris Mason break; 586459931ecSChris Mason } 587459931ecSChris Mason 588459931ecSChris Mason if (key.offset >= end_byte) 589459931ecSChris Mason break; 590459931ecSChris Mason 591459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 592459931ecSChris Mason csum_end <<= blocksize_bits; 593459931ecSChris Mason csum_end += key.offset; 594459931ecSChris Mason 595459931ecSChris Mason /* this csum ends before we start, we're done */ 596459931ecSChris Mason if (csum_end <= bytenr) 597459931ecSChris Mason break; 598459931ecSChris Mason 599459931ecSChris Mason /* delete the entire item, it is inside our range */ 600459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 601459931ecSChris Mason ret = btrfs_del_item(trans, root, path); 60265a246c5STsutomu Itoh if (ret) 60365a246c5STsutomu Itoh goto out; 604dcbdd4dcSChris Mason if (key.offset == bytenr) 605dcbdd4dcSChris Mason break; 606459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 607459931ecSChris Mason unsigned long offset; 608459931ecSChris Mason unsigned long shift_len; 609459931ecSChris Mason unsigned long item_offset; 610459931ecSChris Mason /* 611459931ecSChris Mason * [ bytenr - len ] 612459931ecSChris Mason * [csum ] 613459931ecSChris Mason * 614459931ecSChris Mason * Our bytes are in the middle of the csum, 615459931ecSChris Mason * we need to split this item and insert a new one. 616459931ecSChris Mason * 617459931ecSChris Mason * But we can't drop the path because the 618459931ecSChris Mason * csum could change, get removed, extended etc. 619459931ecSChris Mason * 620459931ecSChris Mason * The trick here is the max size of a csum item leaves 621459931ecSChris Mason * enough room in the tree block for a single 622459931ecSChris Mason * item header. So, we split the item in place, 623459931ecSChris Mason * adding a new header pointing to the existing 624459931ecSChris Mason * bytes. Then we loop around again and we have 625459931ecSChris Mason * a nicely formed csum item that we can neatly 626459931ecSChris Mason * truncate. 627459931ecSChris Mason */ 628459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 629459931ecSChris Mason offset *= csum_size; 630459931ecSChris Mason 631459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 632459931ecSChris Mason 633459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 634459931ecSChris Mason path->slots[0]); 635459931ecSChris Mason 636459931ecSChris Mason memset_extent_buffer(leaf, 0, item_offset + offset, 637459931ecSChris Mason shift_len); 638459931ecSChris Mason key.offset = bytenr; 639459931ecSChris Mason 640459931ecSChris Mason /* 641459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 642459931ecSChris Mason * item changed size or key 643459931ecSChris Mason */ 644459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 64579787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 64679787eaaSJeff Mahoney btrfs_abort_transaction(trans, root, ret); 64779787eaaSJeff Mahoney goto out; 64879787eaaSJeff Mahoney } 649459931ecSChris Mason 650459931ecSChris Mason key.offset = end_byte - 1; 651459931ecSChris Mason } else { 652afe5fea7STsutomu Itoh truncate_one_csum(root, path, &key, bytenr, len); 653dcbdd4dcSChris Mason if (key.offset < bytenr) 654dcbdd4dcSChris Mason break; 655459931ecSChris Mason } 656b3b4aa74SDavid Sterba btrfs_release_path(path); 657459931ecSChris Mason } 65865a246c5STsutomu Itoh ret = 0; 659459931ecSChris Mason out: 660459931ecSChris Mason btrfs_free_path(path); 66165a246c5STsutomu Itoh return ret; 662459931ecSChris Mason } 663459931ecSChris Mason 664065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 665d20f7043SChris Mason struct btrfs_root *root, 666e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 667f254e52cSChris Mason { 668f254e52cSChris Mason struct btrfs_key file_key; 6696567e837SChris Mason struct btrfs_key found_key; 6705caf2a00SChris Mason struct btrfs_path *path; 671f254e52cSChris Mason struct btrfs_csum_item *item; 672065631f6SChris Mason struct btrfs_csum_item *item_end; 673ff79f819SChris Mason struct extent_buffer *leaf = NULL; 674*f51a4a18SMiao Xie u64 next_offset; 675*f51a4a18SMiao Xie u64 total_bytes = 0; 6766567e837SChris Mason u64 csum_offset; 677*f51a4a18SMiao Xie u64 bytenr; 678f578d4bdSChris Mason u32 nritems; 679f578d4bdSChris Mason u32 ins_size; 680*f51a4a18SMiao Xie int index = 0; 681*f51a4a18SMiao Xie int found_next; 682*f51a4a18SMiao Xie int ret; 6836c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 6846e92f5e6SChris Mason 6855caf2a00SChris Mason path = btrfs_alloc_path(); 686d8926bb3SMark Fasheh if (!path) 687d8926bb3SMark Fasheh return -ENOMEM; 688065631f6SChris Mason again: 689065631f6SChris Mason next_offset = (u64)-1; 690065631f6SChris Mason found_next = 0; 691*f51a4a18SMiao Xie bytenr = sums->bytenr + total_bytes; 692d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 693*f51a4a18SMiao Xie file_key.offset = bytenr; 694d20f7043SChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); 695a429e513SChris Mason 696*f51a4a18SMiao Xie item = btrfs_lookup_csum(trans, root, path, bytenr, 1); 697ff79f819SChris Mason if (!IS_ERR(item)) { 698639cb586SChris Mason ret = 0; 699*f51a4a18SMiao Xie leaf = path->nodes[0]; 700*f51a4a18SMiao Xie item_end = btrfs_item_ptr(leaf, path->slots[0], 701*f51a4a18SMiao Xie struct btrfs_csum_item); 702*f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((char *)item_end + 703*f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 704a429e513SChris Mason goto found; 705ff79f819SChris Mason } 706a429e513SChris Mason ret = PTR_ERR(item); 7074a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7084a500fd1SYan, Zheng goto fail_unlock; 7094a500fd1SYan, Zheng 710a429e513SChris Mason if (ret == -EFBIG) { 711a429e513SChris Mason u32 item_size; 712a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7135f39d397SChris Mason leaf = path->nodes[0]; 7145f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 715607d432dSJosef Bacik if ((item_size / csum_size) >= 716607d432dSJosef Bacik MAX_CSUM_ITEMS(root, csum_size)) { 717a429e513SChris Mason /* already at max size, make a new one */ 718a429e513SChris Mason goto insert; 719a429e513SChris Mason } 720a429e513SChris Mason } else { 721f578d4bdSChris Mason int slot = path->slots[0] + 1; 722a429e513SChris Mason /* we didn't find a csum item, insert one */ 723f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 724f578d4bdSChris Mason if (path->slots[0] >= nritems - 1) { 725f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 726b56baf5bSYan if (ret == 1) 727f578d4bdSChris Mason found_next = 1; 728b56baf5bSYan if (ret != 0) 729f578d4bdSChris Mason goto insert; 730b56baf5bSYan slot = 0; 731f578d4bdSChris Mason } 732f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 733d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 734d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 735f578d4bdSChris Mason found_next = 1; 736f578d4bdSChris Mason goto insert; 737f578d4bdSChris Mason } 738f578d4bdSChris Mason next_offset = found_key.offset; 739f578d4bdSChris Mason found_next = 1; 740a429e513SChris Mason goto insert; 741a429e513SChris Mason } 742a429e513SChris Mason 743a429e513SChris Mason /* 744a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 745a429e513SChris Mason * enough yet to put our csum in. Grow it 746a429e513SChris Mason */ 747b3b4aa74SDavid Sterba btrfs_release_path(path); 7486567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 749607d432dSJosef Bacik csum_size, 1); 7506567e837SChris Mason if (ret < 0) 75153863232SChris Mason goto fail_unlock; 752459931ecSChris Mason 753459931ecSChris Mason if (ret > 0) { 754459931ecSChris Mason if (path->slots[0] == 0) 7556567e837SChris Mason goto insert; 7566567e837SChris Mason path->slots[0]--; 757459931ecSChris Mason } 758459931ecSChris Mason 7595f39d397SChris Mason leaf = path->nodes[0]; 7605f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 761d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 7626567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 763459931ecSChris Mason 764d20f7043SChris Mason if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || 765d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 766607d432dSJosef Bacik csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { 7676567e837SChris Mason goto insert; 7686567e837SChris Mason } 769459931ecSChris Mason 7702f697dc6SLiu Bo if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / 771607d432dSJosef Bacik csum_size) { 7722f697dc6SLiu Bo int extend_nr; 7732f697dc6SLiu Bo u64 tmp; 7742f697dc6SLiu Bo u32 diff; 7752f697dc6SLiu Bo u32 free_space; 776459931ecSChris Mason 7772f697dc6SLiu Bo if (btrfs_leaf_free_space(root, leaf) < 7782f697dc6SLiu Bo sizeof(struct btrfs_item) + csum_size * 2) 7792f697dc6SLiu Bo goto insert; 7802f697dc6SLiu Bo 7812f697dc6SLiu Bo free_space = btrfs_leaf_free_space(root, leaf) - 7822f697dc6SLiu Bo sizeof(struct btrfs_item) - csum_size; 783*f51a4a18SMiao Xie tmp = sums->len - total_bytes; 7842f697dc6SLiu Bo tmp >>= root->fs_info->sb->s_blocksize_bits; 7852f697dc6SLiu Bo WARN_ON(tmp < 1); 7862f697dc6SLiu Bo 7872f697dc6SLiu Bo extend_nr = max_t(int, 1, (int)tmp); 7882f697dc6SLiu Bo diff = (csum_offset + extend_nr) * csum_size; 7892f697dc6SLiu Bo diff = min(diff, MAX_CSUM_ITEMS(root, csum_size) * csum_size); 790459931ecSChris Mason 7915f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 7922f697dc6SLiu Bo diff = min(free_space, diff); 7932f697dc6SLiu Bo diff /= csum_size; 7942f697dc6SLiu Bo diff *= csum_size; 795459931ecSChris Mason 7964b90c680STsutomu Itoh btrfs_extend_item(root, path, diff); 797*f51a4a18SMiao Xie ret = 0; 7986567e837SChris Mason goto csum; 7996567e837SChris Mason } 8006567e837SChris Mason 8016567e837SChris Mason insert: 802b3b4aa74SDavid Sterba btrfs_release_path(path); 8036567e837SChris Mason csum_offset = 0; 804f578d4bdSChris Mason if (found_next) { 8052f697dc6SLiu Bo u64 tmp; 806d20f7043SChris Mason 807*f51a4a18SMiao Xie tmp = sums->len - total_bytes; 808f578d4bdSChris Mason tmp >>= root->fs_info->sb->s_blocksize_bits; 8092f697dc6SLiu Bo tmp = min(tmp, (next_offset - file_key.offset) >> 8102f697dc6SLiu Bo root->fs_info->sb->s_blocksize_bits); 8112f697dc6SLiu Bo 812f578d4bdSChris Mason tmp = max((u64)1, tmp); 813607d432dSJosef Bacik tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); 814607d432dSJosef Bacik ins_size = csum_size * tmp; 815f578d4bdSChris Mason } else { 816607d432dSJosef Bacik ins_size = csum_size; 817f578d4bdSChris Mason } 818b9473439SChris Mason path->leave_spinning = 1; 8195caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 820f578d4bdSChris Mason ins_size); 821b9473439SChris Mason path->leave_spinning = 0; 82254aa1f4dSChris Mason if (ret < 0) 82353863232SChris Mason goto fail_unlock; 824a429e513SChris Mason if (ret != 0) { 825a429e513SChris Mason WARN_ON(1); 82653863232SChris Mason goto fail_unlock; 827a429e513SChris Mason } 8285f39d397SChris Mason leaf = path->nodes[0]; 829*f51a4a18SMiao Xie csum: 8305f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 831*f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((unsigned char *)item + 832*f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 833509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 834607d432dSJosef Bacik csum_offset * csum_size); 835b18c6685SChris Mason found: 836*f51a4a18SMiao Xie ins_size = (u32)(sums->len - total_bytes) >> 837*f51a4a18SMiao Xie root->fs_info->sb->s_blocksize_bits; 838*f51a4a18SMiao Xie ins_size *= csum_size; 839*f51a4a18SMiao Xie ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item, 840*f51a4a18SMiao Xie ins_size); 841*f51a4a18SMiao Xie write_extent_buffer(leaf, sums->sums + index, (unsigned long)item, 842*f51a4a18SMiao Xie ins_size); 843aadfeb6eSChris Mason 844*f51a4a18SMiao Xie ins_size /= csum_size; 845*f51a4a18SMiao Xie total_bytes += ins_size * root->sectorsize; 846*f51a4a18SMiao Xie index += ins_size; 847a6591715SChris Mason 8485caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 849e6dcd2dcSChris Mason if (total_bytes < sums->len) { 850b3b4aa74SDavid Sterba btrfs_release_path(path); 851b9473439SChris Mason cond_resched(); 852065631f6SChris Mason goto again; 853065631f6SChris Mason } 85453863232SChris Mason out: 8555caf2a00SChris Mason btrfs_free_path(path); 856f254e52cSChris Mason return ret; 85753863232SChris Mason 85853863232SChris Mason fail_unlock: 85953863232SChris Mason goto out; 860f254e52cSChris Mason } 861