1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 26cbd5570SChris Mason /* 36cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 46cbd5570SChris Mason */ 56cbd5570SChris Mason 6065631f6SChris Mason #include <linux/bio.h> 75a0e3ad6STejun Heo #include <linux/slab.h> 8065631f6SChris Mason #include <linux/pagemap.h> 9065631f6SChris Mason #include <linux/highmem.h> 10a3d46aeaSNikolay Borisov #include <linux/sched/mm.h> 11d5178578SJohannes Thumshirn #include <crypto/hash.h> 121e1d2701SChris Mason #include "ctree.h" 13dee26a9fSChris Mason #include "disk-io.h" 149f5fae2fSChris Mason #include "transaction.h" 15facc8a22SMiao Xie #include "volumes.h" 161de037a4SChris Mason #include "print-tree.h" 17ebb8765bSAnand Jain #include "compression.h" 181e1d2701SChris Mason 1942049bf6SChris Mason #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ 2042049bf6SChris Mason sizeof(struct btrfs_item) * 2) / \ 2142049bf6SChris Mason size) - 1)) 2207d400a6SYan Zheng 23221b8318SZach Brown #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ 2409cbfeafSKirill A. Shutemov PAGE_SIZE)) 257ca4be45SChris Mason 261e25a2e3SJohannes Thumshirn static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info, 271e25a2e3SJohannes Thumshirn u16 csum_size) 281e25a2e3SJohannes Thumshirn { 291e25a2e3SJohannes Thumshirn u32 ncsums = (PAGE_SIZE - sizeof(struct btrfs_ordered_sum)) / csum_size; 301e25a2e3SJohannes Thumshirn 311e25a2e3SJohannes Thumshirn return ncsums * fs_info->sectorsize; 321e25a2e3SJohannes Thumshirn } 3307d400a6SYan Zheng 34b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 35dee26a9fSChris Mason struct btrfs_root *root, 36b18c6685SChris Mason u64 objectid, u64 pos, 37f2eb0a24SSage Weil u64 disk_offset, u64 disk_num_bytes, 38c8b97818SChris Mason u64 num_bytes, u64 offset, u64 ram_bytes, 39c8b97818SChris Mason u8 compression, u8 encryption, u16 other_encoding) 409f5fae2fSChris Mason { 41dee26a9fSChris Mason int ret = 0; 42dee26a9fSChris Mason struct btrfs_file_extent_item *item; 43dee26a9fSChris Mason struct btrfs_key file_key; 445caf2a00SChris Mason struct btrfs_path *path; 455f39d397SChris Mason struct extent_buffer *leaf; 46dee26a9fSChris Mason 475caf2a00SChris Mason path = btrfs_alloc_path(); 48db5b493aSTsutomu Itoh if (!path) 49db5b493aSTsutomu Itoh return -ENOMEM; 50dee26a9fSChris Mason file_key.objectid = objectid; 51b18c6685SChris Mason file_key.offset = pos; 52962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_DATA_KEY; 53dee26a9fSChris Mason 54b9473439SChris Mason path->leave_spinning = 1; 555caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 56dee26a9fSChris Mason sizeof(*item)); 5754aa1f4dSChris Mason if (ret < 0) 5854aa1f4dSChris Mason goto out; 5979787eaaSJeff Mahoney BUG_ON(ret); /* Can't happen */ 605f39d397SChris Mason leaf = path->nodes[0]; 615f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], 62dee26a9fSChris Mason struct btrfs_file_extent_item); 63f2eb0a24SSage Weil btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); 64db94535dSChris Mason btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 65f2eb0a24SSage Weil btrfs_set_file_extent_offset(leaf, item, offset); 66db94535dSChris Mason btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 67c8b97818SChris Mason btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); 685f39d397SChris Mason btrfs_set_file_extent_generation(leaf, item, trans->transid); 695f39d397SChris Mason btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 70c8b97818SChris Mason btrfs_set_file_extent_compression(leaf, item, compression); 71c8b97818SChris Mason btrfs_set_file_extent_encryption(leaf, item, encryption); 72c8b97818SChris Mason btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); 73c8b97818SChris Mason 745f39d397SChris Mason btrfs_mark_buffer_dirty(leaf); 7554aa1f4dSChris Mason out: 765caf2a00SChris Mason btrfs_free_path(path); 7754aa1f4dSChris Mason return ret; 789f5fae2fSChris Mason } 79dee26a9fSChris Mason 8048a3b636SEric Sandeen static struct btrfs_csum_item * 8148a3b636SEric Sandeen btrfs_lookup_csum(struct btrfs_trans_handle *trans, 82b18c6685SChris Mason struct btrfs_root *root, 836567e837SChris Mason struct btrfs_path *path, 84d20f7043SChris Mason u64 bytenr, int cow) 856567e837SChris Mason { 860b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 876567e837SChris Mason int ret; 886567e837SChris Mason struct btrfs_key file_key; 896567e837SChris Mason struct btrfs_key found_key; 906567e837SChris Mason struct btrfs_csum_item *item; 915f39d397SChris Mason struct extent_buffer *leaf; 926567e837SChris Mason u64 csum_offset = 0; 930b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 94a429e513SChris Mason int csums_in_item; 956567e837SChris Mason 96d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 97d20f7043SChris Mason file_key.offset = bytenr; 98962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 99b18c6685SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 1006567e837SChris Mason if (ret < 0) 1016567e837SChris Mason goto fail; 1025f39d397SChris Mason leaf = path->nodes[0]; 1036567e837SChris Mason if (ret > 0) { 1046567e837SChris Mason ret = 1; 10570b2befdSChris Mason if (path->slots[0] == 0) 1066567e837SChris Mason goto fail; 1076567e837SChris Mason path->slots[0]--; 1085f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 109962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY) 1106567e837SChris Mason goto fail; 111d20f7043SChris Mason 112d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 1130b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 1145f39d397SChris Mason csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 115607d432dSJosef Bacik csums_in_item /= csum_size; 116a429e513SChris Mason 11782d130ffSMiao Xie if (csum_offset == csums_in_item) { 118a429e513SChris Mason ret = -EFBIG; 1196567e837SChris Mason goto fail; 12082d130ffSMiao Xie } else if (csum_offset > csums_in_item) { 12182d130ffSMiao Xie goto fail; 1226567e837SChris Mason } 1236567e837SChris Mason } 1246567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 125509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 126607d432dSJosef Bacik csum_offset * csum_size); 1276567e837SChris Mason return item; 1286567e837SChris Mason fail: 1296567e837SChris Mason if (ret > 0) 130b18c6685SChris Mason ret = -ENOENT; 1316567e837SChris Mason return ERR_PTR(ret); 1326567e837SChris Mason } 1336567e837SChris Mason 134dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 135dee26a9fSChris Mason struct btrfs_root *root, 136dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1379773a788SChris Mason u64 offset, int mod) 138dee26a9fSChris Mason { 139dee26a9fSChris Mason int ret; 140dee26a9fSChris Mason struct btrfs_key file_key; 141dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 142dee26a9fSChris Mason int cow = mod != 0; 143dee26a9fSChris Mason 144dee26a9fSChris Mason file_key.objectid = objectid; 14570b2befdSChris Mason file_key.offset = offset; 146962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_DATA_KEY; 147dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 148dee26a9fSChris Mason return ret; 149dee26a9fSChris Mason } 150f254e52cSChris Mason 151*e62958fcSOmar Sandoval /** 152*e62958fcSOmar Sandoval * btrfs_lookup_bio_sums - Look up checksums for a bio. 153*e62958fcSOmar Sandoval * @inode: inode that the bio is for. 154*e62958fcSOmar Sandoval * @bio: bio embedded in btrfs_io_bio. 155*e62958fcSOmar Sandoval * @at_offset: If true, look up checksums for the extent at @offset. 156*e62958fcSOmar Sandoval * If false, use the page offsets from the bio. 157*e62958fcSOmar Sandoval * @offset: If @at_offset is true, offset in file to look up checksums for. 158*e62958fcSOmar Sandoval * Ignored otherwise. 159*e62958fcSOmar Sandoval * @dst: Buffer of size btrfs_super_csum_size() used to return checksum. If 160*e62958fcSOmar Sandoval * NULL, the checksum is returned in btrfs_io_bio(bio)->csum instead. 161*e62958fcSOmar Sandoval * 162*e62958fcSOmar Sandoval * Return: BLK_STS_RESOURCE if allocating memory fails, BLK_STS_OK otherwise. 163*e62958fcSOmar Sandoval */ 164*e62958fcSOmar Sandoval blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, 165*e62958fcSOmar Sandoval bool at_offset, u64 offset, u8 *dst) 16661b49440SChris Mason { 1670b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 16817347cecSLiu Bo struct bio_vec bvec; 16917347cecSLiu Bo struct bvec_iter iter; 170facc8a22SMiao Xie struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); 171facc8a22SMiao Xie struct btrfs_csum_item *item = NULL; 172facc8a22SMiao Xie struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 173facc8a22SMiao Xie struct btrfs_path *path; 174facc8a22SMiao Xie u8 *csum; 17561b49440SChris Mason u64 item_start_offset = 0; 17661b49440SChris Mason u64 item_last_offset = 0; 177d20f7043SChris Mason u64 disk_bytenr; 178c40a3d38SChandan Rajendra u64 page_bytes_left; 17961b49440SChris Mason u32 diff; 180facc8a22SMiao Xie int nblocks; 18117347cecSLiu Bo int count = 0; 1820b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 18361b49440SChris Mason 18461b49440SChris Mason path = btrfs_alloc_path(); 185c2db1073STsutomu Itoh if (!path) 1864e4cbee9SChristoph Hellwig return BLK_STS_RESOURCE; 187facc8a22SMiao Xie 1884f024f37SKent Overstreet nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits; 189facc8a22SMiao Xie if (!dst) { 190facc8a22SMiao Xie if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { 19131fecccbSDavid Sterba btrfs_bio->csum = kmalloc_array(nblocks, csum_size, 19231fecccbSDavid Sterba GFP_NOFS); 19331fecccbSDavid Sterba if (!btrfs_bio->csum) { 194facc8a22SMiao Xie btrfs_free_path(path); 1954e4cbee9SChristoph Hellwig return BLK_STS_RESOURCE; 196facc8a22SMiao Xie } 197facc8a22SMiao Xie } else { 198facc8a22SMiao Xie btrfs_bio->csum = btrfs_bio->csum_inline; 199facc8a22SMiao Xie } 200facc8a22SMiao Xie csum = btrfs_bio->csum; 201facc8a22SMiao Xie } else { 20210fe6ca8SJohannes Thumshirn csum = dst; 203facc8a22SMiao Xie } 204facc8a22SMiao Xie 20509cbfeafSKirill A. Shutemov if (bio->bi_iter.bi_size > PAGE_SIZE * 8) 206e4058b54SDavid Sterba path->reada = READA_FORWARD; 20761b49440SChris Mason 2082cf8572dSChris Mason /* 2092cf8572dSChris Mason * the free space stuff is only read when it hasn't been 2102cf8572dSChris Mason * updated in the current transaction. So, we can safely 2112cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 2122cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 2132cf8572dSChris Mason */ 21470ddc553SNikolay Borisov if (btrfs_is_free_space_inode(BTRFS_I(inode))) { 2152cf8572dSChris Mason path->search_commit_root = 1; 216ddf23b3fSJosef Bacik path->skip_locking = 1; 217ddf23b3fSJosef Bacik } 2182cf8572dSChris Mason 2194f024f37SKent Overstreet disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; 220c40a3d38SChandan Rajendra 22117347cecSLiu Bo bio_for_each_segment(bvec, bio, iter) { 22217347cecSLiu Bo page_bytes_left = bvec.bv_len; 2234989d277SChristoph Hellwig if (count) 2244989d277SChristoph Hellwig goto next; 2254989d277SChristoph Hellwig 226*e62958fcSOmar Sandoval if (!at_offset) 22717347cecSLiu Bo offset = page_offset(bvec.bv_page) + bvec.bv_offset; 228facc8a22SMiao Xie count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, 2291e25a2e3SJohannes Thumshirn csum, nblocks); 230e4100d98SMiao Xie if (count) 23161b49440SChris Mason goto found; 23261b49440SChris Mason 233d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 234d20f7043SChris Mason disk_bytenr >= item_last_offset) { 23561b49440SChris Mason struct btrfs_key found_key; 23661b49440SChris Mason u32 item_size; 23761b49440SChris Mason 23861b49440SChris Mason if (item) 239b3b4aa74SDavid Sterba btrfs_release_path(path); 2400b246afaSJeff Mahoney item = btrfs_lookup_csum(NULL, fs_info->csum_root, 241d20f7043SChris Mason path, disk_bytenr, 0); 24261b49440SChris Mason if (IS_ERR(item)) { 243e4100d98SMiao Xie count = 1; 244facc8a22SMiao Xie memset(csum, 0, csum_size); 24517d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 24617d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 24717d217feSYan Zheng set_extent_bits(io_tree, offset, 2480b246afaSJeff Mahoney offset + fs_info->sectorsize - 1, 249ceeb0ae7SDavid Sterba EXTENT_NODATASUM); 25017d217feSYan Zheng } else { 2510b246afaSJeff Mahoney btrfs_info_rl(fs_info, 252efe120a0SFrank Holton "no csum found for inode %llu start %llu", 2534a0cc7caSNikolay Borisov btrfs_ino(BTRFS_I(inode)), offset); 25417d217feSYan Zheng } 2556dab8157SChris Mason item = NULL; 256b3b4aa74SDavid Sterba btrfs_release_path(path); 25761b49440SChris Mason goto found; 25861b49440SChris Mason } 25961b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 26061b49440SChris Mason path->slots[0]); 26161b49440SChris Mason 26261b49440SChris Mason item_start_offset = found_key.offset; 26361b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 26461b49440SChris Mason path->slots[0]); 26561b49440SChris Mason item_last_offset = item_start_offset + 266607d432dSJosef Bacik (item_size / csum_size) * 2670b246afaSJeff Mahoney fs_info->sectorsize; 26861b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 26961b49440SChris Mason struct btrfs_csum_item); 27061b49440SChris Mason } 27161b49440SChris Mason /* 27261b49440SChris Mason * this byte range must be able to fit inside 27361b49440SChris Mason * a single leaf so it will also fit inside a u32 27461b49440SChris Mason */ 275d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 2760b246afaSJeff Mahoney diff = diff / fs_info->sectorsize; 277607d432dSJosef Bacik diff = diff * csum_size; 278facc8a22SMiao Xie count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> 279e4100d98SMiao Xie inode->i_sb->s_blocksize_bits); 280facc8a22SMiao Xie read_extent_buffer(path->nodes[0], csum, 2813de9d6b6SChris Mason ((unsigned long)item) + diff, 282e4100d98SMiao Xie csum_size * count); 28361b49440SChris Mason found: 284facc8a22SMiao Xie csum += count * csum_size; 285facc8a22SMiao Xie nblocks -= count; 2864989d277SChristoph Hellwig next: 287e4100d98SMiao Xie while (count--) { 2880b246afaSJeff Mahoney disk_bytenr += fs_info->sectorsize; 2890b246afaSJeff Mahoney offset += fs_info->sectorsize; 2900b246afaSJeff Mahoney page_bytes_left -= fs_info->sectorsize; 2914989d277SChristoph Hellwig if (!page_bytes_left) 2924989d277SChristoph Hellwig break; /* move to next bio */ 2934989d277SChristoph Hellwig } 2944989d277SChristoph Hellwig } 2954989d277SChristoph Hellwig 296389f239cSChris Mason WARN_ON_ONCE(count); 29761b49440SChris Mason btrfs_free_path(path); 298*e62958fcSOmar Sandoval return BLK_STS_OK; 2994b46fce2SJosef Bacik } 3004b46fce2SJosef Bacik 30117d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 302a2de733cSArne Jansen struct list_head *list, int search_commit) 30317d217feSYan Zheng { 3040b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 30517d217feSYan Zheng struct btrfs_key key; 30617d217feSYan Zheng struct btrfs_path *path; 30717d217feSYan Zheng struct extent_buffer *leaf; 30817d217feSYan Zheng struct btrfs_ordered_sum *sums; 30917d217feSYan Zheng struct btrfs_csum_item *item; 3100678b618SMark Fasheh LIST_HEAD(tmplist); 31117d217feSYan Zheng unsigned long offset; 31217d217feSYan Zheng int ret; 31317d217feSYan Zheng size_t size; 31417d217feSYan Zheng u64 csum_end; 3150b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 31617d217feSYan Zheng 3170b246afaSJeff Mahoney ASSERT(IS_ALIGNED(start, fs_info->sectorsize) && 3180b246afaSJeff Mahoney IS_ALIGNED(end + 1, fs_info->sectorsize)); 3194277a9c3SJosef Bacik 32017d217feSYan Zheng path = btrfs_alloc_path(); 321d8926bb3SMark Fasheh if (!path) 322d8926bb3SMark Fasheh return -ENOMEM; 32317d217feSYan Zheng 324a2de733cSArne Jansen if (search_commit) { 325a2de733cSArne Jansen path->skip_locking = 1; 326e4058b54SDavid Sterba path->reada = READA_FORWARD; 327a2de733cSArne Jansen path->search_commit_root = 1; 328a2de733cSArne Jansen } 329a2de733cSArne Jansen 33017d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 33117d217feSYan Zheng key.offset = start; 33217d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 33317d217feSYan Zheng 33407d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 33517d217feSYan Zheng if (ret < 0) 33617d217feSYan Zheng goto fail; 33717d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 33817d217feSYan Zheng leaf = path->nodes[0]; 33917d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 34017d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 34117d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 34217d217feSYan Zheng offset = (start - key.offset) >> 3430b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 34417d217feSYan Zheng if (offset * csum_size < 34517d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 34617d217feSYan Zheng path->slots[0]--; 34717d217feSYan Zheng } 34817d217feSYan Zheng } 34917d217feSYan Zheng 35017d217feSYan Zheng while (start <= end) { 35117d217feSYan Zheng leaf = path->nodes[0]; 35217d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 35307d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 35417d217feSYan Zheng if (ret < 0) 35517d217feSYan Zheng goto fail; 35617d217feSYan Zheng if (ret > 0) 35717d217feSYan Zheng break; 35817d217feSYan Zheng leaf = path->nodes[0]; 35917d217feSYan Zheng } 36017d217feSYan Zheng 36117d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 36217d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 363628c8282SZhi Yong Wu key.type != BTRFS_EXTENT_CSUM_KEY || 364628c8282SZhi Yong Wu key.offset > end) 36517d217feSYan Zheng break; 36617d217feSYan Zheng 36717d217feSYan Zheng if (key.offset > start) 36817d217feSYan Zheng start = key.offset; 36917d217feSYan Zheng 37017d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 3710b246afaSJeff Mahoney csum_end = key.offset + (size / csum_size) * fs_info->sectorsize; 37287b29b20SYan Zheng if (csum_end <= start) { 37387b29b20SYan Zheng path->slots[0]++; 37487b29b20SYan Zheng continue; 37587b29b20SYan Zheng } 37617d217feSYan Zheng 37707d400a6SYan Zheng csum_end = min(csum_end, end + 1); 37807d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 37907d400a6SYan Zheng struct btrfs_csum_item); 38007d400a6SYan Zheng while (start < csum_end) { 38107d400a6SYan Zheng size = min_t(size_t, csum_end - start, 3821e25a2e3SJohannes Thumshirn max_ordered_sum_bytes(fs_info, csum_size)); 3830b246afaSJeff Mahoney sums = kzalloc(btrfs_ordered_sum_size(fs_info, size), 38407d400a6SYan Zheng GFP_NOFS); 3850678b618SMark Fasheh if (!sums) { 3860678b618SMark Fasheh ret = -ENOMEM; 3870678b618SMark Fasheh goto fail; 3880678b618SMark Fasheh } 38917d217feSYan Zheng 39017d217feSYan Zheng sums->bytenr = start; 391f51a4a18SMiao Xie sums->len = (int)size; 39217d217feSYan Zheng 39317d217feSYan Zheng offset = (start - key.offset) >> 3940b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 39517d217feSYan Zheng offset *= csum_size; 3960b246afaSJeff Mahoney size >>= fs_info->sb->s_blocksize_bits; 39717d217feSYan Zheng 39807d400a6SYan Zheng read_extent_buffer(path->nodes[0], 399f51a4a18SMiao Xie sums->sums, 400f51a4a18SMiao Xie ((unsigned long)item) + offset, 401f51a4a18SMiao Xie csum_size * size); 40217d217feSYan Zheng 4030b246afaSJeff Mahoney start += fs_info->sectorsize * size; 4040678b618SMark Fasheh list_add_tail(&sums->list, &tmplist); 40507d400a6SYan Zheng } 40617d217feSYan Zheng path->slots[0]++; 40717d217feSYan Zheng } 40817d217feSYan Zheng ret = 0; 40917d217feSYan Zheng fail: 4100678b618SMark Fasheh while (ret < 0 && !list_empty(&tmplist)) { 4116e5aafb2SChris Mason sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); 4120678b618SMark Fasheh list_del(&sums->list); 4130678b618SMark Fasheh kfree(sums); 4140678b618SMark Fasheh } 4150678b618SMark Fasheh list_splice_tail(&tmplist, list); 4160678b618SMark Fasheh 41717d217feSYan Zheng btrfs_free_path(path); 41817d217feSYan Zheng return ret; 41917d217feSYan Zheng } 42017d217feSYan Zheng 42151d470aeSNikolay Borisov /* 42251d470aeSNikolay Borisov * btrfs_csum_one_bio - Calculates checksums of the data contained inside a bio 42351d470aeSNikolay Borisov * @inode: Owner of the data inside the bio 42451d470aeSNikolay Borisov * @bio: Contains the data to be checksummed 42551d470aeSNikolay Borisov * @file_start: offset in file this bio begins to describe 42651d470aeSNikolay Borisov * @contig: Boolean. If true/1 means all bio vecs in this bio are 42751d470aeSNikolay Borisov * contiguous and they begin at @file_start in the file. False/0 42851d470aeSNikolay Borisov * means this bio can contains potentially discontigous bio vecs 42951d470aeSNikolay Borisov * so the logical offset of each should be calculated separately. 43051d470aeSNikolay Borisov */ 4314e4cbee9SChristoph Hellwig blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio, 4322ff7e61eSJeff Mahoney u64 file_start, int contig) 433e015640fSChris Mason { 4340b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 435d5178578SJohannes Thumshirn SHASH_DESC_ON_STACK(shash, fs_info->csum_shash); 436e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums; 4376cd7ce49SChristoph Hellwig struct btrfs_ordered_extent *ordered = NULL; 438e015640fSChris Mason char *data; 43917347cecSLiu Bo struct bvec_iter iter; 44017347cecSLiu Bo struct bio_vec bvec; 441f51a4a18SMiao Xie int index; 442c40a3d38SChandan Rajendra int nr_sectors; 4433edf7d33SChris Mason unsigned long total_bytes = 0; 4443edf7d33SChris Mason unsigned long this_sum_bytes = 0; 44517347cecSLiu Bo int i; 4463edf7d33SChris Mason u64 offset; 447a3d46aeaSNikolay Borisov unsigned nofs_flag; 4481e25a2e3SJohannes Thumshirn const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 449e015640fSChris Mason 450a3d46aeaSNikolay Borisov nofs_flag = memalloc_nofs_save(); 451a3d46aeaSNikolay Borisov sums = kvzalloc(btrfs_ordered_sum_size(fs_info, bio->bi_iter.bi_size), 452a3d46aeaSNikolay Borisov GFP_KERNEL); 453a3d46aeaSNikolay Borisov memalloc_nofs_restore(nofs_flag); 454a3d46aeaSNikolay Borisov 455e015640fSChris Mason if (!sums) 4564e4cbee9SChristoph Hellwig return BLK_STS_RESOURCE; 4573edf7d33SChris Mason 4584f024f37SKent Overstreet sums->len = bio->bi_iter.bi_size; 459e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 460d20f7043SChris Mason 461d20f7043SChris Mason if (contig) 462d20f7043SChris Mason offset = file_start; 463d20f7043SChris Mason else 4646cd7ce49SChristoph Hellwig offset = 0; /* shut up gcc */ 465d20f7043SChris Mason 4664f024f37SKent Overstreet sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; 467f51a4a18SMiao Xie index = 0; 468e015640fSChris Mason 469d5178578SJohannes Thumshirn shash->tfm = fs_info->csum_shash; 470d5178578SJohannes Thumshirn 47117347cecSLiu Bo bio_for_each_segment(bvec, bio, iter) { 472d20f7043SChris Mason if (!contig) 47317347cecSLiu Bo offset = page_offset(bvec.bv_page) + bvec.bv_offset; 474d20f7043SChris Mason 4756cd7ce49SChristoph Hellwig if (!ordered) { 4766cd7ce49SChristoph Hellwig ordered = btrfs_lookup_ordered_extent(inode, offset); 4776cd7ce49SChristoph Hellwig BUG_ON(!ordered); /* Logic error */ 4786cd7ce49SChristoph Hellwig } 4796cd7ce49SChristoph Hellwig 4800b246afaSJeff Mahoney nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, 48117347cecSLiu Bo bvec.bv_len + fs_info->sectorsize 482c40a3d38SChandan Rajendra - 1); 483c40a3d38SChandan Rajendra 484c40a3d38SChandan Rajendra for (i = 0; i < nr_sectors; i++) { 485e58dd74bSJosef Bacik if (offset >= ordered->file_offset + ordered->len || 486e58dd74bSJosef Bacik offset < ordered->file_offset) { 4873edf7d33SChris Mason unsigned long bytes_left; 488c40a3d38SChandan Rajendra 4893edf7d33SChris Mason sums->len = this_sum_bytes; 4903edf7d33SChris Mason this_sum_bytes = 0; 491f9756261SNikolay Borisov btrfs_add_ordered_sum(ordered, sums); 4923edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4933edf7d33SChris Mason 4944f024f37SKent Overstreet bytes_left = bio->bi_iter.bi_size - total_bytes; 4953edf7d33SChris Mason 496a3d46aeaSNikolay Borisov nofs_flag = memalloc_nofs_save(); 497a3d46aeaSNikolay Borisov sums = kvzalloc(btrfs_ordered_sum_size(fs_info, 498a3d46aeaSNikolay Borisov bytes_left), GFP_KERNEL); 499a3d46aeaSNikolay Borisov memalloc_nofs_restore(nofs_flag); 50079787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 5013edf7d33SChris Mason sums->len = bytes_left; 502c40a3d38SChandan Rajendra ordered = btrfs_lookup_ordered_extent(inode, 503c40a3d38SChandan Rajendra offset); 504c40a3d38SChandan Rajendra ASSERT(ordered); /* Logic error */ 505c40a3d38SChandan Rajendra sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) 506c40a3d38SChandan Rajendra + total_bytes; 507f51a4a18SMiao Xie index = 0; 508c40a3d38SChandan Rajendra } 509c40a3d38SChandan Rajendra 510d5178578SJohannes Thumshirn crypto_shash_init(shash); 511443c8e2aSJohannes Thumshirn data = kmap_atomic(bvec.bv_page); 512d5178578SJohannes Thumshirn crypto_shash_update(shash, data + bvec.bv_offset 5130b246afaSJeff Mahoney + (i * fs_info->sectorsize), 5140b246afaSJeff Mahoney fs_info->sectorsize); 515443c8e2aSJohannes Thumshirn kunmap_atomic(data); 516d5178578SJohannes Thumshirn crypto_shash_final(shash, (char *)(sums->sums + index)); 5171e25a2e3SJohannes Thumshirn index += csum_size; 5180b246afaSJeff Mahoney offset += fs_info->sectorsize; 5190b246afaSJeff Mahoney this_sum_bytes += fs_info->sectorsize; 5200b246afaSJeff Mahoney total_bytes += fs_info->sectorsize; 521c40a3d38SChandan Rajendra } 522c40a3d38SChandan Rajendra 523e015640fSChris Mason } 524ed98b56aSChris Mason this_sum_bytes = 0; 525f9756261SNikolay Borisov btrfs_add_ordered_sum(ordered, sums); 5263edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 527e015640fSChris Mason return 0; 528e015640fSChris Mason } 529e015640fSChris Mason 530459931ecSChris Mason /* 531459931ecSChris Mason * helper function for csum removal, this expects the 532459931ecSChris Mason * key to describe the csum pointed to by the path, and it expects 533459931ecSChris Mason * the csum to overlap the range [bytenr, len] 534459931ecSChris Mason * 535459931ecSChris Mason * The csum should not be entirely contained in the range and the 536459931ecSChris Mason * range should not be entirely contained in the csum. 537459931ecSChris Mason * 538459931ecSChris Mason * This calls btrfs_truncate_item with the correct args based on the 539459931ecSChris Mason * overlap, and fixes up the key as required. 540459931ecSChris Mason */ 5412ff7e61eSJeff Mahoney static noinline void truncate_one_csum(struct btrfs_fs_info *fs_info, 542459931ecSChris Mason struct btrfs_path *path, 543459931ecSChris Mason struct btrfs_key *key, 544459931ecSChris Mason u64 bytenr, u64 len) 545459931ecSChris Mason { 546459931ecSChris Mason struct extent_buffer *leaf; 5470b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 548459931ecSChris Mason u64 csum_end; 549459931ecSChris Mason u64 end_byte = bytenr + len; 5500b246afaSJeff Mahoney u32 blocksize_bits = fs_info->sb->s_blocksize_bits; 551459931ecSChris Mason 552459931ecSChris Mason leaf = path->nodes[0]; 553459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 5540b246afaSJeff Mahoney csum_end <<= fs_info->sb->s_blocksize_bits; 555459931ecSChris Mason csum_end += key->offset; 556459931ecSChris Mason 557459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 558459931ecSChris Mason /* 559459931ecSChris Mason * [ bytenr - len ] 560459931ecSChris Mason * [ ] 561459931ecSChris Mason * [csum ] 562459931ecSChris Mason * A simple truncate off the end of the item 563459931ecSChris Mason */ 564459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 565459931ecSChris Mason new_size *= csum_size; 56678ac4f9eSDavid Sterba btrfs_truncate_item(path, new_size, 1); 567459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 568459931ecSChris Mason end_byte > key->offset) { 569459931ecSChris Mason /* 570459931ecSChris Mason * [ bytenr - len ] 571459931ecSChris Mason * [ ] 572459931ecSChris Mason * [csum ] 573459931ecSChris Mason * we need to truncate from the beginning of the csum 574459931ecSChris Mason */ 575459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 576459931ecSChris Mason new_size *= csum_size; 577459931ecSChris Mason 57878ac4f9eSDavid Sterba btrfs_truncate_item(path, new_size, 0); 579459931ecSChris Mason 580459931ecSChris Mason key->offset = end_byte; 5810b246afaSJeff Mahoney btrfs_set_item_key_safe(fs_info, path, key); 582459931ecSChris Mason } else { 583459931ecSChris Mason BUG(); 584459931ecSChris Mason } 585459931ecSChris Mason } 586459931ecSChris Mason 587459931ecSChris Mason /* 588459931ecSChris Mason * deletes the csum items from the csum tree for a given 589459931ecSChris Mason * range of bytes. 590459931ecSChris Mason */ 591459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 59240e046acSFilipe Manana struct btrfs_root *root, u64 bytenr, u64 len) 593459931ecSChris Mason { 59440e046acSFilipe Manana struct btrfs_fs_info *fs_info = trans->fs_info; 595459931ecSChris Mason struct btrfs_path *path; 596459931ecSChris Mason struct btrfs_key key; 597459931ecSChris Mason u64 end_byte = bytenr + len; 598459931ecSChris Mason u64 csum_end; 599459931ecSChris Mason struct extent_buffer *leaf; 600459931ecSChris Mason int ret; 6010b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 6020b246afaSJeff Mahoney int blocksize_bits = fs_info->sb->s_blocksize_bits; 603459931ecSChris Mason 60440e046acSFilipe Manana ASSERT(root == fs_info->csum_root || 60540e046acSFilipe Manana root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID); 60640e046acSFilipe Manana 607459931ecSChris Mason path = btrfs_alloc_path(); 6082a29edc6Sliubo if (!path) 6092a29edc6Sliubo return -ENOMEM; 610459931ecSChris Mason 611459931ecSChris Mason while (1) { 612459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 613459931ecSChris Mason key.offset = end_byte - 1; 614459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 615459931ecSChris Mason 616b9473439SChris Mason path->leave_spinning = 1; 617459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 618459931ecSChris Mason if (ret > 0) { 619459931ecSChris Mason if (path->slots[0] == 0) 62065a246c5STsutomu Itoh break; 621459931ecSChris Mason path->slots[0]--; 622ad0397a7SJosef Bacik } else if (ret < 0) { 62365a246c5STsutomu Itoh break; 624459931ecSChris Mason } 625ad0397a7SJosef Bacik 626459931ecSChris Mason leaf = path->nodes[0]; 627459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 628459931ecSChris Mason 629459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 630459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 631459931ecSChris Mason break; 632459931ecSChris Mason } 633459931ecSChris Mason 634459931ecSChris Mason if (key.offset >= end_byte) 635459931ecSChris Mason break; 636459931ecSChris Mason 637459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 638459931ecSChris Mason csum_end <<= blocksize_bits; 639459931ecSChris Mason csum_end += key.offset; 640459931ecSChris Mason 641459931ecSChris Mason /* this csum ends before we start, we're done */ 642459931ecSChris Mason if (csum_end <= bytenr) 643459931ecSChris Mason break; 644459931ecSChris Mason 645459931ecSChris Mason /* delete the entire item, it is inside our range */ 646459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 6476f546216SFilipe Manana int del_nr = 1; 6486f546216SFilipe Manana 6496f546216SFilipe Manana /* 6506f546216SFilipe Manana * Check how many csum items preceding this one in this 6516f546216SFilipe Manana * leaf correspond to our range and then delete them all 6526f546216SFilipe Manana * at once. 6536f546216SFilipe Manana */ 6546f546216SFilipe Manana if (key.offset > bytenr && path->slots[0] > 0) { 6556f546216SFilipe Manana int slot = path->slots[0] - 1; 6566f546216SFilipe Manana 6576f546216SFilipe Manana while (slot >= 0) { 6586f546216SFilipe Manana struct btrfs_key pk; 6596f546216SFilipe Manana 6606f546216SFilipe Manana btrfs_item_key_to_cpu(leaf, &pk, slot); 6616f546216SFilipe Manana if (pk.offset < bytenr || 6626f546216SFilipe Manana pk.type != BTRFS_EXTENT_CSUM_KEY || 6636f546216SFilipe Manana pk.objectid != 6646f546216SFilipe Manana BTRFS_EXTENT_CSUM_OBJECTID) 6656f546216SFilipe Manana break; 6666f546216SFilipe Manana path->slots[0] = slot; 6676f546216SFilipe Manana del_nr++; 6686f546216SFilipe Manana key.offset = pk.offset; 6696f546216SFilipe Manana slot--; 6706f546216SFilipe Manana } 6716f546216SFilipe Manana } 6726f546216SFilipe Manana ret = btrfs_del_items(trans, root, path, 6736f546216SFilipe Manana path->slots[0], del_nr); 67465a246c5STsutomu Itoh if (ret) 67565a246c5STsutomu Itoh goto out; 676dcbdd4dcSChris Mason if (key.offset == bytenr) 677dcbdd4dcSChris Mason break; 678459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 679459931ecSChris Mason unsigned long offset; 680459931ecSChris Mason unsigned long shift_len; 681459931ecSChris Mason unsigned long item_offset; 682459931ecSChris Mason /* 683459931ecSChris Mason * [ bytenr - len ] 684459931ecSChris Mason * [csum ] 685459931ecSChris Mason * 686459931ecSChris Mason * Our bytes are in the middle of the csum, 687459931ecSChris Mason * we need to split this item and insert a new one. 688459931ecSChris Mason * 689459931ecSChris Mason * But we can't drop the path because the 690459931ecSChris Mason * csum could change, get removed, extended etc. 691459931ecSChris Mason * 692459931ecSChris Mason * The trick here is the max size of a csum item leaves 693459931ecSChris Mason * enough room in the tree block for a single 694459931ecSChris Mason * item header. So, we split the item in place, 695459931ecSChris Mason * adding a new header pointing to the existing 696459931ecSChris Mason * bytes. Then we loop around again and we have 697459931ecSChris Mason * a nicely formed csum item that we can neatly 698459931ecSChris Mason * truncate. 699459931ecSChris Mason */ 700459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 701459931ecSChris Mason offset *= csum_size; 702459931ecSChris Mason 703459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 704459931ecSChris Mason 705459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 706459931ecSChris Mason path->slots[0]); 707459931ecSChris Mason 708b159fa28SDavid Sterba memzero_extent_buffer(leaf, item_offset + offset, 709459931ecSChris Mason shift_len); 710459931ecSChris Mason key.offset = bytenr; 711459931ecSChris Mason 712459931ecSChris Mason /* 713459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 714459931ecSChris Mason * item changed size or key 715459931ecSChris Mason */ 716459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 71779787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 71866642832SJeff Mahoney btrfs_abort_transaction(trans, ret); 71979787eaaSJeff Mahoney goto out; 72079787eaaSJeff Mahoney } 721459931ecSChris Mason 722459931ecSChris Mason key.offset = end_byte - 1; 723459931ecSChris Mason } else { 7242ff7e61eSJeff Mahoney truncate_one_csum(fs_info, path, &key, bytenr, len); 725dcbdd4dcSChris Mason if (key.offset < bytenr) 726dcbdd4dcSChris Mason break; 727459931ecSChris Mason } 728b3b4aa74SDavid Sterba btrfs_release_path(path); 729459931ecSChris Mason } 73065a246c5STsutomu Itoh ret = 0; 731459931ecSChris Mason out: 732459931ecSChris Mason btrfs_free_path(path); 73365a246c5STsutomu Itoh return ret; 734459931ecSChris Mason } 735459931ecSChris Mason 736065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 737d20f7043SChris Mason struct btrfs_root *root, 738e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 739f254e52cSChris Mason { 7400b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 741f254e52cSChris Mason struct btrfs_key file_key; 7426567e837SChris Mason struct btrfs_key found_key; 7435caf2a00SChris Mason struct btrfs_path *path; 744f254e52cSChris Mason struct btrfs_csum_item *item; 745065631f6SChris Mason struct btrfs_csum_item *item_end; 746ff79f819SChris Mason struct extent_buffer *leaf = NULL; 747f51a4a18SMiao Xie u64 next_offset; 748f51a4a18SMiao Xie u64 total_bytes = 0; 7496567e837SChris Mason u64 csum_offset; 750f51a4a18SMiao Xie u64 bytenr; 751f578d4bdSChris Mason u32 nritems; 752f578d4bdSChris Mason u32 ins_size; 753f51a4a18SMiao Xie int index = 0; 754f51a4a18SMiao Xie int found_next; 755f51a4a18SMiao Xie int ret; 7560b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 7576e92f5e6SChris Mason 7585caf2a00SChris Mason path = btrfs_alloc_path(); 759d8926bb3SMark Fasheh if (!path) 760d8926bb3SMark Fasheh return -ENOMEM; 761065631f6SChris Mason again: 762065631f6SChris Mason next_offset = (u64)-1; 763065631f6SChris Mason found_next = 0; 764f51a4a18SMiao Xie bytenr = sums->bytenr + total_bytes; 765d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 766f51a4a18SMiao Xie file_key.offset = bytenr; 767962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 768a429e513SChris Mason 769f51a4a18SMiao Xie item = btrfs_lookup_csum(trans, root, path, bytenr, 1); 770ff79f819SChris Mason if (!IS_ERR(item)) { 771639cb586SChris Mason ret = 0; 772f51a4a18SMiao Xie leaf = path->nodes[0]; 773f51a4a18SMiao Xie item_end = btrfs_item_ptr(leaf, path->slots[0], 774f51a4a18SMiao Xie struct btrfs_csum_item); 775f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((char *)item_end + 776f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 777a429e513SChris Mason goto found; 778ff79f819SChris Mason } 779a429e513SChris Mason ret = PTR_ERR(item); 7804a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7814a500fd1SYan, Zheng goto fail_unlock; 7824a500fd1SYan, Zheng 783a429e513SChris Mason if (ret == -EFBIG) { 784a429e513SChris Mason u32 item_size; 785a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7865f39d397SChris Mason leaf = path->nodes[0]; 7875f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 788607d432dSJosef Bacik if ((item_size / csum_size) >= 7890b246afaSJeff Mahoney MAX_CSUM_ITEMS(fs_info, csum_size)) { 790a429e513SChris Mason /* already at max size, make a new one */ 791a429e513SChris Mason goto insert; 792a429e513SChris Mason } 793a429e513SChris Mason } else { 794f578d4bdSChris Mason int slot = path->slots[0] + 1; 795a429e513SChris Mason /* we didn't find a csum item, insert one */ 796f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 79735045bf2SFilipe Manana if (!nritems || (path->slots[0] >= nritems - 1)) { 798f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 799b56baf5bSYan if (ret == 1) 800f578d4bdSChris Mason found_next = 1; 801b56baf5bSYan if (ret != 0) 802f578d4bdSChris Mason goto insert; 80327b9a812SFilipe Manana slot = path->slots[0]; 804f578d4bdSChris Mason } 805f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 806d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 807d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 808f578d4bdSChris Mason found_next = 1; 809f578d4bdSChris Mason goto insert; 810f578d4bdSChris Mason } 811f578d4bdSChris Mason next_offset = found_key.offset; 812f578d4bdSChris Mason found_next = 1; 813a429e513SChris Mason goto insert; 814a429e513SChris Mason } 815a429e513SChris Mason 816a429e513SChris Mason /* 817a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 818a429e513SChris Mason * enough yet to put our csum in. Grow it 819a429e513SChris Mason */ 820b3b4aa74SDavid Sterba btrfs_release_path(path); 8216567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 822607d432dSJosef Bacik csum_size, 1); 8236567e837SChris Mason if (ret < 0) 82453863232SChris Mason goto fail_unlock; 825459931ecSChris Mason 826459931ecSChris Mason if (ret > 0) { 827459931ecSChris Mason if (path->slots[0] == 0) 8286567e837SChris Mason goto insert; 8296567e837SChris Mason path->slots[0]--; 830459931ecSChris Mason } 831459931ecSChris Mason 8325f39d397SChris Mason leaf = path->nodes[0]; 8335f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 834d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 8350b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 836459931ecSChris Mason 837962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY || 838d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 8390b246afaSJeff Mahoney csum_offset >= MAX_CSUM_ITEMS(fs_info, csum_size)) { 8406567e837SChris Mason goto insert; 8416567e837SChris Mason } 842459931ecSChris Mason 8432f697dc6SLiu Bo if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / 844607d432dSJosef Bacik csum_size) { 8452f697dc6SLiu Bo int extend_nr; 8462f697dc6SLiu Bo u64 tmp; 8472f697dc6SLiu Bo u32 diff; 8482f697dc6SLiu Bo u32 free_space; 849459931ecSChris Mason 850e902baacSDavid Sterba if (btrfs_leaf_free_space(leaf) < 8512f697dc6SLiu Bo sizeof(struct btrfs_item) + csum_size * 2) 8522f697dc6SLiu Bo goto insert; 8532f697dc6SLiu Bo 854e902baacSDavid Sterba free_space = btrfs_leaf_free_space(leaf) - 8552f697dc6SLiu Bo sizeof(struct btrfs_item) - csum_size; 856f51a4a18SMiao Xie tmp = sums->len - total_bytes; 8570b246afaSJeff Mahoney tmp >>= fs_info->sb->s_blocksize_bits; 8582f697dc6SLiu Bo WARN_ON(tmp < 1); 8592f697dc6SLiu Bo 8602f697dc6SLiu Bo extend_nr = max_t(int, 1, (int)tmp); 8612f697dc6SLiu Bo diff = (csum_offset + extend_nr) * csum_size; 8620b246afaSJeff Mahoney diff = min(diff, 8630b246afaSJeff Mahoney MAX_CSUM_ITEMS(fs_info, csum_size) * csum_size); 864459931ecSChris Mason 8655f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 8662f697dc6SLiu Bo diff = min(free_space, diff); 8672f697dc6SLiu Bo diff /= csum_size; 8682f697dc6SLiu Bo diff *= csum_size; 869459931ecSChris Mason 870c71dd880SDavid Sterba btrfs_extend_item(path, diff); 871f51a4a18SMiao Xie ret = 0; 8726567e837SChris Mason goto csum; 8736567e837SChris Mason } 8746567e837SChris Mason 8756567e837SChris Mason insert: 876b3b4aa74SDavid Sterba btrfs_release_path(path); 8776567e837SChris Mason csum_offset = 0; 878f578d4bdSChris Mason if (found_next) { 8792f697dc6SLiu Bo u64 tmp; 880d20f7043SChris Mason 881f51a4a18SMiao Xie tmp = sums->len - total_bytes; 8820b246afaSJeff Mahoney tmp >>= fs_info->sb->s_blocksize_bits; 8832f697dc6SLiu Bo tmp = min(tmp, (next_offset - file_key.offset) >> 8840b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits); 8852f697dc6SLiu Bo 88650d0446eSSeraphime Kirkovski tmp = max_t(u64, 1, tmp); 88750d0446eSSeraphime Kirkovski tmp = min_t(u64, tmp, MAX_CSUM_ITEMS(fs_info, csum_size)); 888607d432dSJosef Bacik ins_size = csum_size * tmp; 889f578d4bdSChris Mason } else { 890607d432dSJosef Bacik ins_size = csum_size; 891f578d4bdSChris Mason } 892b9473439SChris Mason path->leave_spinning = 1; 8935caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 894f578d4bdSChris Mason ins_size); 895b9473439SChris Mason path->leave_spinning = 0; 89654aa1f4dSChris Mason if (ret < 0) 89753863232SChris Mason goto fail_unlock; 898fae7f21cSDulshani Gunawardhana if (WARN_ON(ret != 0)) 89953863232SChris Mason goto fail_unlock; 9005f39d397SChris Mason leaf = path->nodes[0]; 901f51a4a18SMiao Xie csum: 9025f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 903f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((unsigned char *)item + 904f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 905509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 906607d432dSJosef Bacik csum_offset * csum_size); 907b18c6685SChris Mason found: 908f51a4a18SMiao Xie ins_size = (u32)(sums->len - total_bytes) >> 9090b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 910f51a4a18SMiao Xie ins_size *= csum_size; 911f51a4a18SMiao Xie ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item, 912f51a4a18SMiao Xie ins_size); 913f51a4a18SMiao Xie write_extent_buffer(leaf, sums->sums + index, (unsigned long)item, 914f51a4a18SMiao Xie ins_size); 915aadfeb6eSChris Mason 9161e25a2e3SJohannes Thumshirn index += ins_size; 917f51a4a18SMiao Xie ins_size /= csum_size; 9180b246afaSJeff Mahoney total_bytes += ins_size * fs_info->sectorsize; 919a6591715SChris Mason 9205caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 921e6dcd2dcSChris Mason if (total_bytes < sums->len) { 922b3b4aa74SDavid Sterba btrfs_release_path(path); 923b9473439SChris Mason cond_resched(); 924065631f6SChris Mason goto again; 925065631f6SChris Mason } 92653863232SChris Mason out: 9275caf2a00SChris Mason btrfs_free_path(path); 928f254e52cSChris Mason return ret; 92953863232SChris Mason 93053863232SChris Mason fail_unlock: 93153863232SChris Mason goto out; 932f254e52cSChris Mason } 9337ffbb598SFilipe Manana 9349cdc5124SNikolay Borisov void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, 9357ffbb598SFilipe Manana const struct btrfs_path *path, 9367ffbb598SFilipe Manana struct btrfs_file_extent_item *fi, 9377ffbb598SFilipe Manana const bool new_inline, 9387ffbb598SFilipe Manana struct extent_map *em) 9397ffbb598SFilipe Manana { 9403ffbd68cSDavid Sterba struct btrfs_fs_info *fs_info = inode->root->fs_info; 9419cdc5124SNikolay Borisov struct btrfs_root *root = inode->root; 9427ffbb598SFilipe Manana struct extent_buffer *leaf = path->nodes[0]; 9437ffbb598SFilipe Manana const int slot = path->slots[0]; 9447ffbb598SFilipe Manana struct btrfs_key key; 9457ffbb598SFilipe Manana u64 extent_start, extent_end; 9467ffbb598SFilipe Manana u64 bytenr; 9477ffbb598SFilipe Manana u8 type = btrfs_file_extent_type(leaf, fi); 9487ffbb598SFilipe Manana int compress_type = btrfs_file_extent_compression(leaf, fi); 9497ffbb598SFilipe Manana 9507ffbb598SFilipe Manana btrfs_item_key_to_cpu(leaf, &key, slot); 9517ffbb598SFilipe Manana extent_start = key.offset; 9527ffbb598SFilipe Manana 9537ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 9547ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9557ffbb598SFilipe Manana extent_end = extent_start + 9567ffbb598SFilipe Manana btrfs_file_extent_num_bytes(leaf, fi); 9577ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9587ffbb598SFilipe Manana size_t size; 959e41ca589SQu Wenruo size = btrfs_file_extent_ram_bytes(leaf, fi); 960da17066cSJeff Mahoney extent_end = ALIGN(extent_start + size, 9610b246afaSJeff Mahoney fs_info->sectorsize); 9627ffbb598SFilipe Manana } 9637ffbb598SFilipe Manana 9647ffbb598SFilipe Manana em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); 9657ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 9667ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9677ffbb598SFilipe Manana em->start = extent_start; 9687ffbb598SFilipe Manana em->len = extent_end - extent_start; 9697ffbb598SFilipe Manana em->orig_start = extent_start - 9707ffbb598SFilipe Manana btrfs_file_extent_offset(leaf, fi); 9717ffbb598SFilipe Manana em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); 9727ffbb598SFilipe Manana bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); 9737ffbb598SFilipe Manana if (bytenr == 0) { 9747ffbb598SFilipe Manana em->block_start = EXTENT_MAP_HOLE; 9757ffbb598SFilipe Manana return; 9767ffbb598SFilipe Manana } 9777ffbb598SFilipe Manana if (compress_type != BTRFS_COMPRESS_NONE) { 9787ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 9797ffbb598SFilipe Manana em->compress_type = compress_type; 9807ffbb598SFilipe Manana em->block_start = bytenr; 9817ffbb598SFilipe Manana em->block_len = em->orig_block_len; 9827ffbb598SFilipe Manana } else { 9837ffbb598SFilipe Manana bytenr += btrfs_file_extent_offset(leaf, fi); 9847ffbb598SFilipe Manana em->block_start = bytenr; 9857ffbb598SFilipe Manana em->block_len = em->len; 9867ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_PREALLOC) 9877ffbb598SFilipe Manana set_bit(EXTENT_FLAG_PREALLOC, &em->flags); 9887ffbb598SFilipe Manana } 9897ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9907ffbb598SFilipe Manana em->block_start = EXTENT_MAP_INLINE; 9917ffbb598SFilipe Manana em->start = extent_start; 9927ffbb598SFilipe Manana em->len = extent_end - extent_start; 9937ffbb598SFilipe Manana /* 9947ffbb598SFilipe Manana * Initialize orig_start and block_len with the same values 9957ffbb598SFilipe Manana * as in inode.c:btrfs_get_extent(). 9967ffbb598SFilipe Manana */ 9977ffbb598SFilipe Manana em->orig_start = EXTENT_MAP_HOLE; 9987ffbb598SFilipe Manana em->block_len = (u64)-1; 9997ffbb598SFilipe Manana if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) { 10007ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 10017ffbb598SFilipe Manana em->compress_type = compress_type; 10027ffbb598SFilipe Manana } 10037ffbb598SFilipe Manana } else { 10040b246afaSJeff Mahoney btrfs_err(fs_info, 10059cdc5124SNikolay Borisov "unknown file extent item type %d, inode %llu, offset %llu, " 10069cdc5124SNikolay Borisov "root %llu", type, btrfs_ino(inode), extent_start, 10077ffbb598SFilipe Manana root->root_key.objectid); 10087ffbb598SFilipe Manana } 10097ffbb598SFilipe Manana } 1010