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)) / \ 3707d400a6SYan Zheng sizeof(struct btrfs_sector_sum) * \ 3807d400a6SYan Zheng (r)->sectorsize - (r)->sectorsize) 3907d400a6SYan Zheng 40b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 41dee26a9fSChris Mason struct btrfs_root *root, 42b18c6685SChris Mason u64 objectid, u64 pos, 43f2eb0a24SSage Weil u64 disk_offset, u64 disk_num_bytes, 44c8b97818SChris Mason u64 num_bytes, u64 offset, u64 ram_bytes, 45c8b97818SChris Mason u8 compression, u8 encryption, u16 other_encoding) 469f5fae2fSChris Mason { 47dee26a9fSChris Mason int ret = 0; 48dee26a9fSChris Mason struct btrfs_file_extent_item *item; 49dee26a9fSChris Mason struct btrfs_key file_key; 505caf2a00SChris Mason struct btrfs_path *path; 515f39d397SChris Mason struct extent_buffer *leaf; 52dee26a9fSChris Mason 535caf2a00SChris Mason path = btrfs_alloc_path(); 54db5b493aSTsutomu Itoh if (!path) 55db5b493aSTsutomu Itoh return -ENOMEM; 56dee26a9fSChris Mason file_key.objectid = objectid; 57b18c6685SChris Mason file_key.offset = pos; 58dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 59dee26a9fSChris Mason 60b9473439SChris Mason path->leave_spinning = 1; 615caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 62dee26a9fSChris Mason sizeof(*item)); 6354aa1f4dSChris Mason if (ret < 0) 6454aa1f4dSChris Mason goto out; 6579787eaaSJeff Mahoney BUG_ON(ret); /* Can't happen */ 665f39d397SChris Mason leaf = path->nodes[0]; 675f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], 68dee26a9fSChris Mason struct btrfs_file_extent_item); 69f2eb0a24SSage Weil btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); 70db94535dSChris Mason btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 71f2eb0a24SSage Weil btrfs_set_file_extent_offset(leaf, item, offset); 72db94535dSChris Mason btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 73c8b97818SChris Mason btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); 745f39d397SChris Mason btrfs_set_file_extent_generation(leaf, item, trans->transid); 755f39d397SChris Mason btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 76c8b97818SChris Mason btrfs_set_file_extent_compression(leaf, item, compression); 77c8b97818SChris Mason btrfs_set_file_extent_encryption(leaf, item, encryption); 78c8b97818SChris Mason btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); 79c8b97818SChris Mason 805f39d397SChris Mason btrfs_mark_buffer_dirty(leaf); 8154aa1f4dSChris Mason out: 825caf2a00SChris Mason btrfs_free_path(path); 8354aa1f4dSChris Mason return ret; 849f5fae2fSChris Mason } 85dee26a9fSChris Mason 86b18c6685SChris Mason struct btrfs_csum_item *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 121a429e513SChris Mason if (csum_offset >= csums_in_item) { 122a429e513SChris Mason ret = -EFBIG; 1236567e837SChris Mason goto fail; 1246567e837SChris Mason } 1256567e837SChris Mason } 1266567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 127509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 128607d432dSJosef Bacik csum_offset * csum_size); 1296567e837SChris Mason return item; 1306567e837SChris Mason fail: 1316567e837SChris Mason if (ret > 0) 132b18c6685SChris Mason ret = -ENOENT; 1336567e837SChris Mason return ERR_PTR(ret); 1346567e837SChris Mason } 1356567e837SChris Mason 136dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 137dee26a9fSChris Mason struct btrfs_root *root, 138dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1399773a788SChris Mason u64 offset, int mod) 140dee26a9fSChris Mason { 141dee26a9fSChris Mason int ret; 142dee26a9fSChris Mason struct btrfs_key file_key; 143dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 144dee26a9fSChris Mason int cow = mod != 0; 145dee26a9fSChris Mason 146dee26a9fSChris Mason file_key.objectid = objectid; 14770b2befdSChris Mason file_key.offset = offset; 148dee26a9fSChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); 149dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 150dee26a9fSChris Mason return ret; 151dee26a9fSChris Mason } 152f254e52cSChris Mason 153315a9850SMiao Xie u64 btrfs_file_extent_length(struct btrfs_path *path) 154315a9850SMiao Xie { 155315a9850SMiao Xie int extent_type; 156315a9850SMiao Xie struct btrfs_file_extent_item *fi; 157315a9850SMiao Xie u64 len; 158315a9850SMiao Xie 159315a9850SMiao Xie fi = btrfs_item_ptr(path->nodes[0], path->slots[0], 160315a9850SMiao Xie struct btrfs_file_extent_item); 161315a9850SMiao Xie extent_type = btrfs_file_extent_type(path->nodes[0], fi); 162315a9850SMiao Xie 163315a9850SMiao Xie if (extent_type == BTRFS_FILE_EXTENT_REG || 164315a9850SMiao Xie extent_type == BTRFS_FILE_EXTENT_PREALLOC) 165315a9850SMiao Xie len = btrfs_file_extent_num_bytes(path->nodes[0], fi); 166315a9850SMiao Xie else if (extent_type == BTRFS_FILE_EXTENT_INLINE) 167315a9850SMiao Xie len = btrfs_file_extent_inline_len(path->nodes[0], fi); 168315a9850SMiao Xie else 169315a9850SMiao Xie BUG(); 170315a9850SMiao Xie 171315a9850SMiao Xie return len; 172315a9850SMiao Xie } 17317d217feSYan Zheng 1744b46fce2SJosef Bacik static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 1754b46fce2SJosef Bacik struct inode *inode, struct bio *bio, 1764b46fce2SJosef Bacik u64 logical_offset, u32 *dst, int dio) 17761b49440SChris Mason { 17861b49440SChris Mason u32 sum; 17961b49440SChris Mason struct bio_vec *bvec = bio->bi_io_vec; 18061b49440SChris Mason int bio_index = 0; 1814b46fce2SJosef Bacik u64 offset = 0; 18261b49440SChris Mason u64 item_start_offset = 0; 18361b49440SChris Mason u64 item_last_offset = 0; 184d20f7043SChris Mason u64 disk_bytenr; 18561b49440SChris Mason u32 diff; 1866c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 18761b49440SChris Mason int ret; 18861b49440SChris Mason struct btrfs_path *path; 18961b49440SChris Mason struct btrfs_csum_item *item = NULL; 19061b49440SChris Mason struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 19161b49440SChris Mason 19261b49440SChris Mason path = btrfs_alloc_path(); 193c2db1073STsutomu Itoh if (!path) 194c2db1073STsutomu Itoh return -ENOMEM; 1954d1b5fb4SChris Mason if (bio->bi_size > PAGE_CACHE_SIZE * 8) 1964d1b5fb4SChris Mason path->reada = 2; 19761b49440SChris Mason 19861b49440SChris Mason WARN_ON(bio->bi_vcnt <= 0); 19961b49440SChris Mason 2002cf8572dSChris Mason /* 2012cf8572dSChris Mason * the free space stuff is only read when it hasn't been 2022cf8572dSChris Mason * updated in the current transaction. So, we can safely 2032cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 2042cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 2052cf8572dSChris Mason */ 20683eea1f1SLiu Bo if (btrfs_is_free_space_inode(inode)) { 2072cf8572dSChris Mason path->search_commit_root = 1; 208ddf23b3fSJosef Bacik path->skip_locking = 1; 209ddf23b3fSJosef Bacik } 2102cf8572dSChris Mason 211d20f7043SChris Mason disk_bytenr = (u64)bio->bi_sector << 9; 2124b46fce2SJosef Bacik if (dio) 2134b46fce2SJosef Bacik offset = logical_offset; 21461b49440SChris Mason while (bio_index < bio->bi_vcnt) { 2154b46fce2SJosef Bacik if (!dio) 21661b49440SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 217d20f7043SChris Mason ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); 21861b49440SChris Mason if (ret == 0) 21961b49440SChris Mason goto found; 22061b49440SChris Mason 221d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 222d20f7043SChris Mason disk_bytenr >= item_last_offset) { 22361b49440SChris Mason struct btrfs_key found_key; 22461b49440SChris Mason u32 item_size; 22561b49440SChris Mason 22661b49440SChris Mason if (item) 227b3b4aa74SDavid Sterba btrfs_release_path(path); 228d20f7043SChris Mason item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, 229d20f7043SChris Mason path, disk_bytenr, 0); 23061b49440SChris Mason if (IS_ERR(item)) { 23161b49440SChris Mason ret = PTR_ERR(item); 23261b49440SChris Mason if (ret == -ENOENT || ret == -EFBIG) 23361b49440SChris Mason ret = 0; 23461b49440SChris Mason sum = 0; 23517d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 23617d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 23717d217feSYan Zheng set_extent_bits(io_tree, offset, 23817d217feSYan Zheng offset + bvec->bv_len - 1, 23917d217feSYan Zheng EXTENT_NODATASUM, GFP_NOFS); 24017d217feSYan Zheng } else { 241d397712bSChris Mason printk(KERN_INFO "btrfs no csum found " 24233345d01SLi Zefan "for inode %llu start %llu\n", 24333345d01SLi Zefan (unsigned long long) 24433345d01SLi Zefan btrfs_ino(inode), 24561b49440SChris Mason (unsigned long long)offset); 24617d217feSYan Zheng } 2476dab8157SChris Mason item = NULL; 248b3b4aa74SDavid Sterba btrfs_release_path(path); 24961b49440SChris Mason goto found; 25061b49440SChris Mason } 25161b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 25261b49440SChris Mason path->slots[0]); 25361b49440SChris Mason 25461b49440SChris Mason item_start_offset = found_key.offset; 25561b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 25661b49440SChris Mason path->slots[0]); 25761b49440SChris Mason item_last_offset = item_start_offset + 258607d432dSJosef Bacik (item_size / csum_size) * 25961b49440SChris Mason root->sectorsize; 26061b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 26161b49440SChris Mason struct btrfs_csum_item); 26261b49440SChris Mason } 26361b49440SChris Mason /* 26461b49440SChris Mason * this byte range must be able to fit inside 26561b49440SChris Mason * a single leaf so it will also fit inside a u32 26661b49440SChris Mason */ 267d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 26861b49440SChris Mason diff = diff / root->sectorsize; 269607d432dSJosef Bacik diff = diff * csum_size; 27061b49440SChris Mason 27161b49440SChris Mason read_extent_buffer(path->nodes[0], &sum, 2723de9d6b6SChris Mason ((unsigned long)item) + diff, 273607d432dSJosef Bacik csum_size); 27461b49440SChris Mason found: 275d20f7043SChris Mason if (dst) 276d20f7043SChris Mason *dst++ = sum; 277d20f7043SChris Mason else 27861b49440SChris Mason set_state_private(io_tree, offset, sum); 279d20f7043SChris Mason disk_bytenr += bvec->bv_len; 2804b46fce2SJosef Bacik offset += bvec->bv_len; 28161b49440SChris Mason bio_index++; 28261b49440SChris Mason bvec++; 28361b49440SChris Mason } 28461b49440SChris Mason btrfs_free_path(path); 28561b49440SChris Mason return 0; 28661b49440SChris Mason } 28761b49440SChris Mason 2884b46fce2SJosef Bacik int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 2894b46fce2SJosef Bacik struct bio *bio, u32 *dst) 2904b46fce2SJosef Bacik { 2914b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); 2924b46fce2SJosef Bacik } 2934b46fce2SJosef Bacik 2944b46fce2SJosef Bacik int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 295c329861dSJosef Bacik struct bio *bio, u64 offset) 2964b46fce2SJosef Bacik { 297c329861dSJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); 2984b46fce2SJosef Bacik } 2994b46fce2SJosef Bacik 30017d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 301a2de733cSArne Jansen struct list_head *list, int search_commit) 30217d217feSYan Zheng { 30317d217feSYan Zheng struct btrfs_key key; 30417d217feSYan Zheng struct btrfs_path *path; 30517d217feSYan Zheng struct extent_buffer *leaf; 30617d217feSYan Zheng struct btrfs_ordered_sum *sums; 30717d217feSYan Zheng struct btrfs_sector_sum *sector_sum; 30817d217feSYan Zheng struct btrfs_csum_item *item; 3090678b618SMark Fasheh LIST_HEAD(tmplist); 31017d217feSYan Zheng unsigned long offset; 31117d217feSYan Zheng int ret; 31217d217feSYan Zheng size_t size; 31317d217feSYan Zheng u64 csum_end; 3146c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 31517d217feSYan Zheng 31617d217feSYan Zheng path = btrfs_alloc_path(); 317d8926bb3SMark Fasheh if (!path) 318d8926bb3SMark Fasheh return -ENOMEM; 31917d217feSYan Zheng 320a2de733cSArne Jansen if (search_commit) { 321a2de733cSArne Jansen path->skip_locking = 1; 322a2de733cSArne Jansen path->reada = 2; 323a2de733cSArne Jansen path->search_commit_root = 1; 324a2de733cSArne Jansen } 325a2de733cSArne Jansen 32617d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 32717d217feSYan Zheng key.offset = start; 32817d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 32917d217feSYan Zheng 33007d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 33117d217feSYan Zheng if (ret < 0) 33217d217feSYan Zheng goto fail; 33317d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 33417d217feSYan Zheng leaf = path->nodes[0]; 33517d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 33617d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 33717d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 33817d217feSYan Zheng offset = (start - key.offset) >> 33917d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 34017d217feSYan Zheng if (offset * csum_size < 34117d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 34217d217feSYan Zheng path->slots[0]--; 34317d217feSYan Zheng } 34417d217feSYan Zheng } 34517d217feSYan Zheng 34617d217feSYan Zheng while (start <= end) { 34717d217feSYan Zheng leaf = path->nodes[0]; 34817d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 34907d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 35017d217feSYan Zheng if (ret < 0) 35117d217feSYan Zheng goto fail; 35217d217feSYan Zheng if (ret > 0) 35317d217feSYan Zheng break; 35417d217feSYan Zheng leaf = path->nodes[0]; 35517d217feSYan Zheng } 35617d217feSYan Zheng 35717d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 35817d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 35917d217feSYan Zheng key.type != BTRFS_EXTENT_CSUM_KEY) 36017d217feSYan Zheng break; 36117d217feSYan Zheng 36217d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 36317d217feSYan Zheng if (key.offset > end) 36417d217feSYan Zheng break; 36517d217feSYan Zheng 36617d217feSYan Zheng if (key.offset > start) 36717d217feSYan Zheng start = key.offset; 36817d217feSYan Zheng 36917d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 37017d217feSYan Zheng csum_end = key.offset + (size / csum_size) * root->sectorsize; 37187b29b20SYan Zheng if (csum_end <= start) { 37287b29b20SYan Zheng path->slots[0]++; 37387b29b20SYan Zheng continue; 37487b29b20SYan Zheng } 37517d217feSYan Zheng 37607d400a6SYan Zheng csum_end = min(csum_end, end + 1); 37707d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 37807d400a6SYan Zheng struct btrfs_csum_item); 37907d400a6SYan Zheng while (start < csum_end) { 38007d400a6SYan Zheng size = min_t(size_t, csum_end - start, 38107d400a6SYan Zheng MAX_ORDERED_SUM_BYTES(root)); 38207d400a6SYan Zheng sums = kzalloc(btrfs_ordered_sum_size(root, size), 38307d400a6SYan Zheng GFP_NOFS); 3840678b618SMark Fasheh if (!sums) { 3850678b618SMark Fasheh ret = -ENOMEM; 3860678b618SMark Fasheh goto fail; 3870678b618SMark Fasheh } 38817d217feSYan Zheng 38917d217feSYan Zheng sector_sum = sums->sums; 39017d217feSYan Zheng sums->bytenr = start; 39117d217feSYan Zheng sums->len = size; 39217d217feSYan Zheng 39317d217feSYan Zheng offset = (start - key.offset) >> 39417d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 39517d217feSYan Zheng offset *= csum_size; 39617d217feSYan Zheng 39717d217feSYan Zheng while (size > 0) { 39807d400a6SYan Zheng read_extent_buffer(path->nodes[0], 39907d400a6SYan Zheng §or_sum->sum, 40007d400a6SYan Zheng ((unsigned long)item) + 40107d400a6SYan Zheng offset, csum_size); 40217d217feSYan Zheng sector_sum->bytenr = start; 40317d217feSYan Zheng 40417d217feSYan Zheng size -= root->sectorsize; 40517d217feSYan Zheng start += root->sectorsize; 40617d217feSYan Zheng offset += csum_size; 40717d217feSYan Zheng sector_sum++; 40817d217feSYan Zheng } 4090678b618SMark Fasheh list_add_tail(&sums->list, &tmplist); 41007d400a6SYan Zheng } 41117d217feSYan Zheng path->slots[0]++; 41217d217feSYan Zheng } 41317d217feSYan Zheng ret = 0; 41417d217feSYan Zheng fail: 4150678b618SMark Fasheh while (ret < 0 && !list_empty(&tmplist)) { 4160678b618SMark Fasheh sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); 4170678b618SMark Fasheh list_del(&sums->list); 4180678b618SMark Fasheh kfree(sums); 4190678b618SMark Fasheh } 4200678b618SMark Fasheh list_splice_tail(&tmplist, list); 4210678b618SMark Fasheh 42217d217feSYan Zheng btrfs_free_path(path); 42317d217feSYan Zheng return ret; 42417d217feSYan Zheng } 42517d217feSYan Zheng 4263edf7d33SChris Mason int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 427d20f7043SChris Mason struct bio *bio, u64 file_start, int contig) 428e015640fSChris Mason { 429e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums; 430e6dcd2dcSChris Mason struct btrfs_sector_sum *sector_sum; 4313edf7d33SChris Mason struct btrfs_ordered_extent *ordered; 432e015640fSChris Mason char *data; 433e015640fSChris Mason struct bio_vec *bvec = bio->bi_io_vec; 434e015640fSChris Mason int bio_index = 0; 4353edf7d33SChris Mason unsigned long total_bytes = 0; 4363edf7d33SChris Mason unsigned long this_sum_bytes = 0; 4373edf7d33SChris Mason u64 offset; 438d20f7043SChris Mason u64 disk_bytenr; 439e015640fSChris Mason 440e6dcd2dcSChris Mason WARN_ON(bio->bi_vcnt <= 0); 441e6dcd2dcSChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); 442e015640fSChris Mason if (!sums) 443e015640fSChris Mason return -ENOMEM; 4443edf7d33SChris Mason 445ed98b56aSChris Mason sector_sum = sums->sums; 446d20f7043SChris Mason disk_bytenr = (u64)bio->bi_sector << 9; 447e6dcd2dcSChris Mason sums->len = bio->bi_size; 448e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 449d20f7043SChris Mason 450d20f7043SChris Mason if (contig) 451d20f7043SChris Mason offset = file_start; 452d20f7043SChris Mason else 453d20f7043SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 454d20f7043SChris Mason 455d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 45679787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 457d20f7043SChris Mason sums->bytenr = ordered->start; 458e015640fSChris Mason 459e015640fSChris Mason while (bio_index < bio->bi_vcnt) { 460d20f7043SChris Mason if (!contig) 4613edf7d33SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 462d20f7043SChris Mason 463e58dd74bSJosef Bacik if (offset >= ordered->file_offset + ordered->len || 464e58dd74bSJosef Bacik offset < ordered->file_offset) { 4653edf7d33SChris Mason unsigned long bytes_left; 4663edf7d33SChris Mason sums->len = this_sum_bytes; 4673edf7d33SChris Mason this_sum_bytes = 0; 4683edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4693edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4703edf7d33SChris Mason 4713edf7d33SChris Mason bytes_left = bio->bi_size - total_bytes; 4723edf7d33SChris Mason 4733edf7d33SChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), 4743edf7d33SChris Mason GFP_NOFS); 47579787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 476ed98b56aSChris Mason sector_sum = sums->sums; 4773edf7d33SChris Mason sums->len = bytes_left; 478d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 47979787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 480d20f7043SChris Mason sums->bytenr = ordered->start; 4813edf7d33SChris Mason } 4823edf7d33SChris Mason 4837ac687d9SCong Wang data = kmap_atomic(bvec->bv_page); 484e6dcd2dcSChris Mason sector_sum->sum = ~(u32)0; 485e6dcd2dcSChris Mason sector_sum->sum = btrfs_csum_data(root, 486e6dcd2dcSChris Mason data + bvec->bv_offset, 487e6dcd2dcSChris Mason sector_sum->sum, 488e6dcd2dcSChris Mason bvec->bv_len); 4897ac687d9SCong Wang kunmap_atomic(data); 490e6dcd2dcSChris Mason btrfs_csum_final(sector_sum->sum, 491e6dcd2dcSChris Mason (char *)§or_sum->sum); 492d20f7043SChris Mason sector_sum->bytenr = disk_bytenr; 493ed98b56aSChris Mason 494e6dcd2dcSChris Mason sector_sum++; 495e015640fSChris Mason bio_index++; 4963edf7d33SChris Mason total_bytes += bvec->bv_len; 4973edf7d33SChris Mason this_sum_bytes += bvec->bv_len; 498d20f7043SChris Mason disk_bytenr += bvec->bv_len; 499d20f7043SChris Mason offset += bvec->bv_len; 500e015640fSChris Mason bvec++; 501e015640fSChris Mason } 502ed98b56aSChris Mason this_sum_bytes = 0; 5033edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 5043edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 505e015640fSChris Mason return 0; 506e015640fSChris Mason } 507e015640fSChris Mason 508459931ecSChris Mason /* 509459931ecSChris Mason * helper function for csum removal, this expects the 510459931ecSChris Mason * key to describe the csum pointed to by the path, and it expects 511459931ecSChris Mason * the csum to overlap the range [bytenr, len] 512459931ecSChris Mason * 513459931ecSChris Mason * The csum should not be entirely contained in the range and the 514459931ecSChris Mason * range should not be entirely contained in the csum. 515459931ecSChris Mason * 516459931ecSChris Mason * This calls btrfs_truncate_item with the correct args based on the 517459931ecSChris Mason * overlap, and fixes up the key as required. 518459931ecSChris Mason */ 519143bede5SJeff Mahoney static noinline void truncate_one_csum(struct btrfs_trans_handle *trans, 520459931ecSChris Mason struct btrfs_root *root, 521459931ecSChris Mason struct btrfs_path *path, 522459931ecSChris Mason struct btrfs_key *key, 523459931ecSChris Mason u64 bytenr, u64 len) 524459931ecSChris Mason { 525459931ecSChris Mason struct extent_buffer *leaf; 5266c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 527459931ecSChris Mason u64 csum_end; 528459931ecSChris Mason u64 end_byte = bytenr + len; 529459931ecSChris Mason u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; 530459931ecSChris Mason 531459931ecSChris Mason leaf = path->nodes[0]; 532459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 533459931ecSChris Mason csum_end <<= root->fs_info->sb->s_blocksize_bits; 534459931ecSChris Mason csum_end += key->offset; 535459931ecSChris Mason 536459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 537459931ecSChris Mason /* 538459931ecSChris Mason * [ bytenr - len ] 539459931ecSChris Mason * [ ] 540459931ecSChris Mason * [csum ] 541459931ecSChris Mason * A simple truncate off the end of the item 542459931ecSChris Mason */ 543459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 544459931ecSChris Mason new_size *= csum_size; 545143bede5SJeff Mahoney btrfs_truncate_item(trans, root, path, new_size, 1); 546459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 547459931ecSChris Mason end_byte > key->offset) { 548459931ecSChris Mason /* 549459931ecSChris Mason * [ bytenr - len ] 550459931ecSChris Mason * [ ] 551459931ecSChris Mason * [csum ] 552459931ecSChris Mason * we need to truncate from the beginning of the csum 553459931ecSChris Mason */ 554459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 555459931ecSChris Mason new_size *= csum_size; 556459931ecSChris Mason 557143bede5SJeff Mahoney btrfs_truncate_item(trans, root, path, new_size, 0); 558459931ecSChris Mason 559459931ecSChris Mason key->offset = end_byte; 560143bede5SJeff Mahoney btrfs_set_item_key_safe(trans, root, path, key); 561459931ecSChris Mason } else { 562459931ecSChris Mason BUG(); 563459931ecSChris Mason } 564459931ecSChris Mason } 565459931ecSChris Mason 566459931ecSChris Mason /* 567459931ecSChris Mason * deletes the csum items from the csum tree for a given 568459931ecSChris Mason * range of bytes. 569459931ecSChris Mason */ 570459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 571459931ecSChris Mason struct btrfs_root *root, u64 bytenr, u64 len) 572459931ecSChris Mason { 573459931ecSChris Mason struct btrfs_path *path; 574459931ecSChris Mason struct btrfs_key key; 575459931ecSChris Mason u64 end_byte = bytenr + len; 576459931ecSChris Mason u64 csum_end; 577459931ecSChris Mason struct extent_buffer *leaf; 578459931ecSChris Mason int ret; 5796c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 580459931ecSChris Mason int blocksize_bits = root->fs_info->sb->s_blocksize_bits; 581459931ecSChris Mason 582459931ecSChris Mason root = root->fs_info->csum_root; 583459931ecSChris Mason 584459931ecSChris Mason path = btrfs_alloc_path(); 5852a29edc6Sliubo if (!path) 5862a29edc6Sliubo return -ENOMEM; 587459931ecSChris Mason 588459931ecSChris Mason while (1) { 589459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 590459931ecSChris Mason key.offset = end_byte - 1; 591459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 592459931ecSChris Mason 593b9473439SChris Mason path->leave_spinning = 1; 594459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 595459931ecSChris Mason if (ret > 0) { 596459931ecSChris Mason if (path->slots[0] == 0) 59765a246c5STsutomu Itoh break; 598459931ecSChris Mason path->slots[0]--; 599ad0397a7SJosef Bacik } else if (ret < 0) { 60065a246c5STsutomu Itoh break; 601459931ecSChris Mason } 602ad0397a7SJosef Bacik 603459931ecSChris Mason leaf = path->nodes[0]; 604459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 605459931ecSChris Mason 606459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 607459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 608459931ecSChris Mason break; 609459931ecSChris Mason } 610459931ecSChris Mason 611459931ecSChris Mason if (key.offset >= end_byte) 612459931ecSChris Mason break; 613459931ecSChris Mason 614459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 615459931ecSChris Mason csum_end <<= blocksize_bits; 616459931ecSChris Mason csum_end += key.offset; 617459931ecSChris Mason 618459931ecSChris Mason /* this csum ends before we start, we're done */ 619459931ecSChris Mason if (csum_end <= bytenr) 620459931ecSChris Mason break; 621459931ecSChris Mason 622459931ecSChris Mason /* delete the entire item, it is inside our range */ 623459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 624459931ecSChris Mason ret = btrfs_del_item(trans, root, path); 62565a246c5STsutomu Itoh if (ret) 62665a246c5STsutomu Itoh goto out; 627dcbdd4dcSChris Mason if (key.offset == bytenr) 628dcbdd4dcSChris Mason break; 629459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 630459931ecSChris Mason unsigned long offset; 631459931ecSChris Mason unsigned long shift_len; 632459931ecSChris Mason unsigned long item_offset; 633459931ecSChris Mason /* 634459931ecSChris Mason * [ bytenr - len ] 635459931ecSChris Mason * [csum ] 636459931ecSChris Mason * 637459931ecSChris Mason * Our bytes are in the middle of the csum, 638459931ecSChris Mason * we need to split this item and insert a new one. 639459931ecSChris Mason * 640459931ecSChris Mason * But we can't drop the path because the 641459931ecSChris Mason * csum could change, get removed, extended etc. 642459931ecSChris Mason * 643459931ecSChris Mason * The trick here is the max size of a csum item leaves 644459931ecSChris Mason * enough room in the tree block for a single 645459931ecSChris Mason * item header. So, we split the item in place, 646459931ecSChris Mason * adding a new header pointing to the existing 647459931ecSChris Mason * bytes. Then we loop around again and we have 648459931ecSChris Mason * a nicely formed csum item that we can neatly 649459931ecSChris Mason * truncate. 650459931ecSChris Mason */ 651459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 652459931ecSChris Mason offset *= csum_size; 653459931ecSChris Mason 654459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 655459931ecSChris Mason 656459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 657459931ecSChris Mason path->slots[0]); 658459931ecSChris Mason 659459931ecSChris Mason memset_extent_buffer(leaf, 0, item_offset + offset, 660459931ecSChris Mason shift_len); 661459931ecSChris Mason key.offset = bytenr; 662459931ecSChris Mason 663459931ecSChris Mason /* 664459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 665459931ecSChris Mason * item changed size or key 666459931ecSChris Mason */ 667459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 66879787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 66979787eaaSJeff Mahoney btrfs_abort_transaction(trans, root, ret); 67079787eaaSJeff Mahoney goto out; 67179787eaaSJeff Mahoney } 672459931ecSChris Mason 673459931ecSChris Mason key.offset = end_byte - 1; 674459931ecSChris Mason } else { 675143bede5SJeff Mahoney truncate_one_csum(trans, root, path, &key, bytenr, len); 676dcbdd4dcSChris Mason if (key.offset < bytenr) 677dcbdd4dcSChris Mason break; 678459931ecSChris Mason } 679b3b4aa74SDavid Sterba btrfs_release_path(path); 680459931ecSChris Mason } 68165a246c5STsutomu Itoh ret = 0; 682459931ecSChris Mason out: 683459931ecSChris Mason btrfs_free_path(path); 68465a246c5STsutomu Itoh return ret; 685459931ecSChris Mason } 686459931ecSChris Mason 687*2f697dc6SLiu Bo static u64 btrfs_sector_sum_left(struct btrfs_ordered_sum *sums, 688*2f697dc6SLiu Bo struct btrfs_sector_sum *sector_sum, 689*2f697dc6SLiu Bo u64 total_bytes, u64 sectorsize) 690*2f697dc6SLiu Bo { 691*2f697dc6SLiu Bo u64 tmp = sectorsize; 692*2f697dc6SLiu Bo u64 next_sector = sector_sum->bytenr; 693*2f697dc6SLiu Bo struct btrfs_sector_sum *next = sector_sum + 1; 694*2f697dc6SLiu Bo 695*2f697dc6SLiu Bo while ((tmp + total_bytes) < sums->len) { 696*2f697dc6SLiu Bo if (next_sector + sectorsize != next->bytenr) 697*2f697dc6SLiu Bo break; 698*2f697dc6SLiu Bo tmp += sectorsize; 699*2f697dc6SLiu Bo next_sector = next->bytenr; 700*2f697dc6SLiu Bo next++; 701*2f697dc6SLiu Bo } 702*2f697dc6SLiu Bo return tmp; 703*2f697dc6SLiu Bo } 704*2f697dc6SLiu Bo 705065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 706d20f7043SChris Mason struct btrfs_root *root, 707e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 708f254e52cSChris Mason { 709d20f7043SChris Mason u64 bytenr; 710f254e52cSChris Mason int ret; 711f254e52cSChris Mason struct btrfs_key file_key; 7126567e837SChris Mason struct btrfs_key found_key; 713065631f6SChris Mason u64 next_offset; 714e6dcd2dcSChris Mason u64 total_bytes = 0; 715065631f6SChris Mason int found_next; 7165caf2a00SChris Mason struct btrfs_path *path; 717f254e52cSChris Mason struct btrfs_csum_item *item; 718065631f6SChris Mason struct btrfs_csum_item *item_end; 719ff79f819SChris Mason struct extent_buffer *leaf = NULL; 7206567e837SChris Mason u64 csum_offset; 721e6dcd2dcSChris Mason struct btrfs_sector_sum *sector_sum; 722f578d4bdSChris Mason u32 nritems; 723f578d4bdSChris Mason u32 ins_size; 7246c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 7256e92f5e6SChris Mason 7265caf2a00SChris Mason path = btrfs_alloc_path(); 727d8926bb3SMark Fasheh if (!path) 728d8926bb3SMark Fasheh return -ENOMEM; 729d8926bb3SMark Fasheh 730ed98b56aSChris Mason sector_sum = sums->sums; 7310e721106SJosef Bacik trans->adding_csums = 1; 732065631f6SChris Mason again: 733065631f6SChris Mason next_offset = (u64)-1; 734065631f6SChris Mason found_next = 0; 735d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 736d20f7043SChris Mason file_key.offset = sector_sum->bytenr; 737d20f7043SChris Mason bytenr = sector_sum->bytenr; 738d20f7043SChris Mason btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY); 739a429e513SChris Mason 740d20f7043SChris Mason item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1); 741ff79f819SChris Mason if (!IS_ERR(item)) { 742ff79f819SChris Mason leaf = path->nodes[0]; 743639cb586SChris Mason ret = 0; 744a429e513SChris Mason goto found; 745ff79f819SChris Mason } 746a429e513SChris Mason ret = PTR_ERR(item); 7474a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7484a500fd1SYan, Zheng goto fail_unlock; 7494a500fd1SYan, Zheng 750a429e513SChris Mason if (ret == -EFBIG) { 751a429e513SChris Mason u32 item_size; 752a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7535f39d397SChris Mason leaf = path->nodes[0]; 7545f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 755607d432dSJosef Bacik if ((item_size / csum_size) >= 756607d432dSJosef Bacik MAX_CSUM_ITEMS(root, csum_size)) { 757a429e513SChris Mason /* already at max size, make a new one */ 758a429e513SChris Mason goto insert; 759a429e513SChris Mason } 760a429e513SChris Mason } else { 761f578d4bdSChris Mason int slot = path->slots[0] + 1; 762a429e513SChris Mason /* we didn't find a csum item, insert one */ 763f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 764f578d4bdSChris Mason if (path->slots[0] >= nritems - 1) { 765f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 766b56baf5bSYan if (ret == 1) 767f578d4bdSChris Mason found_next = 1; 768b56baf5bSYan if (ret != 0) 769f578d4bdSChris Mason goto insert; 770b56baf5bSYan slot = 0; 771f578d4bdSChris Mason } 772f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 773d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 774d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 775f578d4bdSChris Mason found_next = 1; 776f578d4bdSChris Mason goto insert; 777f578d4bdSChris Mason } 778f578d4bdSChris Mason next_offset = found_key.offset; 779f578d4bdSChris Mason found_next = 1; 780a429e513SChris Mason goto insert; 781a429e513SChris Mason } 782a429e513SChris Mason 783a429e513SChris Mason /* 784a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 785a429e513SChris Mason * enough yet to put our csum in. Grow it 786a429e513SChris Mason */ 787b3b4aa74SDavid Sterba btrfs_release_path(path); 7886567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 789607d432dSJosef Bacik csum_size, 1); 7906567e837SChris Mason if (ret < 0) 79153863232SChris Mason goto fail_unlock; 792459931ecSChris Mason 793459931ecSChris Mason if (ret > 0) { 794459931ecSChris Mason if (path->slots[0] == 0) 7956567e837SChris Mason goto insert; 7966567e837SChris Mason path->slots[0]--; 797459931ecSChris Mason } 798459931ecSChris Mason 7995f39d397SChris Mason leaf = path->nodes[0]; 8005f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 801d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 8026567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 803459931ecSChris Mason 804d20f7043SChris Mason if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || 805d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 806607d432dSJosef Bacik csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { 8076567e837SChris Mason goto insert; 8086567e837SChris Mason } 809459931ecSChris Mason 810*2f697dc6SLiu Bo if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / 811607d432dSJosef Bacik csum_size) { 812*2f697dc6SLiu Bo int extend_nr; 813*2f697dc6SLiu Bo u64 tmp; 814*2f697dc6SLiu Bo u32 diff; 815*2f697dc6SLiu Bo u32 free_space; 816459931ecSChris Mason 817*2f697dc6SLiu Bo if (btrfs_leaf_free_space(root, leaf) < 818*2f697dc6SLiu Bo sizeof(struct btrfs_item) + csum_size * 2) 819*2f697dc6SLiu Bo goto insert; 820*2f697dc6SLiu Bo 821*2f697dc6SLiu Bo free_space = btrfs_leaf_free_space(root, leaf) - 822*2f697dc6SLiu Bo sizeof(struct btrfs_item) - csum_size; 823*2f697dc6SLiu Bo tmp = btrfs_sector_sum_left(sums, sector_sum, total_bytes, 824*2f697dc6SLiu Bo root->sectorsize); 825*2f697dc6SLiu Bo tmp >>= root->fs_info->sb->s_blocksize_bits; 826*2f697dc6SLiu Bo WARN_ON(tmp < 1); 827*2f697dc6SLiu Bo 828*2f697dc6SLiu Bo extend_nr = max_t(int, 1, (int)tmp); 829*2f697dc6SLiu Bo diff = (csum_offset + extend_nr) * csum_size; 830*2f697dc6SLiu Bo diff = min(diff, MAX_CSUM_ITEMS(root, csum_size) * csum_size); 831459931ecSChris Mason 8325f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 833*2f697dc6SLiu Bo diff = min(free_space, diff); 834*2f697dc6SLiu Bo diff /= csum_size; 835*2f697dc6SLiu Bo diff *= csum_size; 836459931ecSChris Mason 837143bede5SJeff Mahoney btrfs_extend_item(trans, root, path, diff); 8386567e837SChris Mason goto csum; 8396567e837SChris Mason } 8406567e837SChris Mason 8416567e837SChris Mason insert: 842b3b4aa74SDavid Sterba btrfs_release_path(path); 8436567e837SChris Mason csum_offset = 0; 844f578d4bdSChris Mason if (found_next) { 845*2f697dc6SLiu Bo u64 tmp; 846d20f7043SChris Mason 847*2f697dc6SLiu Bo tmp = btrfs_sector_sum_left(sums, sector_sum, total_bytes, 848*2f697dc6SLiu Bo root->sectorsize); 849f578d4bdSChris Mason tmp >>= root->fs_info->sb->s_blocksize_bits; 850*2f697dc6SLiu Bo tmp = min(tmp, (next_offset - file_key.offset) >> 851*2f697dc6SLiu Bo root->fs_info->sb->s_blocksize_bits); 852*2f697dc6SLiu Bo 853f578d4bdSChris Mason tmp = max((u64)1, tmp); 854607d432dSJosef Bacik tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); 855607d432dSJosef Bacik ins_size = csum_size * tmp; 856f578d4bdSChris Mason } else { 857607d432dSJosef Bacik ins_size = csum_size; 858f578d4bdSChris Mason } 859b9473439SChris Mason path->leave_spinning = 1; 8605caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 861f578d4bdSChris Mason ins_size); 862b9473439SChris Mason path->leave_spinning = 0; 86354aa1f4dSChris Mason if (ret < 0) 86453863232SChris Mason goto fail_unlock; 865a429e513SChris Mason if (ret != 0) { 866a429e513SChris Mason WARN_ON(1); 86753863232SChris Mason goto fail_unlock; 868a429e513SChris Mason } 8696567e837SChris Mason csum: 8705f39d397SChris Mason leaf = path->nodes[0]; 8715f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 872f254e52cSChris Mason ret = 0; 873509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 874607d432dSJosef Bacik csum_offset * csum_size); 875b18c6685SChris Mason found: 876065631f6SChris Mason item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 877065631f6SChris Mason item_end = (struct btrfs_csum_item *)((unsigned char *)item_end + 878065631f6SChris Mason btrfs_item_size_nr(leaf, path->slots[0])); 879e6dcd2dcSChris Mason next_sector: 880aadfeb6eSChris Mason 881a6591715SChris Mason write_extent_buffer(leaf, §or_sum->sum, (unsigned long)item, csum_size); 8827f3c74fbSChris Mason 883e6dcd2dcSChris Mason total_bytes += root->sectorsize; 884e6dcd2dcSChris Mason sector_sum++; 885e6dcd2dcSChris Mason if (total_bytes < sums->len) { 8866e92f5e6SChris Mason item = (struct btrfs_csum_item *)((char *)item + 887607d432dSJosef Bacik csum_size); 888d20f7043SChris Mason if (item < item_end && bytenr + PAGE_CACHE_SIZE == 889d20f7043SChris Mason sector_sum->bytenr) { 890d20f7043SChris Mason bytenr = sector_sum->bytenr; 891e6dcd2dcSChris Mason goto next_sector; 892065631f6SChris Mason } 8932e1a992eSChris Mason } 894a6591715SChris Mason 8955caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 896e6dcd2dcSChris Mason if (total_bytes < sums->len) { 897b3b4aa74SDavid Sterba btrfs_release_path(path); 898b9473439SChris Mason cond_resched(); 899065631f6SChris Mason goto again; 900065631f6SChris Mason } 90153863232SChris Mason out: 9020e721106SJosef Bacik trans->adding_csums = 0; 9035caf2a00SChris Mason btrfs_free_path(path); 904f254e52cSChris Mason return ret; 90553863232SChris Mason 90653863232SChris Mason fail_unlock: 90753863232SChris Mason goto out; 908f254e52cSChris Mason } 909