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" 26facc8a22SMiao Xie #include "volumes.h" 271de037a4SChris Mason #include "print-tree.h" 281e1d2701SChris Mason 29995e01b7SJan Schmidt #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ 30a429e513SChris Mason sizeof(struct btrfs_item) * 2) / \ 31607d432dSJosef Bacik size) - 1)) 3207d400a6SYan Zheng 33221b8318SZach Brown #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ 34221b8318SZach Brown PAGE_CACHE_SIZE)) 357ca4be45SChris Mason 3607d400a6SYan Zheng #define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ 3707d400a6SYan Zheng sizeof(struct btrfs_ordered_sum)) / \ 38f51a4a18SMiao Xie sizeof(u32) * (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; 58962a298fSDavid Sterba file_key.type = 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 8648a3b636SEric Sandeen static struct btrfs_csum_item * 8748a3b636SEric Sandeen btrfs_lookup_csum(struct btrfs_trans_handle *trans, 88b18c6685SChris Mason struct btrfs_root *root, 896567e837SChris Mason struct btrfs_path *path, 90d20f7043SChris Mason u64 bytenr, int cow) 916567e837SChris Mason { 926567e837SChris Mason int ret; 936567e837SChris Mason struct btrfs_key file_key; 946567e837SChris Mason struct btrfs_key found_key; 956567e837SChris Mason struct btrfs_csum_item *item; 965f39d397SChris Mason struct extent_buffer *leaf; 976567e837SChris Mason u64 csum_offset = 0; 986c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 99a429e513SChris Mason int csums_in_item; 1006567e837SChris Mason 101d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 102d20f7043SChris Mason file_key.offset = bytenr; 103962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 104b18c6685SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 1056567e837SChris Mason if (ret < 0) 1066567e837SChris Mason goto fail; 1075f39d397SChris Mason leaf = path->nodes[0]; 1086567e837SChris Mason if (ret > 0) { 1096567e837SChris Mason ret = 1; 11070b2befdSChris Mason if (path->slots[0] == 0) 1116567e837SChris Mason goto fail; 1126567e837SChris Mason path->slots[0]--; 1135f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 114962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY) 1156567e837SChris Mason goto fail; 116d20f7043SChris Mason 117d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 1186567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 1195f39d397SChris Mason csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 120607d432dSJosef Bacik csums_in_item /= csum_size; 121a429e513SChris Mason 12282d130ffSMiao Xie if (csum_offset == csums_in_item) { 123a429e513SChris Mason ret = -EFBIG; 1246567e837SChris Mason goto fail; 12582d130ffSMiao Xie } else if (csum_offset > csums_in_item) { 12682d130ffSMiao Xie goto fail; 1276567e837SChris Mason } 1286567e837SChris Mason } 1296567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 130509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 131607d432dSJosef Bacik csum_offset * csum_size); 1326567e837SChris Mason return item; 1336567e837SChris Mason fail: 1346567e837SChris Mason if (ret > 0) 135b18c6685SChris Mason ret = -ENOENT; 1366567e837SChris Mason return ERR_PTR(ret); 1376567e837SChris Mason } 1386567e837SChris Mason 139dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 140dee26a9fSChris Mason struct btrfs_root *root, 141dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1429773a788SChris Mason u64 offset, int mod) 143dee26a9fSChris Mason { 144dee26a9fSChris Mason int ret; 145dee26a9fSChris Mason struct btrfs_key file_key; 146dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 147dee26a9fSChris Mason int cow = mod != 0; 148dee26a9fSChris Mason 149dee26a9fSChris Mason file_key.objectid = objectid; 15070b2befdSChris Mason file_key.offset = offset; 151962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_DATA_KEY; 152dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 153dee26a9fSChris Mason return ret; 154dee26a9fSChris Mason } 155f254e52cSChris Mason 156facc8a22SMiao Xie static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) 157facc8a22SMiao Xie { 158facc8a22SMiao Xie kfree(bio->csum_allocated); 159facc8a22SMiao Xie } 160facc8a22SMiao Xie 1614b46fce2SJosef Bacik static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 1624b46fce2SJosef Bacik struct inode *inode, struct bio *bio, 1634b46fce2SJosef Bacik u64 logical_offset, u32 *dst, int dio) 16461b49440SChris Mason { 16561b49440SChris Mason struct bio_vec *bvec = bio->bi_io_vec; 166facc8a22SMiao Xie struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); 167facc8a22SMiao Xie struct btrfs_csum_item *item = NULL; 168facc8a22SMiao Xie struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 169facc8a22SMiao Xie struct btrfs_path *path; 170facc8a22SMiao Xie u8 *csum; 1714b46fce2SJosef Bacik u64 offset = 0; 17261b49440SChris Mason u64 item_start_offset = 0; 17361b49440SChris Mason u64 item_last_offset = 0; 174d20f7043SChris Mason u64 disk_bytenr; 17561b49440SChris Mason u32 diff; 176facc8a22SMiao Xie int nblocks; 177facc8a22SMiao Xie int bio_index = 0; 178e4100d98SMiao Xie int count; 179facc8a22SMiao Xie u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 18061b49440SChris Mason 18161b49440SChris Mason path = btrfs_alloc_path(); 182c2db1073STsutomu Itoh if (!path) 183c2db1073STsutomu Itoh return -ENOMEM; 184facc8a22SMiao Xie 1854f024f37SKent Overstreet nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits; 186facc8a22SMiao Xie if (!dst) { 187facc8a22SMiao Xie if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { 188facc8a22SMiao Xie btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size, 189facc8a22SMiao Xie GFP_NOFS); 190facc8a22SMiao Xie if (!btrfs_bio->csum_allocated) { 191facc8a22SMiao Xie btrfs_free_path(path); 192facc8a22SMiao Xie return -ENOMEM; 193facc8a22SMiao Xie } 194facc8a22SMiao Xie btrfs_bio->csum = btrfs_bio->csum_allocated; 195facc8a22SMiao Xie btrfs_bio->end_io = btrfs_io_bio_endio_readpage; 196facc8a22SMiao Xie } else { 197facc8a22SMiao Xie btrfs_bio->csum = btrfs_bio->csum_inline; 198facc8a22SMiao Xie } 199facc8a22SMiao Xie csum = btrfs_bio->csum; 200facc8a22SMiao Xie } else { 201facc8a22SMiao Xie csum = (u8 *)dst; 202facc8a22SMiao Xie } 203facc8a22SMiao Xie 2044f024f37SKent Overstreet if (bio->bi_iter.bi_size > PAGE_CACHE_SIZE * 8) 2054d1b5fb4SChris Mason path->reada = 2; 20661b49440SChris Mason 20761b49440SChris Mason WARN_ON(bio->bi_vcnt <= 0); 20861b49440SChris Mason 2092cf8572dSChris Mason /* 2102cf8572dSChris Mason * the free space stuff is only read when it hasn't been 2112cf8572dSChris Mason * updated in the current transaction. So, we can safely 2122cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 2132cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 2142cf8572dSChris Mason */ 21583eea1f1SLiu Bo if (btrfs_is_free_space_inode(inode)) { 2162cf8572dSChris Mason path->search_commit_root = 1; 217ddf23b3fSJosef Bacik path->skip_locking = 1; 218ddf23b3fSJosef Bacik } 2192cf8572dSChris Mason 2204f024f37SKent Overstreet disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; 2214b46fce2SJosef Bacik if (dio) 2224b46fce2SJosef Bacik offset = logical_offset; 22361b49440SChris Mason while (bio_index < bio->bi_vcnt) { 2244b46fce2SJosef Bacik if (!dio) 22561b49440SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 226facc8a22SMiao Xie count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, 227facc8a22SMiao Xie (u32 *)csum, nblocks); 228e4100d98SMiao Xie if (count) 22961b49440SChris Mason goto found; 23061b49440SChris Mason 231d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 232d20f7043SChris Mason disk_bytenr >= item_last_offset) { 23361b49440SChris Mason struct btrfs_key found_key; 23461b49440SChris Mason u32 item_size; 23561b49440SChris Mason 23661b49440SChris Mason if (item) 237b3b4aa74SDavid Sterba btrfs_release_path(path); 238d20f7043SChris Mason item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, 239d20f7043SChris Mason path, disk_bytenr, 0); 24061b49440SChris Mason if (IS_ERR(item)) { 241e4100d98SMiao Xie count = 1; 242facc8a22SMiao Xie memset(csum, 0, csum_size); 24317d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 24417d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 24517d217feSYan Zheng set_extent_bits(io_tree, offset, 24617d217feSYan Zheng offset + bvec->bv_len - 1, 24717d217feSYan Zheng EXTENT_NODATASUM, GFP_NOFS); 24817d217feSYan Zheng } else { 249efe120a0SFrank Holton btrfs_info(BTRFS_I(inode)->root->fs_info, 250efe120a0SFrank Holton "no csum found for inode %llu start %llu", 251c1c9ff7cSGeert Uytterhoeven btrfs_ino(inode), offset); 25217d217feSYan Zheng } 2536dab8157SChris Mason item = NULL; 254b3b4aa74SDavid Sterba btrfs_release_path(path); 25561b49440SChris Mason goto found; 25661b49440SChris Mason } 25761b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 25861b49440SChris Mason path->slots[0]); 25961b49440SChris Mason 26061b49440SChris Mason item_start_offset = found_key.offset; 26161b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 26261b49440SChris Mason path->slots[0]); 26361b49440SChris Mason item_last_offset = item_start_offset + 264607d432dSJosef Bacik (item_size / csum_size) * 26561b49440SChris Mason root->sectorsize; 26661b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 26761b49440SChris Mason struct btrfs_csum_item); 26861b49440SChris Mason } 26961b49440SChris Mason /* 27061b49440SChris Mason * this byte range must be able to fit inside 27161b49440SChris Mason * a single leaf so it will also fit inside a u32 27261b49440SChris Mason */ 273d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 27461b49440SChris Mason diff = diff / root->sectorsize; 275607d432dSJosef Bacik diff = diff * csum_size; 276facc8a22SMiao Xie count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> 277e4100d98SMiao Xie inode->i_sb->s_blocksize_bits); 278facc8a22SMiao Xie read_extent_buffer(path->nodes[0], csum, 2793de9d6b6SChris Mason ((unsigned long)item) + diff, 280e4100d98SMiao Xie csum_size * count); 28161b49440SChris Mason found: 282facc8a22SMiao Xie csum += count * csum_size; 283facc8a22SMiao Xie nblocks -= count; 284d2cbf2a2SLiu Bo bio_index += count; 285e4100d98SMiao Xie while (count--) { 286d20f7043SChris Mason disk_bytenr += bvec->bv_len; 2874b46fce2SJosef Bacik offset += bvec->bv_len; 28861b49440SChris Mason bvec++; 28961b49440SChris Mason } 290e4100d98SMiao Xie } 29161b49440SChris Mason btrfs_free_path(path); 29261b49440SChris Mason return 0; 29361b49440SChris Mason } 29461b49440SChris Mason 2954b46fce2SJosef Bacik int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 2964b46fce2SJosef Bacik struct bio *bio, u32 *dst) 2974b46fce2SJosef Bacik { 2984b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); 2994b46fce2SJosef Bacik } 3004b46fce2SJosef Bacik 3014b46fce2SJosef Bacik int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 30223ea8e5aSMiao Xie struct bio *bio, u64 offset) 3034b46fce2SJosef Bacik { 30423ea8e5aSMiao Xie return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); 3054b46fce2SJosef Bacik } 3064b46fce2SJosef Bacik 30717d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 308a2de733cSArne Jansen struct list_head *list, int search_commit) 30917d217feSYan Zheng { 31017d217feSYan Zheng struct btrfs_key key; 31117d217feSYan Zheng struct btrfs_path *path; 31217d217feSYan Zheng struct extent_buffer *leaf; 31317d217feSYan Zheng struct btrfs_ordered_sum *sums; 31417d217feSYan Zheng struct btrfs_csum_item *item; 3150678b618SMark Fasheh LIST_HEAD(tmplist); 31617d217feSYan Zheng unsigned long offset; 31717d217feSYan Zheng int ret; 31817d217feSYan Zheng size_t size; 31917d217feSYan Zheng u64 csum_end; 3206c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 32117d217feSYan Zheng 322d1b00a47SSatoru Takeuchi ASSERT(IS_ALIGNED(start, root->sectorsize) && 323d1b00a47SSatoru Takeuchi IS_ALIGNED(end + 1, root->sectorsize)); 3244277a9c3SJosef Bacik 32517d217feSYan Zheng path = btrfs_alloc_path(); 326d8926bb3SMark Fasheh if (!path) 327d8926bb3SMark Fasheh return -ENOMEM; 32817d217feSYan Zheng 329a2de733cSArne Jansen if (search_commit) { 330a2de733cSArne Jansen path->skip_locking = 1; 331a2de733cSArne Jansen path->reada = 2; 332a2de733cSArne Jansen path->search_commit_root = 1; 333a2de733cSArne Jansen } 334a2de733cSArne Jansen 33517d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 33617d217feSYan Zheng key.offset = start; 33717d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 33817d217feSYan Zheng 33907d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 34017d217feSYan Zheng if (ret < 0) 34117d217feSYan Zheng goto fail; 34217d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 34317d217feSYan Zheng leaf = path->nodes[0]; 34417d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 34517d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 34617d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 34717d217feSYan Zheng offset = (start - key.offset) >> 34817d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 34917d217feSYan Zheng if (offset * csum_size < 35017d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 35117d217feSYan Zheng path->slots[0]--; 35217d217feSYan Zheng } 35317d217feSYan Zheng } 35417d217feSYan Zheng 35517d217feSYan Zheng while (start <= end) { 35617d217feSYan Zheng leaf = path->nodes[0]; 35717d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 35807d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 35917d217feSYan Zheng if (ret < 0) 36017d217feSYan Zheng goto fail; 36117d217feSYan Zheng if (ret > 0) 36217d217feSYan Zheng break; 36317d217feSYan Zheng leaf = path->nodes[0]; 36417d217feSYan Zheng } 36517d217feSYan Zheng 36617d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 36717d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 368628c8282SZhi Yong Wu key.type != BTRFS_EXTENT_CSUM_KEY || 369628c8282SZhi Yong Wu key.offset > end) 37017d217feSYan Zheng break; 37117d217feSYan Zheng 37217d217feSYan Zheng if (key.offset > start) 37317d217feSYan Zheng start = key.offset; 37417d217feSYan Zheng 37517d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 37617d217feSYan Zheng csum_end = key.offset + (size / csum_size) * root->sectorsize; 37787b29b20SYan Zheng if (csum_end <= start) { 37887b29b20SYan Zheng path->slots[0]++; 37987b29b20SYan Zheng continue; 38087b29b20SYan Zheng } 38117d217feSYan Zheng 38207d400a6SYan Zheng csum_end = min(csum_end, end + 1); 38307d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 38407d400a6SYan Zheng struct btrfs_csum_item); 38507d400a6SYan Zheng while (start < csum_end) { 38607d400a6SYan Zheng size = min_t(size_t, csum_end - start, 38707d400a6SYan Zheng MAX_ORDERED_SUM_BYTES(root)); 38807d400a6SYan Zheng sums = kzalloc(btrfs_ordered_sum_size(root, size), 38907d400a6SYan Zheng GFP_NOFS); 3900678b618SMark Fasheh if (!sums) { 3910678b618SMark Fasheh ret = -ENOMEM; 3920678b618SMark Fasheh goto fail; 3930678b618SMark Fasheh } 39417d217feSYan Zheng 39517d217feSYan Zheng sums->bytenr = start; 396f51a4a18SMiao Xie sums->len = (int)size; 39717d217feSYan Zheng 39817d217feSYan Zheng offset = (start - key.offset) >> 39917d217feSYan Zheng root->fs_info->sb->s_blocksize_bits; 40017d217feSYan Zheng offset *= csum_size; 401f51a4a18SMiao Xie size >>= root->fs_info->sb->s_blocksize_bits; 40217d217feSYan Zheng 40307d400a6SYan Zheng read_extent_buffer(path->nodes[0], 404f51a4a18SMiao Xie sums->sums, 405f51a4a18SMiao Xie ((unsigned long)item) + offset, 406f51a4a18SMiao Xie csum_size * size); 40717d217feSYan Zheng 408f51a4a18SMiao Xie start += root->sectorsize * size; 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)) { 416*6e5aafb2SChris Mason sums = list_entry(tmplist.next, 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; 4303edf7d33SChris Mason struct btrfs_ordered_extent *ordered; 431e015640fSChris Mason char *data; 432e015640fSChris Mason struct bio_vec *bvec = bio->bi_io_vec; 433e015640fSChris Mason int bio_index = 0; 434f51a4a18SMiao Xie int index; 4353edf7d33SChris Mason unsigned long total_bytes = 0; 4363edf7d33SChris Mason unsigned long this_sum_bytes = 0; 4373edf7d33SChris Mason u64 offset; 438e015640fSChris Mason 439e6dcd2dcSChris Mason WARN_ON(bio->bi_vcnt <= 0); 4404f024f37SKent Overstreet sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size), 4414f024f37SKent Overstreet GFP_NOFS); 442e015640fSChris Mason if (!sums) 443e015640fSChris Mason return -ENOMEM; 4443edf7d33SChris Mason 4454f024f37SKent Overstreet sums->len = bio->bi_iter.bi_size; 446e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 447d20f7043SChris Mason 448d20f7043SChris Mason if (contig) 449d20f7043SChris Mason offset = file_start; 450d20f7043SChris Mason else 451d20f7043SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 452d20f7043SChris Mason 453d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 45479787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 4554f024f37SKent Overstreet sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; 456f51a4a18SMiao Xie index = 0; 457e015640fSChris Mason 458e015640fSChris Mason while (bio_index < bio->bi_vcnt) { 459d20f7043SChris Mason if (!contig) 4603edf7d33SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 461d20f7043SChris Mason 462e58dd74bSJosef Bacik if (offset >= ordered->file_offset + ordered->len || 463e58dd74bSJosef Bacik offset < ordered->file_offset) { 4643edf7d33SChris Mason unsigned long bytes_left; 4653edf7d33SChris Mason sums->len = this_sum_bytes; 4663edf7d33SChris Mason this_sum_bytes = 0; 4673edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4683edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4693edf7d33SChris Mason 4704f024f37SKent Overstreet bytes_left = bio->bi_iter.bi_size - total_bytes; 4713edf7d33SChris Mason 4723edf7d33SChris Mason sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), 4733edf7d33SChris Mason GFP_NOFS); 47479787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 4753edf7d33SChris Mason sums->len = bytes_left; 476d20f7043SChris Mason ordered = btrfs_lookup_ordered_extent(inode, offset); 47779787eaaSJeff Mahoney BUG_ON(!ordered); /* Logic error */ 4784f024f37SKent Overstreet sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) + 479f51a4a18SMiao Xie total_bytes; 480f51a4a18SMiao Xie index = 0; 4813edf7d33SChris Mason } 4823edf7d33SChris Mason 4837ac687d9SCong Wang data = kmap_atomic(bvec->bv_page); 484f51a4a18SMiao Xie sums->sums[index] = ~(u32)0; 485f51a4a18SMiao Xie sums->sums[index] = btrfs_csum_data(data + bvec->bv_offset, 486f51a4a18SMiao Xie sums->sums[index], 487e6dcd2dcSChris Mason bvec->bv_len); 4887ac687d9SCong Wang kunmap_atomic(data); 489f51a4a18SMiao Xie btrfs_csum_final(sums->sums[index], 490f51a4a18SMiao Xie (char *)(sums->sums + index)); 491ed98b56aSChris Mason 492e015640fSChris Mason bio_index++; 493f51a4a18SMiao Xie index++; 4943edf7d33SChris Mason total_bytes += bvec->bv_len; 4953edf7d33SChris Mason this_sum_bytes += bvec->bv_len; 496d20f7043SChris Mason offset += bvec->bv_len; 497e015640fSChris Mason bvec++; 498e015640fSChris Mason } 499ed98b56aSChris Mason this_sum_bytes = 0; 5003edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 5013edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 502e015640fSChris Mason return 0; 503e015640fSChris Mason } 504e015640fSChris Mason 505459931ecSChris Mason /* 506459931ecSChris Mason * helper function for csum removal, this expects the 507459931ecSChris Mason * key to describe the csum pointed to by the path, and it expects 508459931ecSChris Mason * the csum to overlap the range [bytenr, len] 509459931ecSChris Mason * 510459931ecSChris Mason * The csum should not be entirely contained in the range and the 511459931ecSChris Mason * range should not be entirely contained in the csum. 512459931ecSChris Mason * 513459931ecSChris Mason * This calls btrfs_truncate_item with the correct args based on the 514459931ecSChris Mason * overlap, and fixes up the key as required. 515459931ecSChris Mason */ 516afe5fea7STsutomu Itoh static noinline void truncate_one_csum(struct btrfs_root *root, 517459931ecSChris Mason struct btrfs_path *path, 518459931ecSChris Mason struct btrfs_key *key, 519459931ecSChris Mason u64 bytenr, u64 len) 520459931ecSChris Mason { 521459931ecSChris Mason struct extent_buffer *leaf; 5226c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 523459931ecSChris Mason u64 csum_end; 524459931ecSChris Mason u64 end_byte = bytenr + len; 525459931ecSChris Mason u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; 526459931ecSChris Mason 527459931ecSChris Mason leaf = path->nodes[0]; 528459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 529459931ecSChris Mason csum_end <<= root->fs_info->sb->s_blocksize_bits; 530459931ecSChris Mason csum_end += key->offset; 531459931ecSChris Mason 532459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 533459931ecSChris Mason /* 534459931ecSChris Mason * [ bytenr - len ] 535459931ecSChris Mason * [ ] 536459931ecSChris Mason * [csum ] 537459931ecSChris Mason * A simple truncate off the end of the item 538459931ecSChris Mason */ 539459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 540459931ecSChris Mason new_size *= csum_size; 541afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 1); 542459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 543459931ecSChris Mason end_byte > key->offset) { 544459931ecSChris Mason /* 545459931ecSChris Mason * [ bytenr - len ] 546459931ecSChris Mason * [ ] 547459931ecSChris Mason * [csum ] 548459931ecSChris Mason * we need to truncate from the beginning of the csum 549459931ecSChris Mason */ 550459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 551459931ecSChris Mason new_size *= csum_size; 552459931ecSChris Mason 553afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 0); 554459931ecSChris Mason 555459931ecSChris Mason key->offset = end_byte; 556afe5fea7STsutomu Itoh btrfs_set_item_key_safe(root, path, key); 557459931ecSChris Mason } else { 558459931ecSChris Mason BUG(); 559459931ecSChris Mason } 560459931ecSChris Mason } 561459931ecSChris Mason 562459931ecSChris Mason /* 563459931ecSChris Mason * deletes the csum items from the csum tree for a given 564459931ecSChris Mason * range of bytes. 565459931ecSChris Mason */ 566459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 567459931ecSChris Mason struct btrfs_root *root, u64 bytenr, u64 len) 568459931ecSChris Mason { 569459931ecSChris Mason struct btrfs_path *path; 570459931ecSChris Mason struct btrfs_key key; 571459931ecSChris Mason u64 end_byte = bytenr + len; 572459931ecSChris Mason u64 csum_end; 573459931ecSChris Mason struct extent_buffer *leaf; 574459931ecSChris Mason int ret; 5756c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 576459931ecSChris Mason int blocksize_bits = root->fs_info->sb->s_blocksize_bits; 577459931ecSChris Mason 578459931ecSChris Mason root = root->fs_info->csum_root; 579459931ecSChris Mason 580459931ecSChris Mason path = btrfs_alloc_path(); 5812a29edc6Sliubo if (!path) 5822a29edc6Sliubo return -ENOMEM; 583459931ecSChris Mason 584459931ecSChris Mason while (1) { 585459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 586459931ecSChris Mason key.offset = end_byte - 1; 587459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 588459931ecSChris Mason 589b9473439SChris Mason path->leave_spinning = 1; 590459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 591459931ecSChris Mason if (ret > 0) { 592459931ecSChris Mason if (path->slots[0] == 0) 59365a246c5STsutomu Itoh break; 594459931ecSChris Mason path->slots[0]--; 595ad0397a7SJosef Bacik } else if (ret < 0) { 59665a246c5STsutomu Itoh break; 597459931ecSChris Mason } 598ad0397a7SJosef Bacik 599459931ecSChris Mason leaf = path->nodes[0]; 600459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 601459931ecSChris Mason 602459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 603459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 604459931ecSChris Mason break; 605459931ecSChris Mason } 606459931ecSChris Mason 607459931ecSChris Mason if (key.offset >= end_byte) 608459931ecSChris Mason break; 609459931ecSChris Mason 610459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 611459931ecSChris Mason csum_end <<= blocksize_bits; 612459931ecSChris Mason csum_end += key.offset; 613459931ecSChris Mason 614459931ecSChris Mason /* this csum ends before we start, we're done */ 615459931ecSChris Mason if (csum_end <= bytenr) 616459931ecSChris Mason break; 617459931ecSChris Mason 618459931ecSChris Mason /* delete the entire item, it is inside our range */ 619459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 620459931ecSChris Mason ret = btrfs_del_item(trans, root, path); 62165a246c5STsutomu Itoh if (ret) 62265a246c5STsutomu Itoh goto out; 623dcbdd4dcSChris Mason if (key.offset == bytenr) 624dcbdd4dcSChris Mason break; 625459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 626459931ecSChris Mason unsigned long offset; 627459931ecSChris Mason unsigned long shift_len; 628459931ecSChris Mason unsigned long item_offset; 629459931ecSChris Mason /* 630459931ecSChris Mason * [ bytenr - len ] 631459931ecSChris Mason * [csum ] 632459931ecSChris Mason * 633459931ecSChris Mason * Our bytes are in the middle of the csum, 634459931ecSChris Mason * we need to split this item and insert a new one. 635459931ecSChris Mason * 636459931ecSChris Mason * But we can't drop the path because the 637459931ecSChris Mason * csum could change, get removed, extended etc. 638459931ecSChris Mason * 639459931ecSChris Mason * The trick here is the max size of a csum item leaves 640459931ecSChris Mason * enough room in the tree block for a single 641459931ecSChris Mason * item header. So, we split the item in place, 642459931ecSChris Mason * adding a new header pointing to the existing 643459931ecSChris Mason * bytes. Then we loop around again and we have 644459931ecSChris Mason * a nicely formed csum item that we can neatly 645459931ecSChris Mason * truncate. 646459931ecSChris Mason */ 647459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 648459931ecSChris Mason offset *= csum_size; 649459931ecSChris Mason 650459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 651459931ecSChris Mason 652459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 653459931ecSChris Mason path->slots[0]); 654459931ecSChris Mason 655459931ecSChris Mason memset_extent_buffer(leaf, 0, item_offset + offset, 656459931ecSChris Mason shift_len); 657459931ecSChris Mason key.offset = bytenr; 658459931ecSChris Mason 659459931ecSChris Mason /* 660459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 661459931ecSChris Mason * item changed size or key 662459931ecSChris Mason */ 663459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 66479787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 66579787eaaSJeff Mahoney btrfs_abort_transaction(trans, root, ret); 66679787eaaSJeff Mahoney goto out; 66779787eaaSJeff Mahoney } 668459931ecSChris Mason 669459931ecSChris Mason key.offset = end_byte - 1; 670459931ecSChris Mason } else { 671afe5fea7STsutomu Itoh truncate_one_csum(root, path, &key, bytenr, len); 672dcbdd4dcSChris Mason if (key.offset < bytenr) 673dcbdd4dcSChris Mason break; 674459931ecSChris Mason } 675b3b4aa74SDavid Sterba btrfs_release_path(path); 676459931ecSChris Mason } 67765a246c5STsutomu Itoh ret = 0; 678459931ecSChris Mason out: 679459931ecSChris Mason btrfs_free_path(path); 68065a246c5STsutomu Itoh return ret; 681459931ecSChris Mason } 682459931ecSChris Mason 683065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 684d20f7043SChris Mason struct btrfs_root *root, 685e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 686f254e52cSChris Mason { 687f254e52cSChris Mason struct btrfs_key file_key; 6886567e837SChris Mason struct btrfs_key found_key; 6895caf2a00SChris Mason struct btrfs_path *path; 690f254e52cSChris Mason struct btrfs_csum_item *item; 691065631f6SChris Mason struct btrfs_csum_item *item_end; 692ff79f819SChris Mason struct extent_buffer *leaf = NULL; 693f51a4a18SMiao Xie u64 next_offset; 694f51a4a18SMiao Xie u64 total_bytes = 0; 6956567e837SChris Mason u64 csum_offset; 696f51a4a18SMiao Xie u64 bytenr; 697f578d4bdSChris Mason u32 nritems; 698f578d4bdSChris Mason u32 ins_size; 699f51a4a18SMiao Xie int index = 0; 700f51a4a18SMiao Xie int found_next; 701f51a4a18SMiao Xie int ret; 7026c41761fSDavid Sterba u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 7036e92f5e6SChris Mason 7045caf2a00SChris Mason path = btrfs_alloc_path(); 705d8926bb3SMark Fasheh if (!path) 706d8926bb3SMark Fasheh return -ENOMEM; 707065631f6SChris Mason again: 708065631f6SChris Mason next_offset = (u64)-1; 709065631f6SChris Mason found_next = 0; 710f51a4a18SMiao Xie bytenr = sums->bytenr + total_bytes; 711d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 712f51a4a18SMiao Xie file_key.offset = bytenr; 713962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 714a429e513SChris Mason 715f51a4a18SMiao Xie item = btrfs_lookup_csum(trans, root, path, bytenr, 1); 716ff79f819SChris Mason if (!IS_ERR(item)) { 717639cb586SChris Mason ret = 0; 718f51a4a18SMiao Xie leaf = path->nodes[0]; 719f51a4a18SMiao Xie item_end = btrfs_item_ptr(leaf, path->slots[0], 720f51a4a18SMiao Xie struct btrfs_csum_item); 721f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((char *)item_end + 722f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 723a429e513SChris Mason goto found; 724ff79f819SChris Mason } 725a429e513SChris Mason ret = PTR_ERR(item); 7264a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7274a500fd1SYan, Zheng goto fail_unlock; 7284a500fd1SYan, Zheng 729a429e513SChris Mason if (ret == -EFBIG) { 730a429e513SChris Mason u32 item_size; 731a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7325f39d397SChris Mason leaf = path->nodes[0]; 7335f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 734607d432dSJosef Bacik if ((item_size / csum_size) >= 735607d432dSJosef Bacik MAX_CSUM_ITEMS(root, csum_size)) { 736a429e513SChris Mason /* already at max size, make a new one */ 737a429e513SChris Mason goto insert; 738a429e513SChris Mason } 739a429e513SChris Mason } else { 740f578d4bdSChris Mason int slot = path->slots[0] + 1; 741a429e513SChris Mason /* we didn't find a csum item, insert one */ 742f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 74335045bf2SFilipe Manana if (!nritems || (path->slots[0] >= nritems - 1)) { 744f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 745b56baf5bSYan if (ret == 1) 746f578d4bdSChris Mason found_next = 1; 747b56baf5bSYan if (ret != 0) 748f578d4bdSChris Mason goto insert; 74927b9a812SFilipe Manana slot = path->slots[0]; 750f578d4bdSChris Mason } 751f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 752d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 753d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 754f578d4bdSChris Mason found_next = 1; 755f578d4bdSChris Mason goto insert; 756f578d4bdSChris Mason } 757f578d4bdSChris Mason next_offset = found_key.offset; 758f578d4bdSChris Mason found_next = 1; 759a429e513SChris Mason goto insert; 760a429e513SChris Mason } 761a429e513SChris Mason 762a429e513SChris Mason /* 763a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 764a429e513SChris Mason * enough yet to put our csum in. Grow it 765a429e513SChris Mason */ 766b3b4aa74SDavid Sterba btrfs_release_path(path); 7676567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 768607d432dSJosef Bacik csum_size, 1); 7696567e837SChris Mason if (ret < 0) 77053863232SChris Mason goto fail_unlock; 771459931ecSChris Mason 772459931ecSChris Mason if (ret > 0) { 773459931ecSChris Mason if (path->slots[0] == 0) 7746567e837SChris Mason goto insert; 7756567e837SChris Mason path->slots[0]--; 776459931ecSChris Mason } 777459931ecSChris Mason 7785f39d397SChris Mason leaf = path->nodes[0]; 7795f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 780d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 7816567e837SChris Mason root->fs_info->sb->s_blocksize_bits; 782459931ecSChris Mason 783962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY || 784d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 785607d432dSJosef Bacik csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { 7866567e837SChris Mason goto insert; 7876567e837SChris Mason } 788459931ecSChris Mason 7892f697dc6SLiu Bo if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / 790607d432dSJosef Bacik csum_size) { 7912f697dc6SLiu Bo int extend_nr; 7922f697dc6SLiu Bo u64 tmp; 7932f697dc6SLiu Bo u32 diff; 7942f697dc6SLiu Bo u32 free_space; 795459931ecSChris Mason 7962f697dc6SLiu Bo if (btrfs_leaf_free_space(root, leaf) < 7972f697dc6SLiu Bo sizeof(struct btrfs_item) + csum_size * 2) 7982f697dc6SLiu Bo goto insert; 7992f697dc6SLiu Bo 8002f697dc6SLiu Bo free_space = btrfs_leaf_free_space(root, leaf) - 8012f697dc6SLiu Bo sizeof(struct btrfs_item) - csum_size; 802f51a4a18SMiao Xie tmp = sums->len - total_bytes; 8032f697dc6SLiu Bo tmp >>= root->fs_info->sb->s_blocksize_bits; 8042f697dc6SLiu Bo WARN_ON(tmp < 1); 8052f697dc6SLiu Bo 8062f697dc6SLiu Bo extend_nr = max_t(int, 1, (int)tmp); 8072f697dc6SLiu Bo diff = (csum_offset + extend_nr) * csum_size; 8082f697dc6SLiu Bo diff = min(diff, MAX_CSUM_ITEMS(root, csum_size) * csum_size); 809459931ecSChris Mason 8105f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 8112f697dc6SLiu Bo diff = min(free_space, diff); 8122f697dc6SLiu Bo diff /= csum_size; 8132f697dc6SLiu Bo diff *= csum_size; 814459931ecSChris Mason 8154b90c680STsutomu Itoh btrfs_extend_item(root, path, diff); 816f51a4a18SMiao Xie ret = 0; 8176567e837SChris Mason goto csum; 8186567e837SChris Mason } 8196567e837SChris Mason 8206567e837SChris Mason insert: 821b3b4aa74SDavid Sterba btrfs_release_path(path); 8226567e837SChris Mason csum_offset = 0; 823f578d4bdSChris Mason if (found_next) { 8242f697dc6SLiu Bo u64 tmp; 825d20f7043SChris Mason 826f51a4a18SMiao Xie tmp = sums->len - total_bytes; 827f578d4bdSChris Mason tmp >>= root->fs_info->sb->s_blocksize_bits; 8282f697dc6SLiu Bo tmp = min(tmp, (next_offset - file_key.offset) >> 8292f697dc6SLiu Bo root->fs_info->sb->s_blocksize_bits); 8302f697dc6SLiu Bo 831f578d4bdSChris Mason tmp = max((u64)1, tmp); 832607d432dSJosef Bacik tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); 833607d432dSJosef Bacik ins_size = csum_size * tmp; 834f578d4bdSChris Mason } else { 835607d432dSJosef Bacik ins_size = csum_size; 836f578d4bdSChris Mason } 837b9473439SChris Mason path->leave_spinning = 1; 8385caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 839f578d4bdSChris Mason ins_size); 840b9473439SChris Mason path->leave_spinning = 0; 84154aa1f4dSChris Mason if (ret < 0) 84253863232SChris Mason goto fail_unlock; 843fae7f21cSDulshani Gunawardhana if (WARN_ON(ret != 0)) 84453863232SChris Mason goto fail_unlock; 8455f39d397SChris Mason leaf = path->nodes[0]; 846f51a4a18SMiao Xie csum: 8475f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 848f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((unsigned char *)item + 849f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 850509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 851607d432dSJosef Bacik csum_offset * csum_size); 852b18c6685SChris Mason found: 853f51a4a18SMiao Xie ins_size = (u32)(sums->len - total_bytes) >> 854f51a4a18SMiao Xie root->fs_info->sb->s_blocksize_bits; 855f51a4a18SMiao Xie ins_size *= csum_size; 856f51a4a18SMiao Xie ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item, 857f51a4a18SMiao Xie ins_size); 858f51a4a18SMiao Xie write_extent_buffer(leaf, sums->sums + index, (unsigned long)item, 859f51a4a18SMiao Xie ins_size); 860aadfeb6eSChris Mason 861f51a4a18SMiao Xie ins_size /= csum_size; 862f51a4a18SMiao Xie total_bytes += ins_size * root->sectorsize; 863f51a4a18SMiao Xie index += ins_size; 864a6591715SChris Mason 8655caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 866e6dcd2dcSChris Mason if (total_bytes < sums->len) { 867b3b4aa74SDavid Sterba btrfs_release_path(path); 868b9473439SChris Mason cond_resched(); 869065631f6SChris Mason goto again; 870065631f6SChris Mason } 87153863232SChris Mason out: 8725caf2a00SChris Mason btrfs_free_path(path); 873f254e52cSChris Mason return ret; 87453863232SChris Mason 87553863232SChris Mason fail_unlock: 87653863232SChris Mason goto out; 877f254e52cSChris Mason } 8787ffbb598SFilipe Manana 8797ffbb598SFilipe Manana void btrfs_extent_item_to_extent_map(struct inode *inode, 8807ffbb598SFilipe Manana const struct btrfs_path *path, 8817ffbb598SFilipe Manana struct btrfs_file_extent_item *fi, 8827ffbb598SFilipe Manana const bool new_inline, 8837ffbb598SFilipe Manana struct extent_map *em) 8847ffbb598SFilipe Manana { 8857ffbb598SFilipe Manana struct btrfs_root *root = BTRFS_I(inode)->root; 8867ffbb598SFilipe Manana struct extent_buffer *leaf = path->nodes[0]; 8877ffbb598SFilipe Manana const int slot = path->slots[0]; 8887ffbb598SFilipe Manana struct btrfs_key key; 8897ffbb598SFilipe Manana u64 extent_start, extent_end; 8907ffbb598SFilipe Manana u64 bytenr; 8917ffbb598SFilipe Manana u8 type = btrfs_file_extent_type(leaf, fi); 8927ffbb598SFilipe Manana int compress_type = btrfs_file_extent_compression(leaf, fi); 8937ffbb598SFilipe Manana 8947ffbb598SFilipe Manana em->bdev = root->fs_info->fs_devices->latest_bdev; 8957ffbb598SFilipe Manana btrfs_item_key_to_cpu(leaf, &key, slot); 8967ffbb598SFilipe Manana extent_start = key.offset; 8977ffbb598SFilipe Manana 8987ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 8997ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9007ffbb598SFilipe Manana extent_end = extent_start + 9017ffbb598SFilipe Manana btrfs_file_extent_num_bytes(leaf, fi); 9027ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9037ffbb598SFilipe Manana size_t size; 9047ffbb598SFilipe Manana size = btrfs_file_extent_inline_len(leaf, slot, fi); 9057ffbb598SFilipe Manana extent_end = ALIGN(extent_start + size, root->sectorsize); 9067ffbb598SFilipe Manana } 9077ffbb598SFilipe Manana 9087ffbb598SFilipe Manana em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); 9097ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 9107ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9117ffbb598SFilipe Manana em->start = extent_start; 9127ffbb598SFilipe Manana em->len = extent_end - extent_start; 9137ffbb598SFilipe Manana em->orig_start = extent_start - 9147ffbb598SFilipe Manana btrfs_file_extent_offset(leaf, fi); 9157ffbb598SFilipe Manana em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); 9167ffbb598SFilipe Manana bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); 9177ffbb598SFilipe Manana if (bytenr == 0) { 9187ffbb598SFilipe Manana em->block_start = EXTENT_MAP_HOLE; 9197ffbb598SFilipe Manana return; 9207ffbb598SFilipe Manana } 9217ffbb598SFilipe Manana if (compress_type != BTRFS_COMPRESS_NONE) { 9227ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 9237ffbb598SFilipe Manana em->compress_type = compress_type; 9247ffbb598SFilipe Manana em->block_start = bytenr; 9257ffbb598SFilipe Manana em->block_len = em->orig_block_len; 9267ffbb598SFilipe Manana } else { 9277ffbb598SFilipe Manana bytenr += btrfs_file_extent_offset(leaf, fi); 9287ffbb598SFilipe Manana em->block_start = bytenr; 9297ffbb598SFilipe Manana em->block_len = em->len; 9307ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_PREALLOC) 9317ffbb598SFilipe Manana set_bit(EXTENT_FLAG_PREALLOC, &em->flags); 9327ffbb598SFilipe Manana } 9337ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9347ffbb598SFilipe Manana em->block_start = EXTENT_MAP_INLINE; 9357ffbb598SFilipe Manana em->start = extent_start; 9367ffbb598SFilipe Manana em->len = extent_end - extent_start; 9377ffbb598SFilipe Manana /* 9387ffbb598SFilipe Manana * Initialize orig_start and block_len with the same values 9397ffbb598SFilipe Manana * as in inode.c:btrfs_get_extent(). 9407ffbb598SFilipe Manana */ 9417ffbb598SFilipe Manana em->orig_start = EXTENT_MAP_HOLE; 9427ffbb598SFilipe Manana em->block_len = (u64)-1; 9437ffbb598SFilipe Manana if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) { 9447ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 9457ffbb598SFilipe Manana em->compress_type = compress_type; 9467ffbb598SFilipe Manana } 9477ffbb598SFilipe Manana } else { 9487ffbb598SFilipe Manana btrfs_err(root->fs_info, 9497ffbb598SFilipe Manana "unknown file extent item type %d, inode %llu, offset %llu, root %llu", 9507ffbb598SFilipe Manana type, btrfs_ino(inode), extent_start, 9517ffbb598SFilipe Manana root->root_key.objectid); 9527ffbb598SFilipe Manana } 9537ffbb598SFilipe Manana } 954