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" 28ebb8765bSAnand Jain #include "compression.h" 291e1d2701SChris Mason 3042049bf6SChris Mason #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ 3142049bf6SChris Mason sizeof(struct btrfs_item) * 2) / \ 3242049bf6SChris Mason size) - 1)) 3307d400a6SYan Zheng 34221b8318SZach Brown #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ 3509cbfeafSKirill A. Shutemov PAGE_SIZE)) 367ca4be45SChris Mason 37da17066cSJeff Mahoney #define MAX_ORDERED_SUM_BYTES(fs_info) ((PAGE_SIZE - \ 3807d400a6SYan Zheng sizeof(struct btrfs_ordered_sum)) / \ 39da17066cSJeff Mahoney sizeof(u32) * (fs_info)->sectorsize) 4007d400a6SYan Zheng 41b18c6685SChris Mason int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 42dee26a9fSChris Mason struct btrfs_root *root, 43b18c6685SChris Mason u64 objectid, u64 pos, 44f2eb0a24SSage Weil u64 disk_offset, u64 disk_num_bytes, 45c8b97818SChris Mason u64 num_bytes, u64 offset, u64 ram_bytes, 46c8b97818SChris Mason u8 compression, u8 encryption, u16 other_encoding) 479f5fae2fSChris Mason { 48dee26a9fSChris Mason int ret = 0; 49dee26a9fSChris Mason struct btrfs_file_extent_item *item; 50dee26a9fSChris Mason struct btrfs_key file_key; 515caf2a00SChris Mason struct btrfs_path *path; 525f39d397SChris Mason struct extent_buffer *leaf; 53dee26a9fSChris Mason 545caf2a00SChris Mason path = btrfs_alloc_path(); 55db5b493aSTsutomu Itoh if (!path) 56db5b493aSTsutomu Itoh return -ENOMEM; 57dee26a9fSChris Mason file_key.objectid = objectid; 58b18c6685SChris Mason file_key.offset = pos; 59962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_DATA_KEY; 60dee26a9fSChris Mason 61b9473439SChris Mason path->leave_spinning = 1; 625caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 63dee26a9fSChris Mason sizeof(*item)); 6454aa1f4dSChris Mason if (ret < 0) 6554aa1f4dSChris Mason goto out; 6679787eaaSJeff Mahoney BUG_ON(ret); /* Can't happen */ 675f39d397SChris Mason leaf = path->nodes[0]; 685f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], 69dee26a9fSChris Mason struct btrfs_file_extent_item); 70f2eb0a24SSage Weil btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); 71db94535dSChris Mason btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); 72f2eb0a24SSage Weil btrfs_set_file_extent_offset(leaf, item, offset); 73db94535dSChris Mason btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); 74c8b97818SChris Mason btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); 755f39d397SChris Mason btrfs_set_file_extent_generation(leaf, item, trans->transid); 765f39d397SChris Mason btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); 77c8b97818SChris Mason btrfs_set_file_extent_compression(leaf, item, compression); 78c8b97818SChris Mason btrfs_set_file_extent_encryption(leaf, item, encryption); 79c8b97818SChris Mason btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); 80c8b97818SChris Mason 815f39d397SChris Mason btrfs_mark_buffer_dirty(leaf); 8254aa1f4dSChris Mason out: 835caf2a00SChris Mason btrfs_free_path(path); 8454aa1f4dSChris Mason return ret; 859f5fae2fSChris Mason } 86dee26a9fSChris Mason 8748a3b636SEric Sandeen static struct btrfs_csum_item * 8848a3b636SEric Sandeen btrfs_lookup_csum(struct btrfs_trans_handle *trans, 89b18c6685SChris Mason struct btrfs_root *root, 906567e837SChris Mason struct btrfs_path *path, 91d20f7043SChris Mason u64 bytenr, int cow) 926567e837SChris Mason { 93*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 946567e837SChris Mason int ret; 956567e837SChris Mason struct btrfs_key file_key; 966567e837SChris Mason struct btrfs_key found_key; 976567e837SChris Mason struct btrfs_csum_item *item; 985f39d397SChris Mason struct extent_buffer *leaf; 996567e837SChris Mason u64 csum_offset = 0; 100*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 101a429e513SChris Mason int csums_in_item; 1026567e837SChris Mason 103d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 104d20f7043SChris Mason file_key.offset = bytenr; 105962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 106b18c6685SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); 1076567e837SChris Mason if (ret < 0) 1086567e837SChris Mason goto fail; 1095f39d397SChris Mason leaf = path->nodes[0]; 1106567e837SChris Mason if (ret > 0) { 1116567e837SChris Mason ret = 1; 11270b2befdSChris Mason if (path->slots[0] == 0) 1136567e837SChris Mason goto fail; 1146567e837SChris Mason path->slots[0]--; 1155f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 116962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY) 1176567e837SChris Mason goto fail; 118d20f7043SChris Mason 119d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 120*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 1215f39d397SChris Mason csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 122607d432dSJosef Bacik csums_in_item /= csum_size; 123a429e513SChris Mason 12482d130ffSMiao Xie if (csum_offset == csums_in_item) { 125a429e513SChris Mason ret = -EFBIG; 1266567e837SChris Mason goto fail; 12782d130ffSMiao Xie } else if (csum_offset > csums_in_item) { 12882d130ffSMiao Xie goto fail; 1296567e837SChris Mason } 1306567e837SChris Mason } 1316567e837SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 132509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 133607d432dSJosef Bacik csum_offset * csum_size); 1346567e837SChris Mason return item; 1356567e837SChris Mason fail: 1366567e837SChris Mason if (ret > 0) 137b18c6685SChris Mason ret = -ENOENT; 1386567e837SChris Mason return ERR_PTR(ret); 1396567e837SChris Mason } 1406567e837SChris Mason 141dee26a9fSChris Mason int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, 142dee26a9fSChris Mason struct btrfs_root *root, 143dee26a9fSChris Mason struct btrfs_path *path, u64 objectid, 1449773a788SChris Mason u64 offset, int mod) 145dee26a9fSChris Mason { 146dee26a9fSChris Mason int ret; 147dee26a9fSChris Mason struct btrfs_key file_key; 148dee26a9fSChris Mason int ins_len = mod < 0 ? -1 : 0; 149dee26a9fSChris Mason int cow = mod != 0; 150dee26a9fSChris Mason 151dee26a9fSChris Mason file_key.objectid = objectid; 15270b2befdSChris Mason file_key.offset = offset; 153962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_DATA_KEY; 154dee26a9fSChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); 155dee26a9fSChris Mason return ret; 156dee26a9fSChris Mason } 157f254e52cSChris Mason 158facc8a22SMiao Xie static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) 159facc8a22SMiao Xie { 160facc8a22SMiao Xie kfree(bio->csum_allocated); 161facc8a22SMiao Xie } 162facc8a22SMiao Xie 1634b46fce2SJosef Bacik static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 1644b46fce2SJosef Bacik struct inode *inode, struct bio *bio, 1654b46fce2SJosef Bacik u64 logical_offset, u32 *dst, int dio) 16661b49440SChris Mason { 167*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 1684989d277SChristoph Hellwig struct bio_vec *bvec; 169facc8a22SMiao Xie struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); 170facc8a22SMiao Xie struct btrfs_csum_item *item = NULL; 171facc8a22SMiao Xie struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 172facc8a22SMiao Xie struct btrfs_path *path; 173facc8a22SMiao Xie u8 *csum; 1744b46fce2SJosef Bacik u64 offset = 0; 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; 1814989d277SChristoph Hellwig int count = 0, i; 182*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 18361b49440SChris Mason 18461b49440SChris Mason path = btrfs_alloc_path(); 185c2db1073STsutomu Itoh if (!path) 186c2db1073STsutomu Itoh return -ENOMEM; 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) { 19131e818feSDavid Sterba btrfs_bio->csum_allocated = kmalloc_array(nblocks, 19231e818feSDavid Sterba csum_size, GFP_NOFS); 193facc8a22SMiao Xie if (!btrfs_bio->csum_allocated) { 194facc8a22SMiao Xie btrfs_free_path(path); 195facc8a22SMiao Xie return -ENOMEM; 196facc8a22SMiao Xie } 197facc8a22SMiao Xie btrfs_bio->csum = btrfs_bio->csum_allocated; 198facc8a22SMiao Xie btrfs_bio->end_io = btrfs_io_bio_endio_readpage; 199facc8a22SMiao Xie } else { 200facc8a22SMiao Xie btrfs_bio->csum = btrfs_bio->csum_inline; 201facc8a22SMiao Xie } 202facc8a22SMiao Xie csum = btrfs_bio->csum; 203facc8a22SMiao Xie } else { 204facc8a22SMiao Xie csum = (u8 *)dst; 205facc8a22SMiao Xie } 206facc8a22SMiao Xie 20709cbfeafSKirill A. Shutemov if (bio->bi_iter.bi_size > PAGE_SIZE * 8) 208e4058b54SDavid Sterba path->reada = READA_FORWARD; 20961b49440SChris Mason 21061b49440SChris Mason WARN_ON(bio->bi_vcnt <= 0); 21161b49440SChris Mason 2122cf8572dSChris Mason /* 2132cf8572dSChris Mason * the free space stuff is only read when it hasn't been 2142cf8572dSChris Mason * updated in the current transaction. So, we can safely 2152cf8572dSChris Mason * read from the commit root and sidestep a nasty deadlock 2162cf8572dSChris Mason * between reading the free space cache and updating the csum tree. 2172cf8572dSChris Mason */ 21883eea1f1SLiu Bo if (btrfs_is_free_space_inode(inode)) { 2192cf8572dSChris Mason path->search_commit_root = 1; 220ddf23b3fSJosef Bacik path->skip_locking = 1; 221ddf23b3fSJosef Bacik } 2222cf8572dSChris Mason 2234f024f37SKent Overstreet disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; 2244b46fce2SJosef Bacik if (dio) 2254b46fce2SJosef Bacik offset = logical_offset; 226c40a3d38SChandan Rajendra 2274989d277SChristoph Hellwig bio_for_each_segment_all(bvec, bio, i) { 228c40a3d38SChandan Rajendra page_bytes_left = bvec->bv_len; 2294989d277SChristoph Hellwig if (count) 2304989d277SChristoph Hellwig goto next; 2314989d277SChristoph Hellwig 2324b46fce2SJosef Bacik if (!dio) 23361b49440SChris Mason offset = page_offset(bvec->bv_page) + bvec->bv_offset; 234facc8a22SMiao Xie count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, 235facc8a22SMiao Xie (u32 *)csum, nblocks); 236e4100d98SMiao Xie if (count) 23761b49440SChris Mason goto found; 23861b49440SChris Mason 239d20f7043SChris Mason if (!item || disk_bytenr < item_start_offset || 240d20f7043SChris Mason disk_bytenr >= item_last_offset) { 24161b49440SChris Mason struct btrfs_key found_key; 24261b49440SChris Mason u32 item_size; 24361b49440SChris Mason 24461b49440SChris Mason if (item) 245b3b4aa74SDavid Sterba btrfs_release_path(path); 246*0b246afaSJeff Mahoney item = btrfs_lookup_csum(NULL, fs_info->csum_root, 247d20f7043SChris Mason path, disk_bytenr, 0); 24861b49440SChris Mason if (IS_ERR(item)) { 249e4100d98SMiao Xie count = 1; 250facc8a22SMiao Xie memset(csum, 0, csum_size); 25117d217feSYan Zheng if (BTRFS_I(inode)->root->root_key.objectid == 25217d217feSYan Zheng BTRFS_DATA_RELOC_TREE_OBJECTID) { 25317d217feSYan Zheng set_extent_bits(io_tree, offset, 254*0b246afaSJeff Mahoney offset + fs_info->sectorsize - 1, 255ceeb0ae7SDavid Sterba EXTENT_NODATASUM); 25617d217feSYan Zheng } else { 257*0b246afaSJeff Mahoney btrfs_info_rl(fs_info, 258efe120a0SFrank Holton "no csum found for inode %llu start %llu", 259c1c9ff7cSGeert Uytterhoeven btrfs_ino(inode), offset); 26017d217feSYan Zheng } 2616dab8157SChris Mason item = NULL; 262b3b4aa74SDavid Sterba btrfs_release_path(path); 26361b49440SChris Mason goto found; 26461b49440SChris Mason } 26561b49440SChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, 26661b49440SChris Mason path->slots[0]); 26761b49440SChris Mason 26861b49440SChris Mason item_start_offset = found_key.offset; 26961b49440SChris Mason item_size = btrfs_item_size_nr(path->nodes[0], 27061b49440SChris Mason path->slots[0]); 27161b49440SChris Mason item_last_offset = item_start_offset + 272607d432dSJosef Bacik (item_size / csum_size) * 273*0b246afaSJeff Mahoney fs_info->sectorsize; 27461b49440SChris Mason item = btrfs_item_ptr(path->nodes[0], path->slots[0], 27561b49440SChris Mason struct btrfs_csum_item); 27661b49440SChris Mason } 27761b49440SChris Mason /* 27861b49440SChris Mason * this byte range must be able to fit inside 27961b49440SChris Mason * a single leaf so it will also fit inside a u32 28061b49440SChris Mason */ 281d20f7043SChris Mason diff = disk_bytenr - item_start_offset; 282*0b246afaSJeff Mahoney diff = diff / fs_info->sectorsize; 283607d432dSJosef Bacik diff = diff * csum_size; 284facc8a22SMiao Xie count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> 285e4100d98SMiao Xie inode->i_sb->s_blocksize_bits); 286facc8a22SMiao Xie read_extent_buffer(path->nodes[0], csum, 2873de9d6b6SChris Mason ((unsigned long)item) + diff, 288e4100d98SMiao Xie csum_size * count); 28961b49440SChris Mason found: 290facc8a22SMiao Xie csum += count * csum_size; 291facc8a22SMiao Xie nblocks -= count; 2924989d277SChristoph Hellwig next: 293e4100d98SMiao Xie while (count--) { 294*0b246afaSJeff Mahoney disk_bytenr += fs_info->sectorsize; 295*0b246afaSJeff Mahoney offset += fs_info->sectorsize; 296*0b246afaSJeff Mahoney page_bytes_left -= fs_info->sectorsize; 2974989d277SChristoph Hellwig if (!page_bytes_left) 2984989d277SChristoph Hellwig break; /* move to next bio */ 2994989d277SChristoph Hellwig } 3004989d277SChristoph Hellwig } 3014989d277SChristoph Hellwig 302389f239cSChris Mason WARN_ON_ONCE(count); 30361b49440SChris Mason btrfs_free_path(path); 30461b49440SChris Mason return 0; 30561b49440SChris Mason } 30661b49440SChris Mason 3074b46fce2SJosef Bacik int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 3084b46fce2SJosef Bacik struct bio *bio, u32 *dst) 3094b46fce2SJosef Bacik { 3104b46fce2SJosef Bacik return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); 3114b46fce2SJosef Bacik } 3124b46fce2SJosef Bacik 3134b46fce2SJosef Bacik int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, 31423ea8e5aSMiao Xie struct bio *bio, u64 offset) 3154b46fce2SJosef Bacik { 31623ea8e5aSMiao Xie return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); 3174b46fce2SJosef Bacik } 3184b46fce2SJosef Bacik 31917d217feSYan Zheng int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 320a2de733cSArne Jansen struct list_head *list, int search_commit) 32117d217feSYan Zheng { 322*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 32317d217feSYan Zheng struct btrfs_key key; 32417d217feSYan Zheng struct btrfs_path *path; 32517d217feSYan Zheng struct extent_buffer *leaf; 32617d217feSYan Zheng struct btrfs_ordered_sum *sums; 32717d217feSYan Zheng struct btrfs_csum_item *item; 3280678b618SMark Fasheh LIST_HEAD(tmplist); 32917d217feSYan Zheng unsigned long offset; 33017d217feSYan Zheng int ret; 33117d217feSYan Zheng size_t size; 33217d217feSYan Zheng u64 csum_end; 333*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 33417d217feSYan Zheng 335*0b246afaSJeff Mahoney ASSERT(IS_ALIGNED(start, fs_info->sectorsize) && 336*0b246afaSJeff Mahoney IS_ALIGNED(end + 1, fs_info->sectorsize)); 3374277a9c3SJosef Bacik 33817d217feSYan Zheng path = btrfs_alloc_path(); 339d8926bb3SMark Fasheh if (!path) 340d8926bb3SMark Fasheh return -ENOMEM; 34117d217feSYan Zheng 342a2de733cSArne Jansen if (search_commit) { 343a2de733cSArne Jansen path->skip_locking = 1; 344e4058b54SDavid Sterba path->reada = READA_FORWARD; 345a2de733cSArne Jansen path->search_commit_root = 1; 346a2de733cSArne Jansen } 347a2de733cSArne Jansen 34817d217feSYan Zheng key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 34917d217feSYan Zheng key.offset = start; 35017d217feSYan Zheng key.type = BTRFS_EXTENT_CSUM_KEY; 35117d217feSYan Zheng 35207d400a6SYan Zheng ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); 35317d217feSYan Zheng if (ret < 0) 35417d217feSYan Zheng goto fail; 35517d217feSYan Zheng if (ret > 0 && path->slots[0] > 0) { 35617d217feSYan Zheng leaf = path->nodes[0]; 35717d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); 35817d217feSYan Zheng if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && 35917d217feSYan Zheng key.type == BTRFS_EXTENT_CSUM_KEY) { 36017d217feSYan Zheng offset = (start - key.offset) >> 361*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 36217d217feSYan Zheng if (offset * csum_size < 36317d217feSYan Zheng btrfs_item_size_nr(leaf, path->slots[0] - 1)) 36417d217feSYan Zheng path->slots[0]--; 36517d217feSYan Zheng } 36617d217feSYan Zheng } 36717d217feSYan Zheng 36817d217feSYan Zheng while (start <= end) { 36917d217feSYan Zheng leaf = path->nodes[0]; 37017d217feSYan Zheng if (path->slots[0] >= btrfs_header_nritems(leaf)) { 37107d400a6SYan Zheng ret = btrfs_next_leaf(root, path); 37217d217feSYan Zheng if (ret < 0) 37317d217feSYan Zheng goto fail; 37417d217feSYan Zheng if (ret > 0) 37517d217feSYan Zheng break; 37617d217feSYan Zheng leaf = path->nodes[0]; 37717d217feSYan Zheng } 37817d217feSYan Zheng 37917d217feSYan Zheng btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 38017d217feSYan Zheng if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 381628c8282SZhi Yong Wu key.type != BTRFS_EXTENT_CSUM_KEY || 382628c8282SZhi Yong Wu key.offset > end) 38317d217feSYan Zheng break; 38417d217feSYan Zheng 38517d217feSYan Zheng if (key.offset > start) 38617d217feSYan Zheng start = key.offset; 38717d217feSYan Zheng 38817d217feSYan Zheng size = btrfs_item_size_nr(leaf, path->slots[0]); 389*0b246afaSJeff Mahoney csum_end = key.offset + (size / csum_size) * fs_info->sectorsize; 39087b29b20SYan Zheng if (csum_end <= start) { 39187b29b20SYan Zheng path->slots[0]++; 39287b29b20SYan Zheng continue; 39387b29b20SYan Zheng } 39417d217feSYan Zheng 39507d400a6SYan Zheng csum_end = min(csum_end, end + 1); 39607d400a6SYan Zheng item = btrfs_item_ptr(path->nodes[0], path->slots[0], 39707d400a6SYan Zheng struct btrfs_csum_item); 39807d400a6SYan Zheng while (start < csum_end) { 39907d400a6SYan Zheng size = min_t(size_t, csum_end - start, 400*0b246afaSJeff Mahoney MAX_ORDERED_SUM_BYTES(fs_info)); 401*0b246afaSJeff Mahoney sums = kzalloc(btrfs_ordered_sum_size(fs_info, size), 40207d400a6SYan Zheng GFP_NOFS); 4030678b618SMark Fasheh if (!sums) { 4040678b618SMark Fasheh ret = -ENOMEM; 4050678b618SMark Fasheh goto fail; 4060678b618SMark Fasheh } 40717d217feSYan Zheng 40817d217feSYan Zheng sums->bytenr = start; 409f51a4a18SMiao Xie sums->len = (int)size; 41017d217feSYan Zheng 41117d217feSYan Zheng offset = (start - key.offset) >> 412*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 41317d217feSYan Zheng offset *= csum_size; 414*0b246afaSJeff Mahoney size >>= fs_info->sb->s_blocksize_bits; 41517d217feSYan Zheng 41607d400a6SYan Zheng read_extent_buffer(path->nodes[0], 417f51a4a18SMiao Xie sums->sums, 418f51a4a18SMiao Xie ((unsigned long)item) + offset, 419f51a4a18SMiao Xie csum_size * size); 42017d217feSYan Zheng 421*0b246afaSJeff Mahoney start += fs_info->sectorsize * size; 4220678b618SMark Fasheh list_add_tail(&sums->list, &tmplist); 42307d400a6SYan Zheng } 42417d217feSYan Zheng path->slots[0]++; 42517d217feSYan Zheng } 42617d217feSYan Zheng ret = 0; 42717d217feSYan Zheng fail: 4280678b618SMark Fasheh while (ret < 0 && !list_empty(&tmplist)) { 4296e5aafb2SChris Mason sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); 4300678b618SMark Fasheh list_del(&sums->list); 4310678b618SMark Fasheh kfree(sums); 4320678b618SMark Fasheh } 4330678b618SMark Fasheh list_splice_tail(&tmplist, list); 4340678b618SMark Fasheh 43517d217feSYan Zheng btrfs_free_path(path); 43617d217feSYan Zheng return ret; 43717d217feSYan Zheng } 43817d217feSYan Zheng 4393edf7d33SChris Mason int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, 440d20f7043SChris Mason struct bio *bio, u64 file_start, int contig) 441e015640fSChris Mason { 442*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 443e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums; 4446cd7ce49SChristoph Hellwig struct btrfs_ordered_extent *ordered = NULL; 445e015640fSChris Mason char *data; 4466cd7ce49SChristoph Hellwig struct bio_vec *bvec; 447f51a4a18SMiao Xie int index; 448c40a3d38SChandan Rajendra int nr_sectors; 4496cd7ce49SChristoph Hellwig int i, j; 4503edf7d33SChris Mason unsigned long total_bytes = 0; 4513edf7d33SChris Mason unsigned long this_sum_bytes = 0; 4523edf7d33SChris Mason u64 offset; 453e015640fSChris Mason 454e6dcd2dcSChris Mason WARN_ON(bio->bi_vcnt <= 0); 455*0b246afaSJeff Mahoney sums = kzalloc(btrfs_ordered_sum_size(fs_info, bio->bi_iter.bi_size), 4564f024f37SKent Overstreet GFP_NOFS); 457e015640fSChris Mason if (!sums) 458e015640fSChris Mason return -ENOMEM; 4593edf7d33SChris Mason 4604f024f37SKent Overstreet sums->len = bio->bi_iter.bi_size; 461e6dcd2dcSChris Mason INIT_LIST_HEAD(&sums->list); 462d20f7043SChris Mason 463d20f7043SChris Mason if (contig) 464d20f7043SChris Mason offset = file_start; 465d20f7043SChris Mason else 4666cd7ce49SChristoph Hellwig offset = 0; /* shut up gcc */ 467d20f7043SChris Mason 4684f024f37SKent Overstreet sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; 469f51a4a18SMiao Xie index = 0; 470e015640fSChris Mason 4716cd7ce49SChristoph Hellwig bio_for_each_segment_all(bvec, bio, j) { 472d20f7043SChris Mason if (!contig) 4733edf7d33SChris Mason 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 480c40a3d38SChandan Rajendra data = kmap_atomic(bvec->bv_page); 481c40a3d38SChandan Rajendra 482*0b246afaSJeff Mahoney nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, 483*0b246afaSJeff Mahoney bvec->bv_len + fs_info->sectorsize 484c40a3d38SChandan Rajendra - 1); 485c40a3d38SChandan Rajendra 486c40a3d38SChandan Rajendra for (i = 0; i < nr_sectors; i++) { 487e58dd74bSJosef Bacik if (offset >= ordered->file_offset + ordered->len || 488e58dd74bSJosef Bacik offset < ordered->file_offset) { 4893edf7d33SChris Mason unsigned long bytes_left; 490c40a3d38SChandan Rajendra 491c40a3d38SChandan Rajendra kunmap_atomic(data); 4923edf7d33SChris Mason sums->len = this_sum_bytes; 4933edf7d33SChris Mason this_sum_bytes = 0; 4943edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 4953edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 4963edf7d33SChris Mason 4974f024f37SKent Overstreet bytes_left = bio->bi_iter.bi_size - total_bytes; 4983edf7d33SChris Mason 499*0b246afaSJeff Mahoney sums = kzalloc(btrfs_ordered_sum_size(fs_info, bytes_left), 5003edf7d33SChris Mason GFP_NOFS); 50179787eaaSJeff Mahoney BUG_ON(!sums); /* -ENOMEM */ 5023edf7d33SChris Mason sums->len = bytes_left; 503c40a3d38SChandan Rajendra ordered = btrfs_lookup_ordered_extent(inode, 504c40a3d38SChandan Rajendra offset); 505c40a3d38SChandan Rajendra ASSERT(ordered); /* Logic error */ 506c40a3d38SChandan Rajendra sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) 507c40a3d38SChandan Rajendra + total_bytes; 508f51a4a18SMiao Xie index = 0; 5093edf7d33SChris Mason 5107ac687d9SCong Wang data = kmap_atomic(bvec->bv_page); 511c40a3d38SChandan Rajendra } 512c40a3d38SChandan Rajendra 513f51a4a18SMiao Xie sums->sums[index] = ~(u32)0; 514c40a3d38SChandan Rajendra sums->sums[index] 515c40a3d38SChandan Rajendra = btrfs_csum_data(data + bvec->bv_offset 516*0b246afaSJeff Mahoney + (i * fs_info->sectorsize), 517f51a4a18SMiao Xie sums->sums[index], 518*0b246afaSJeff Mahoney fs_info->sectorsize); 519f51a4a18SMiao Xie btrfs_csum_final(sums->sums[index], 520f51a4a18SMiao Xie (char *)(sums->sums + index)); 521c40a3d38SChandan Rajendra index++; 522*0b246afaSJeff Mahoney offset += fs_info->sectorsize; 523*0b246afaSJeff Mahoney this_sum_bytes += fs_info->sectorsize; 524*0b246afaSJeff Mahoney total_bytes += fs_info->sectorsize; 525c40a3d38SChandan Rajendra } 526c40a3d38SChandan Rajendra 527c40a3d38SChandan Rajendra kunmap_atomic(data); 528e015640fSChris Mason } 529ed98b56aSChris Mason this_sum_bytes = 0; 5303edf7d33SChris Mason btrfs_add_ordered_sum(inode, ordered, sums); 5313edf7d33SChris Mason btrfs_put_ordered_extent(ordered); 532e015640fSChris Mason return 0; 533e015640fSChris Mason } 534e015640fSChris Mason 535459931ecSChris Mason /* 536459931ecSChris Mason * helper function for csum removal, this expects the 537459931ecSChris Mason * key to describe the csum pointed to by the path, and it expects 538459931ecSChris Mason * the csum to overlap the range [bytenr, len] 539459931ecSChris Mason * 540459931ecSChris Mason * The csum should not be entirely contained in the range and the 541459931ecSChris Mason * range should not be entirely contained in the csum. 542459931ecSChris Mason * 543459931ecSChris Mason * This calls btrfs_truncate_item with the correct args based on the 544459931ecSChris Mason * overlap, and fixes up the key as required. 545459931ecSChris Mason */ 546afe5fea7STsutomu Itoh static noinline void truncate_one_csum(struct btrfs_root *root, 547459931ecSChris Mason struct btrfs_path *path, 548459931ecSChris Mason struct btrfs_key *key, 549459931ecSChris Mason u64 bytenr, u64 len) 550459931ecSChris Mason { 551*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 552459931ecSChris Mason struct extent_buffer *leaf; 553*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 554459931ecSChris Mason u64 csum_end; 555459931ecSChris Mason u64 end_byte = bytenr + len; 556*0b246afaSJeff Mahoney u32 blocksize_bits = fs_info->sb->s_blocksize_bits; 557459931ecSChris Mason 558459931ecSChris Mason leaf = path->nodes[0]; 559459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 560*0b246afaSJeff Mahoney csum_end <<= fs_info->sb->s_blocksize_bits; 561459931ecSChris Mason csum_end += key->offset; 562459931ecSChris Mason 563459931ecSChris Mason if (key->offset < bytenr && csum_end <= end_byte) { 564459931ecSChris Mason /* 565459931ecSChris Mason * [ bytenr - len ] 566459931ecSChris Mason * [ ] 567459931ecSChris Mason * [csum ] 568459931ecSChris Mason * A simple truncate off the end of the item 569459931ecSChris Mason */ 570459931ecSChris Mason u32 new_size = (bytenr - key->offset) >> blocksize_bits; 571459931ecSChris Mason new_size *= csum_size; 572afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 1); 573459931ecSChris Mason } else if (key->offset >= bytenr && csum_end > end_byte && 574459931ecSChris Mason end_byte > key->offset) { 575459931ecSChris Mason /* 576459931ecSChris Mason * [ bytenr - len ] 577459931ecSChris Mason * [ ] 578459931ecSChris Mason * [csum ] 579459931ecSChris Mason * we need to truncate from the beginning of the csum 580459931ecSChris Mason */ 581459931ecSChris Mason u32 new_size = (csum_end - end_byte) >> blocksize_bits; 582459931ecSChris Mason new_size *= csum_size; 583459931ecSChris Mason 584afe5fea7STsutomu Itoh btrfs_truncate_item(root, path, new_size, 0); 585459931ecSChris Mason 586459931ecSChris Mason key->offset = end_byte; 587*0b246afaSJeff Mahoney btrfs_set_item_key_safe(fs_info, path, key); 588459931ecSChris Mason } else { 589459931ecSChris Mason BUG(); 590459931ecSChris Mason } 591459931ecSChris Mason } 592459931ecSChris Mason 593459931ecSChris Mason /* 594459931ecSChris Mason * deletes the csum items from the csum tree for a given 595459931ecSChris Mason * range of bytes. 596459931ecSChris Mason */ 597459931ecSChris Mason int btrfs_del_csums(struct btrfs_trans_handle *trans, 5985b4aacefSJeff Mahoney struct btrfs_fs_info *fs_info, u64 bytenr, u64 len) 599459931ecSChris Mason { 6005b4aacefSJeff Mahoney struct btrfs_root *root = fs_info->csum_root; 601459931ecSChris Mason struct btrfs_path *path; 602459931ecSChris Mason struct btrfs_key key; 603459931ecSChris Mason u64 end_byte = bytenr + len; 604459931ecSChris Mason u64 csum_end; 605459931ecSChris Mason struct extent_buffer *leaf; 606459931ecSChris Mason int ret; 607*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 608*0b246afaSJeff Mahoney int blocksize_bits = fs_info->sb->s_blocksize_bits; 609459931ecSChris Mason 610459931ecSChris Mason path = btrfs_alloc_path(); 6112a29edc6Sliubo if (!path) 6122a29edc6Sliubo return -ENOMEM; 613459931ecSChris Mason 614459931ecSChris Mason while (1) { 615459931ecSChris Mason key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 616459931ecSChris Mason key.offset = end_byte - 1; 617459931ecSChris Mason key.type = BTRFS_EXTENT_CSUM_KEY; 618459931ecSChris Mason 619b9473439SChris Mason path->leave_spinning = 1; 620459931ecSChris Mason ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 621459931ecSChris Mason if (ret > 0) { 622459931ecSChris Mason if (path->slots[0] == 0) 62365a246c5STsutomu Itoh break; 624459931ecSChris Mason path->slots[0]--; 625ad0397a7SJosef Bacik } else if (ret < 0) { 62665a246c5STsutomu Itoh break; 627459931ecSChris Mason } 628ad0397a7SJosef Bacik 629459931ecSChris Mason leaf = path->nodes[0]; 630459931ecSChris Mason btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); 631459931ecSChris Mason 632459931ecSChris Mason if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 633459931ecSChris Mason key.type != BTRFS_EXTENT_CSUM_KEY) { 634459931ecSChris Mason break; 635459931ecSChris Mason } 636459931ecSChris Mason 637459931ecSChris Mason if (key.offset >= end_byte) 638459931ecSChris Mason break; 639459931ecSChris Mason 640459931ecSChris Mason csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; 641459931ecSChris Mason csum_end <<= blocksize_bits; 642459931ecSChris Mason csum_end += key.offset; 643459931ecSChris Mason 644459931ecSChris Mason /* this csum ends before we start, we're done */ 645459931ecSChris Mason if (csum_end <= bytenr) 646459931ecSChris Mason break; 647459931ecSChris Mason 648459931ecSChris Mason /* delete the entire item, it is inside our range */ 649459931ecSChris Mason if (key.offset >= bytenr && csum_end <= end_byte) { 650459931ecSChris Mason ret = btrfs_del_item(trans, root, path); 65165a246c5STsutomu Itoh if (ret) 65265a246c5STsutomu Itoh goto out; 653dcbdd4dcSChris Mason if (key.offset == bytenr) 654dcbdd4dcSChris Mason break; 655459931ecSChris Mason } else if (key.offset < bytenr && csum_end > end_byte) { 656459931ecSChris Mason unsigned long offset; 657459931ecSChris Mason unsigned long shift_len; 658459931ecSChris Mason unsigned long item_offset; 659459931ecSChris Mason /* 660459931ecSChris Mason * [ bytenr - len ] 661459931ecSChris Mason * [csum ] 662459931ecSChris Mason * 663459931ecSChris Mason * Our bytes are in the middle of the csum, 664459931ecSChris Mason * we need to split this item and insert a new one. 665459931ecSChris Mason * 666459931ecSChris Mason * But we can't drop the path because the 667459931ecSChris Mason * csum could change, get removed, extended etc. 668459931ecSChris Mason * 669459931ecSChris Mason * The trick here is the max size of a csum item leaves 670459931ecSChris Mason * enough room in the tree block for a single 671459931ecSChris Mason * item header. So, we split the item in place, 672459931ecSChris Mason * adding a new header pointing to the existing 673459931ecSChris Mason * bytes. Then we loop around again and we have 674459931ecSChris Mason * a nicely formed csum item that we can neatly 675459931ecSChris Mason * truncate. 676459931ecSChris Mason */ 677459931ecSChris Mason offset = (bytenr - key.offset) >> blocksize_bits; 678459931ecSChris Mason offset *= csum_size; 679459931ecSChris Mason 680459931ecSChris Mason shift_len = (len >> blocksize_bits) * csum_size; 681459931ecSChris Mason 682459931ecSChris Mason item_offset = btrfs_item_ptr_offset(leaf, 683459931ecSChris Mason path->slots[0]); 684459931ecSChris Mason 685b159fa28SDavid Sterba memzero_extent_buffer(leaf, item_offset + offset, 686459931ecSChris Mason shift_len); 687459931ecSChris Mason key.offset = bytenr; 688459931ecSChris Mason 689459931ecSChris Mason /* 690459931ecSChris Mason * btrfs_split_item returns -EAGAIN when the 691459931ecSChris Mason * item changed size or key 692459931ecSChris Mason */ 693459931ecSChris Mason ret = btrfs_split_item(trans, root, path, &key, offset); 69479787eaaSJeff Mahoney if (ret && ret != -EAGAIN) { 69566642832SJeff Mahoney btrfs_abort_transaction(trans, ret); 69679787eaaSJeff Mahoney goto out; 69779787eaaSJeff Mahoney } 698459931ecSChris Mason 699459931ecSChris Mason key.offset = end_byte - 1; 700459931ecSChris Mason } else { 701afe5fea7STsutomu Itoh truncate_one_csum(root, path, &key, bytenr, len); 702dcbdd4dcSChris Mason if (key.offset < bytenr) 703dcbdd4dcSChris Mason break; 704459931ecSChris Mason } 705b3b4aa74SDavid Sterba btrfs_release_path(path); 706459931ecSChris Mason } 70765a246c5STsutomu Itoh ret = 0; 708459931ecSChris Mason out: 709459931ecSChris Mason btrfs_free_path(path); 71065a246c5STsutomu Itoh return ret; 711459931ecSChris Mason } 712459931ecSChris Mason 713065631f6SChris Mason int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 714d20f7043SChris Mason struct btrfs_root *root, 715e6dcd2dcSChris Mason struct btrfs_ordered_sum *sums) 716f254e52cSChris Mason { 717*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = root->fs_info; 718f254e52cSChris Mason struct btrfs_key file_key; 7196567e837SChris Mason struct btrfs_key found_key; 7205caf2a00SChris Mason struct btrfs_path *path; 721f254e52cSChris Mason struct btrfs_csum_item *item; 722065631f6SChris Mason struct btrfs_csum_item *item_end; 723ff79f819SChris Mason struct extent_buffer *leaf = NULL; 724f51a4a18SMiao Xie u64 next_offset; 725f51a4a18SMiao Xie u64 total_bytes = 0; 7266567e837SChris Mason u64 csum_offset; 727f51a4a18SMiao Xie u64 bytenr; 728f578d4bdSChris Mason u32 nritems; 729f578d4bdSChris Mason u32 ins_size; 730f51a4a18SMiao Xie int index = 0; 731f51a4a18SMiao Xie int found_next; 732f51a4a18SMiao Xie int ret; 733*0b246afaSJeff Mahoney u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); 7346e92f5e6SChris Mason 7355caf2a00SChris Mason path = btrfs_alloc_path(); 736d8926bb3SMark Fasheh if (!path) 737d8926bb3SMark Fasheh return -ENOMEM; 738065631f6SChris Mason again: 739065631f6SChris Mason next_offset = (u64)-1; 740065631f6SChris Mason found_next = 0; 741f51a4a18SMiao Xie bytenr = sums->bytenr + total_bytes; 742d20f7043SChris Mason file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; 743f51a4a18SMiao Xie file_key.offset = bytenr; 744962a298fSDavid Sterba file_key.type = BTRFS_EXTENT_CSUM_KEY; 745a429e513SChris Mason 746f51a4a18SMiao Xie item = btrfs_lookup_csum(trans, root, path, bytenr, 1); 747ff79f819SChris Mason if (!IS_ERR(item)) { 748639cb586SChris Mason ret = 0; 749f51a4a18SMiao Xie leaf = path->nodes[0]; 750f51a4a18SMiao Xie item_end = btrfs_item_ptr(leaf, path->slots[0], 751f51a4a18SMiao Xie struct btrfs_csum_item); 752f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((char *)item_end + 753f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 754a429e513SChris Mason goto found; 755ff79f819SChris Mason } 756a429e513SChris Mason ret = PTR_ERR(item); 7574a500fd1SYan, Zheng if (ret != -EFBIG && ret != -ENOENT) 7584a500fd1SYan, Zheng goto fail_unlock; 7594a500fd1SYan, Zheng 760a429e513SChris Mason if (ret == -EFBIG) { 761a429e513SChris Mason u32 item_size; 762a429e513SChris Mason /* we found one, but it isn't big enough yet */ 7635f39d397SChris Mason leaf = path->nodes[0]; 7645f39d397SChris Mason item_size = btrfs_item_size_nr(leaf, path->slots[0]); 765607d432dSJosef Bacik if ((item_size / csum_size) >= 766*0b246afaSJeff Mahoney MAX_CSUM_ITEMS(fs_info, csum_size)) { 767a429e513SChris Mason /* already at max size, make a new one */ 768a429e513SChris Mason goto insert; 769a429e513SChris Mason } 770a429e513SChris Mason } else { 771f578d4bdSChris Mason int slot = path->slots[0] + 1; 772a429e513SChris Mason /* we didn't find a csum item, insert one */ 773f578d4bdSChris Mason nritems = btrfs_header_nritems(path->nodes[0]); 77435045bf2SFilipe Manana if (!nritems || (path->slots[0] >= nritems - 1)) { 775f578d4bdSChris Mason ret = btrfs_next_leaf(root, path); 776b56baf5bSYan if (ret == 1) 777f578d4bdSChris Mason found_next = 1; 778b56baf5bSYan if (ret != 0) 779f578d4bdSChris Mason goto insert; 78027b9a812SFilipe Manana slot = path->slots[0]; 781f578d4bdSChris Mason } 782f578d4bdSChris Mason btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); 783d20f7043SChris Mason if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 784d20f7043SChris Mason found_key.type != BTRFS_EXTENT_CSUM_KEY) { 785f578d4bdSChris Mason found_next = 1; 786f578d4bdSChris Mason goto insert; 787f578d4bdSChris Mason } 788f578d4bdSChris Mason next_offset = found_key.offset; 789f578d4bdSChris Mason found_next = 1; 790a429e513SChris Mason goto insert; 791a429e513SChris Mason } 792a429e513SChris Mason 793a429e513SChris Mason /* 794a429e513SChris Mason * at this point, we know the tree has an item, but it isn't big 795a429e513SChris Mason * enough yet to put our csum in. Grow it 796a429e513SChris Mason */ 797b3b4aa74SDavid Sterba btrfs_release_path(path); 7986567e837SChris Mason ret = btrfs_search_slot(trans, root, &file_key, path, 799607d432dSJosef Bacik csum_size, 1); 8006567e837SChris Mason if (ret < 0) 80153863232SChris Mason goto fail_unlock; 802459931ecSChris Mason 803459931ecSChris Mason if (ret > 0) { 804459931ecSChris Mason if (path->slots[0] == 0) 8056567e837SChris Mason goto insert; 8066567e837SChris Mason path->slots[0]--; 807459931ecSChris Mason } 808459931ecSChris Mason 8095f39d397SChris Mason leaf = path->nodes[0]; 8105f39d397SChris Mason btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 811d20f7043SChris Mason csum_offset = (bytenr - found_key.offset) >> 812*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 813459931ecSChris Mason 814962a298fSDavid Sterba if (found_key.type != BTRFS_EXTENT_CSUM_KEY || 815d20f7043SChris Mason found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 816*0b246afaSJeff Mahoney csum_offset >= MAX_CSUM_ITEMS(fs_info, csum_size)) { 8176567e837SChris Mason goto insert; 8186567e837SChris Mason } 819459931ecSChris Mason 8202f697dc6SLiu Bo if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / 821607d432dSJosef Bacik csum_size) { 8222f697dc6SLiu Bo int extend_nr; 8232f697dc6SLiu Bo u64 tmp; 8242f697dc6SLiu Bo u32 diff; 8252f697dc6SLiu Bo u32 free_space; 826459931ecSChris Mason 8272f697dc6SLiu Bo if (btrfs_leaf_free_space(root, leaf) < 8282f697dc6SLiu Bo sizeof(struct btrfs_item) + csum_size * 2) 8292f697dc6SLiu Bo goto insert; 8302f697dc6SLiu Bo 8312f697dc6SLiu Bo free_space = btrfs_leaf_free_space(root, leaf) - 8322f697dc6SLiu Bo sizeof(struct btrfs_item) - csum_size; 833f51a4a18SMiao Xie tmp = sums->len - total_bytes; 834*0b246afaSJeff Mahoney tmp >>= fs_info->sb->s_blocksize_bits; 8352f697dc6SLiu Bo WARN_ON(tmp < 1); 8362f697dc6SLiu Bo 8372f697dc6SLiu Bo extend_nr = max_t(int, 1, (int)tmp); 8382f697dc6SLiu Bo diff = (csum_offset + extend_nr) * csum_size; 839*0b246afaSJeff Mahoney diff = min(diff, 840*0b246afaSJeff Mahoney MAX_CSUM_ITEMS(fs_info, csum_size) * csum_size); 841459931ecSChris Mason 8425f39d397SChris Mason diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 8432f697dc6SLiu Bo diff = min(free_space, diff); 8442f697dc6SLiu Bo diff /= csum_size; 8452f697dc6SLiu Bo diff *= csum_size; 846459931ecSChris Mason 8474b90c680STsutomu Itoh btrfs_extend_item(root, path, diff); 848f51a4a18SMiao Xie ret = 0; 8496567e837SChris Mason goto csum; 8506567e837SChris Mason } 8516567e837SChris Mason 8526567e837SChris Mason insert: 853b3b4aa74SDavid Sterba btrfs_release_path(path); 8546567e837SChris Mason csum_offset = 0; 855f578d4bdSChris Mason if (found_next) { 8562f697dc6SLiu Bo u64 tmp; 857d20f7043SChris Mason 858f51a4a18SMiao Xie tmp = sums->len - total_bytes; 859*0b246afaSJeff Mahoney tmp >>= fs_info->sb->s_blocksize_bits; 8602f697dc6SLiu Bo tmp = min(tmp, (next_offset - file_key.offset) >> 861*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits); 8622f697dc6SLiu Bo 863f578d4bdSChris Mason tmp = max((u64)1, tmp); 864*0b246afaSJeff Mahoney tmp = min(tmp, (u64)MAX_CSUM_ITEMS(fs_info, csum_size)); 865607d432dSJosef Bacik ins_size = csum_size * tmp; 866f578d4bdSChris Mason } else { 867607d432dSJosef Bacik ins_size = csum_size; 868f578d4bdSChris Mason } 869b9473439SChris Mason path->leave_spinning = 1; 8705caf2a00SChris Mason ret = btrfs_insert_empty_item(trans, root, path, &file_key, 871f578d4bdSChris Mason ins_size); 872b9473439SChris Mason path->leave_spinning = 0; 87354aa1f4dSChris Mason if (ret < 0) 87453863232SChris Mason goto fail_unlock; 875fae7f21cSDulshani Gunawardhana if (WARN_ON(ret != 0)) 87653863232SChris Mason goto fail_unlock; 8775f39d397SChris Mason leaf = path->nodes[0]; 878f51a4a18SMiao Xie csum: 8795f39d397SChris Mason item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); 880f51a4a18SMiao Xie item_end = (struct btrfs_csum_item *)((unsigned char *)item + 881f51a4a18SMiao Xie btrfs_item_size_nr(leaf, path->slots[0])); 882509659cdSChris Mason item = (struct btrfs_csum_item *)((unsigned char *)item + 883607d432dSJosef Bacik csum_offset * csum_size); 884b18c6685SChris Mason found: 885f51a4a18SMiao Xie ins_size = (u32)(sums->len - total_bytes) >> 886*0b246afaSJeff Mahoney fs_info->sb->s_blocksize_bits; 887f51a4a18SMiao Xie ins_size *= csum_size; 888f51a4a18SMiao Xie ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item, 889f51a4a18SMiao Xie ins_size); 890f51a4a18SMiao Xie write_extent_buffer(leaf, sums->sums + index, (unsigned long)item, 891f51a4a18SMiao Xie ins_size); 892aadfeb6eSChris Mason 893f51a4a18SMiao Xie ins_size /= csum_size; 894*0b246afaSJeff Mahoney total_bytes += ins_size * fs_info->sectorsize; 895f51a4a18SMiao Xie index += ins_size; 896a6591715SChris Mason 8975caf2a00SChris Mason btrfs_mark_buffer_dirty(path->nodes[0]); 898e6dcd2dcSChris Mason if (total_bytes < sums->len) { 899b3b4aa74SDavid Sterba btrfs_release_path(path); 900b9473439SChris Mason cond_resched(); 901065631f6SChris Mason goto again; 902065631f6SChris Mason } 90353863232SChris Mason out: 9045caf2a00SChris Mason btrfs_free_path(path); 905f254e52cSChris Mason return ret; 90653863232SChris Mason 90753863232SChris Mason fail_unlock: 90853863232SChris Mason goto out; 909f254e52cSChris Mason } 9107ffbb598SFilipe Manana 9117ffbb598SFilipe Manana void btrfs_extent_item_to_extent_map(struct inode *inode, 9127ffbb598SFilipe Manana const struct btrfs_path *path, 9137ffbb598SFilipe Manana struct btrfs_file_extent_item *fi, 9147ffbb598SFilipe Manana const bool new_inline, 9157ffbb598SFilipe Manana struct extent_map *em) 9167ffbb598SFilipe Manana { 917*0b246afaSJeff Mahoney struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); 9187ffbb598SFilipe Manana struct btrfs_root *root = BTRFS_I(inode)->root; 9197ffbb598SFilipe Manana struct extent_buffer *leaf = path->nodes[0]; 9207ffbb598SFilipe Manana const int slot = path->slots[0]; 9217ffbb598SFilipe Manana struct btrfs_key key; 9227ffbb598SFilipe Manana u64 extent_start, extent_end; 9237ffbb598SFilipe Manana u64 bytenr; 9247ffbb598SFilipe Manana u8 type = btrfs_file_extent_type(leaf, fi); 9257ffbb598SFilipe Manana int compress_type = btrfs_file_extent_compression(leaf, fi); 9267ffbb598SFilipe Manana 927*0b246afaSJeff Mahoney em->bdev = fs_info->fs_devices->latest_bdev; 9287ffbb598SFilipe Manana btrfs_item_key_to_cpu(leaf, &key, slot); 9297ffbb598SFilipe Manana extent_start = key.offset; 9307ffbb598SFilipe Manana 9317ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 9327ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9337ffbb598SFilipe Manana extent_end = extent_start + 9347ffbb598SFilipe Manana btrfs_file_extent_num_bytes(leaf, fi); 9357ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9367ffbb598SFilipe Manana size_t size; 9377ffbb598SFilipe Manana size = btrfs_file_extent_inline_len(leaf, slot, fi); 938da17066cSJeff Mahoney extent_end = ALIGN(extent_start + size, 939*0b246afaSJeff Mahoney fs_info->sectorsize); 9407ffbb598SFilipe Manana } 9417ffbb598SFilipe Manana 9427ffbb598SFilipe Manana em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); 9437ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_REG || 9447ffbb598SFilipe Manana type == BTRFS_FILE_EXTENT_PREALLOC) { 9457ffbb598SFilipe Manana em->start = extent_start; 9467ffbb598SFilipe Manana em->len = extent_end - extent_start; 9477ffbb598SFilipe Manana em->orig_start = extent_start - 9487ffbb598SFilipe Manana btrfs_file_extent_offset(leaf, fi); 9497ffbb598SFilipe Manana em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); 9507ffbb598SFilipe Manana bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); 9517ffbb598SFilipe Manana if (bytenr == 0) { 9527ffbb598SFilipe Manana em->block_start = EXTENT_MAP_HOLE; 9537ffbb598SFilipe Manana return; 9547ffbb598SFilipe Manana } 9557ffbb598SFilipe Manana if (compress_type != BTRFS_COMPRESS_NONE) { 9567ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 9577ffbb598SFilipe Manana em->compress_type = compress_type; 9587ffbb598SFilipe Manana em->block_start = bytenr; 9597ffbb598SFilipe Manana em->block_len = em->orig_block_len; 9607ffbb598SFilipe Manana } else { 9617ffbb598SFilipe Manana bytenr += btrfs_file_extent_offset(leaf, fi); 9627ffbb598SFilipe Manana em->block_start = bytenr; 9637ffbb598SFilipe Manana em->block_len = em->len; 9647ffbb598SFilipe Manana if (type == BTRFS_FILE_EXTENT_PREALLOC) 9657ffbb598SFilipe Manana set_bit(EXTENT_FLAG_PREALLOC, &em->flags); 9667ffbb598SFilipe Manana } 9677ffbb598SFilipe Manana } else if (type == BTRFS_FILE_EXTENT_INLINE) { 9687ffbb598SFilipe Manana em->block_start = EXTENT_MAP_INLINE; 9697ffbb598SFilipe Manana em->start = extent_start; 9707ffbb598SFilipe Manana em->len = extent_end - extent_start; 9717ffbb598SFilipe Manana /* 9727ffbb598SFilipe Manana * Initialize orig_start and block_len with the same values 9737ffbb598SFilipe Manana * as in inode.c:btrfs_get_extent(). 9747ffbb598SFilipe Manana */ 9757ffbb598SFilipe Manana em->orig_start = EXTENT_MAP_HOLE; 9767ffbb598SFilipe Manana em->block_len = (u64)-1; 9777ffbb598SFilipe Manana if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) { 9787ffbb598SFilipe Manana set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 9797ffbb598SFilipe Manana em->compress_type = compress_type; 9807ffbb598SFilipe Manana } 9817ffbb598SFilipe Manana } else { 982*0b246afaSJeff Mahoney btrfs_err(fs_info, 9837ffbb598SFilipe Manana "unknown file extent item type %d, inode %llu, offset %llu, root %llu", 9847ffbb598SFilipe Manana type, btrfs_ino(inode), extent_start, 9857ffbb598SFilipe Manana root->root_key.objectid); 9867ffbb598SFilipe Manana } 9877ffbb598SFilipe Manana } 988