linux/fs/btrfs/file-item.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2007 Oracle.  All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of the GNU General Public
   6 * License v2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11 * General Public License for more details.
  12 *
  13 * You should have received a copy of the GNU General Public
  14 * License along with this program; if not, write to the
  15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16 * Boston, MA 021110-1307, USA.
  17 */
  18
  19#include <linux/bio.h>
  20#include <linux/pagemap.h>
  21#include <linux/highmem.h>
  22#include "ctree.h"
  23#include "disk-io.h"
  24#include "transaction.h"
  25#include "print-tree.h"
  26
  27#define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r) - \
  28                                   sizeof(struct btrfs_item) * 2) / \
  29                                  size) - 1))
  30
  31#define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \
  32                                   sizeof(struct btrfs_ordered_sum)) / \
  33                                   sizeof(struct btrfs_sector_sum) * \
  34                                   (r)->sectorsize - (r)->sectorsize)
  35
  36int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
  37                             struct btrfs_root *root,
  38                             u64 objectid, u64 pos,
  39                             u64 disk_offset, u64 disk_num_bytes,
  40                             u64 num_bytes, u64 offset, u64 ram_bytes,
  41                             u8 compression, u8 encryption, u16 other_encoding)
  42{
  43        int ret = 0;
  44        struct btrfs_file_extent_item *item;
  45        struct btrfs_key file_key;
  46        struct btrfs_path *path;
  47        struct extent_buffer *leaf;
  48
  49        path = btrfs_alloc_path();
  50        BUG_ON(!path);
  51        file_key.objectid = objectid;
  52        file_key.offset = pos;
  53        btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
  54
  55        path->leave_spinning = 1;
  56        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
  57                                      sizeof(*item));
  58        if (ret < 0)
  59                goto out;
  60        BUG_ON(ret);
  61        leaf = path->nodes[0];
  62        item = btrfs_item_ptr(leaf, path->slots[0],
  63                              struct btrfs_file_extent_item);
  64        btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset);
  65        btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes);
  66        btrfs_set_file_extent_offset(leaf, item, offset);
  67        btrfs_set_file_extent_num_bytes(leaf, item, num_bytes);
  68        btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes);
  69        btrfs_set_file_extent_generation(leaf, item, trans->transid);
  70        btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
  71        btrfs_set_file_extent_compression(leaf, item, compression);
  72        btrfs_set_file_extent_encryption(leaf, item, encryption);
  73        btrfs_set_file_extent_other_encoding(leaf, item, other_encoding);
  74
  75        btrfs_mark_buffer_dirty(leaf);
  76out:
  77        btrfs_free_path(path);
  78        return ret;
  79}
  80
  81struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
  82                                          struct btrfs_root *root,
  83                                          struct btrfs_path *path,
  84                                          u64 bytenr, int cow)
  85{
  86        int ret;
  87        struct btrfs_key file_key;
  88        struct btrfs_key found_key;
  89        struct btrfs_csum_item *item;
  90        struct extent_buffer *leaf;
  91        u64 csum_offset = 0;
  92        u16 csum_size =
  93                btrfs_super_csum_size(&root->fs_info->super_copy);
  94        int csums_in_item;
  95
  96        file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
  97        file_key.offset = bytenr;
  98        btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
  99        ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
 100        if (ret < 0)
 101                goto fail;
 102        leaf = path->nodes[0];
 103        if (ret > 0) {
 104                ret = 1;
 105                if (path->slots[0] == 0)
 106                        goto fail;
 107                path->slots[0]--;
 108                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 109                if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY)
 110                        goto fail;
 111
 112                csum_offset = (bytenr - found_key.offset) >>
 113                                root->fs_info->sb->s_blocksize_bits;
 114                csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
 115                csums_in_item /= csum_size;
 116
 117                if (csum_offset >= csums_in_item) {
 118                        ret = -EFBIG;
 119                        goto fail;
 120                }
 121        }
 122        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
 123        item = (struct btrfs_csum_item *)((unsigned char *)item +
 124                                          csum_offset * csum_size);
 125        return item;
 126fail:
 127        if (ret > 0)
 128                ret = -ENOENT;
 129        return ERR_PTR(ret);
 130}
 131
 132
 133int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 134                             struct btrfs_root *root,
 135                             struct btrfs_path *path, u64 objectid,
 136                             u64 offset, int mod)
 137{
 138        int ret;
 139        struct btrfs_key file_key;
 140        int ins_len = mod < 0 ? -1 : 0;
 141        int cow = mod != 0;
 142
 143        file_key.objectid = objectid;
 144        file_key.offset = offset;
 145        btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);
 146        ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
 147        return ret;
 148}
 149
 150
 151int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
 152                          struct bio *bio, u32 *dst)
 153{
 154        u32 sum;
 155        struct bio_vec *bvec = bio->bi_io_vec;
 156        int bio_index = 0;
 157        u64 offset;
 158        u64 item_start_offset = 0;
 159        u64 item_last_offset = 0;
 160        u64 disk_bytenr;
 161        u32 diff;
 162        u16 csum_size =
 163                btrfs_super_csum_size(&root->fs_info->super_copy);
 164        int ret;
 165        struct btrfs_path *path;
 166        struct btrfs_csum_item *item = NULL;
 167        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 168
 169        path = btrfs_alloc_path();
 170        if (bio->bi_size > PAGE_CACHE_SIZE * 8)
 171                path->reada = 2;
 172
 173        WARN_ON(bio->bi_vcnt <= 0);
 174
 175        disk_bytenr = (u64)bio->bi_sector << 9;
 176        while (bio_index < bio->bi_vcnt) {
 177                offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 178                ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum);
 179                if (ret == 0)
 180                        goto found;
 181
 182                if (!item || disk_bytenr < item_start_offset ||
 183                    disk_bytenr >= item_last_offset) {
 184                        struct btrfs_key found_key;
 185                        u32 item_size;
 186
 187                        if (item)
 188                                btrfs_release_path(root, path);
 189                        item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
 190                                                 path, disk_bytenr, 0);
 191                        if (IS_ERR(item)) {
 192                                ret = PTR_ERR(item);
 193                                if (ret == -ENOENT || ret == -EFBIG)
 194                                        ret = 0;
 195                                sum = 0;
 196                                if (BTRFS_I(inode)->root->root_key.objectid ==
 197                                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
 198                                        set_extent_bits(io_tree, offset,
 199                                                offset + bvec->bv_len - 1,
 200                                                EXTENT_NODATASUM, GFP_NOFS);
 201                                } else {
 202                                        printk(KERN_INFO "btrfs no csum found "
 203                                               "for inode %lu start %llu\n",
 204                                               inode->i_ino,
 205                                               (unsigned long long)offset);
 206                                }
 207                                item = NULL;
 208                                btrfs_release_path(root, path);
 209                                goto found;
 210                        }
 211                        btrfs_item_key_to_cpu(path->nodes[0], &found_key,
 212                                              path->slots[0]);
 213
 214                        item_start_offset = found_key.offset;
 215                        item_size = btrfs_item_size_nr(path->nodes[0],
 216                                                       path->slots[0]);
 217                        item_last_offset = item_start_offset +
 218                                (item_size / csum_size) *
 219                                root->sectorsize;
 220                        item = btrfs_item_ptr(path->nodes[0], path->slots[0],
 221                                              struct btrfs_csum_item);
 222                }
 223                /*
 224                 * this byte range must be able to fit inside
 225                 * a single leaf so it will also fit inside a u32
 226                 */
 227                diff = disk_bytenr - item_start_offset;
 228                diff = diff / root->sectorsize;
 229                diff = diff * csum_size;
 230
 231                read_extent_buffer(path->nodes[0], &sum,
 232                                   ((unsigned long)item) + diff,
 233                                   csum_size);
 234found:
 235                if (dst)
 236                        *dst++ = sum;
 237                else
 238                        set_state_private(io_tree, offset, sum);
 239                disk_bytenr += bvec->bv_len;
 240                bio_index++;
 241                bvec++;
 242        }
 243        btrfs_free_path(path);
 244        return 0;
 245}
 246
 247int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
 248                             struct list_head *list)
 249{
 250        struct btrfs_key key;
 251        struct btrfs_path *path;
 252        struct extent_buffer *leaf;
 253        struct btrfs_ordered_sum *sums;
 254        struct btrfs_sector_sum *sector_sum;
 255        struct btrfs_csum_item *item;
 256        unsigned long offset;
 257        int ret;
 258        size_t size;
 259        u64 csum_end;
 260        u16 csum_size = btrfs_super_csum_size(&root->fs_info->super_copy);
 261
 262        path = btrfs_alloc_path();
 263        BUG_ON(!path);
 264
 265        key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
 266        key.offset = start;
 267        key.type = BTRFS_EXTENT_CSUM_KEY;
 268
 269        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 270        if (ret < 0)
 271                goto fail;
 272        if (ret > 0 && path->slots[0] > 0) {
 273                leaf = path->nodes[0];
 274                btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
 275                if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID &&
 276                    key.type == BTRFS_EXTENT_CSUM_KEY) {
 277                        offset = (start - key.offset) >>
 278                                 root->fs_info->sb->s_blocksize_bits;
 279                        if (offset * csum_size <
 280                            btrfs_item_size_nr(leaf, path->slots[0] - 1))
 281                                path->slots[0]--;
 282                }
 283        }
 284
 285        while (start <= end) {
 286                leaf = path->nodes[0];
 287                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
 288                        ret = btrfs_next_leaf(root, path);
 289                        if (ret < 0)
 290                                goto fail;
 291                        if (ret > 0)
 292                                break;
 293                        leaf = path->nodes[0];
 294                }
 295
 296                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 297                if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
 298                    key.type != BTRFS_EXTENT_CSUM_KEY)
 299                        break;
 300
 301                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 302                if (key.offset > end)
 303                        break;
 304
 305                if (key.offset > start)
 306                        start = key.offset;
 307
 308                size = btrfs_item_size_nr(leaf, path->slots[0]);
 309                csum_end = key.offset + (size / csum_size) * root->sectorsize;
 310                if (csum_end <= start) {
 311                        path->slots[0]++;
 312                        continue;
 313                }
 314
 315                csum_end = min(csum_end, end + 1);
 316                item = btrfs_item_ptr(path->nodes[0], path->slots[0],
 317                                      struct btrfs_csum_item);
 318                while (start < csum_end) {
 319                        size = min_t(size_t, csum_end - start,
 320                                        MAX_ORDERED_SUM_BYTES(root));
 321                        sums = kzalloc(btrfs_ordered_sum_size(root, size),
 322                                        GFP_NOFS);
 323                        BUG_ON(!sums);
 324
 325                        sector_sum = sums->sums;
 326                        sums->bytenr = start;
 327                        sums->len = size;
 328
 329                        offset = (start - key.offset) >>
 330                                root->fs_info->sb->s_blocksize_bits;
 331                        offset *= csum_size;
 332
 333                        while (size > 0) {
 334                                read_extent_buffer(path->nodes[0],
 335                                                &sector_sum->sum,
 336                                                ((unsigned long)item) +
 337                                                offset, csum_size);
 338                                sector_sum->bytenr = start;
 339
 340                                size -= root->sectorsize;
 341                                start += root->sectorsize;
 342                                offset += csum_size;
 343                                sector_sum++;
 344                        }
 345                        list_add_tail(&sums->list, list);
 346                }
 347                path->slots[0]++;
 348        }
 349        ret = 0;
 350fail:
 351        btrfs_free_path(path);
 352        return ret;
 353}
 354
 355int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
 356                       struct bio *bio, u64 file_start, int contig)
 357{
 358        struct btrfs_ordered_sum *sums;
 359        struct btrfs_sector_sum *sector_sum;
 360        struct btrfs_ordered_extent *ordered;
 361        char *data;
 362        struct bio_vec *bvec = bio->bi_io_vec;
 363        int bio_index = 0;
 364        unsigned long total_bytes = 0;
 365        unsigned long this_sum_bytes = 0;
 366        u64 offset;
 367        u64 disk_bytenr;
 368
 369        WARN_ON(bio->bi_vcnt <= 0);
 370        sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
 371        if (!sums)
 372                return -ENOMEM;
 373
 374        sector_sum = sums->sums;
 375        disk_bytenr = (u64)bio->bi_sector << 9;
 376        sums->len = bio->bi_size;
 377        INIT_LIST_HEAD(&sums->list);
 378
 379        if (contig)
 380                offset = file_start;
 381        else
 382                offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 383
 384        ordered = btrfs_lookup_ordered_extent(inode, offset);
 385        BUG_ON(!ordered);
 386        sums->bytenr = ordered->start;
 387
 388        while (bio_index < bio->bi_vcnt) {
 389                if (!contig)
 390                        offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 391
 392                if (!contig && (offset >= ordered->file_offset + ordered->len ||
 393                    offset < ordered->file_offset)) {
 394                        unsigned long bytes_left;
 395                        sums->len = this_sum_bytes;
 396                        this_sum_bytes = 0;
 397                        btrfs_add_ordered_sum(inode, ordered, sums);
 398                        btrfs_put_ordered_extent(ordered);
 399
 400                        bytes_left = bio->bi_size - total_bytes;
 401
 402                        sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
 403                                       GFP_NOFS);
 404                        BUG_ON(!sums);
 405                        sector_sum = sums->sums;
 406                        sums->len = bytes_left;
 407                        ordered = btrfs_lookup_ordered_extent(inode, offset);
 408                        BUG_ON(!ordered);
 409                        sums->bytenr = ordered->start;
 410                }
 411
 412                data = kmap_atomic(bvec->bv_page, KM_USER0);
 413                sector_sum->sum = ~(u32)0;
 414                sector_sum->sum = btrfs_csum_data(root,
 415                                                  data + bvec->bv_offset,
 416                                                  sector_sum->sum,
 417                                                  bvec->bv_len);
 418                kunmap_atomic(data, KM_USER0);
 419                btrfs_csum_final(sector_sum->sum,
 420                                 (char *)&sector_sum->sum);
 421                sector_sum->bytenr = disk_bytenr;
 422
 423                sector_sum++;
 424                bio_index++;
 425                total_bytes += bvec->bv_len;
 426                this_sum_bytes += bvec->bv_len;
 427                disk_bytenr += bvec->bv_len;
 428                offset += bvec->bv_len;
 429                bvec++;
 430        }
 431        this_sum_bytes = 0;
 432        btrfs_add_ordered_sum(inode, ordered, sums);
 433        btrfs_put_ordered_extent(ordered);
 434        return 0;
 435}
 436
 437/*
 438 * helper function for csum removal, this expects the
 439 * key to describe the csum pointed to by the path, and it expects
 440 * the csum to overlap the range [bytenr, len]
 441 *
 442 * The csum should not be entirely contained in the range and the
 443 * range should not be entirely contained in the csum.
 444 *
 445 * This calls btrfs_truncate_item with the correct args based on the
 446 * overlap, and fixes up the key as required.
 447 */
 448static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
 449                                      struct btrfs_root *root,
 450                                      struct btrfs_path *path,
 451                                      struct btrfs_key *key,
 452                                      u64 bytenr, u64 len)
 453{
 454        struct extent_buffer *leaf;
 455        u16 csum_size =
 456                btrfs_super_csum_size(&root->fs_info->super_copy);
 457        u64 csum_end;
 458        u64 end_byte = bytenr + len;
 459        u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits;
 460        int ret;
 461
 462        leaf = path->nodes[0];
 463        csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
 464        csum_end <<= root->fs_info->sb->s_blocksize_bits;
 465        csum_end += key->offset;
 466
 467        if (key->offset < bytenr && csum_end <= end_byte) {
 468                /*
 469                 *         [ bytenr - len ]
 470                 *         [   ]
 471                 *   [csum     ]
 472                 *   A simple truncate off the end of the item
 473                 */
 474                u32 new_size = (bytenr - key->offset) >> blocksize_bits;
 475                new_size *= csum_size;
 476                ret = btrfs_truncate_item(trans, root, path, new_size, 1);
 477                BUG_ON(ret);
 478        } else if (key->offset >= bytenr && csum_end > end_byte &&
 479                   end_byte > key->offset) {
 480                /*
 481                 *         [ bytenr - len ]
 482                 *                 [ ]
 483                 *                 [csum     ]
 484                 * we need to truncate from the beginning of the csum
 485                 */
 486                u32 new_size = (csum_end - end_byte) >> blocksize_bits;
 487                new_size *= csum_size;
 488
 489                ret = btrfs_truncate_item(trans, root, path, new_size, 0);
 490                BUG_ON(ret);
 491
 492                key->offset = end_byte;
 493                ret = btrfs_set_item_key_safe(trans, root, path, key);
 494                BUG_ON(ret);
 495        } else {
 496                BUG();
 497        }
 498        return 0;
 499}
 500
 501/*
 502 * deletes the csum items from the csum tree for a given
 503 * range of bytes.
 504 */
 505int btrfs_del_csums(struct btrfs_trans_handle *trans,
 506                    struct btrfs_root *root, u64 bytenr, u64 len)
 507{
 508        struct btrfs_path *path;
 509        struct btrfs_key key;
 510        u64 end_byte = bytenr + len;
 511        u64 csum_end;
 512        struct extent_buffer *leaf;
 513        int ret;
 514        u16 csum_size =
 515                btrfs_super_csum_size(&root->fs_info->super_copy);
 516        int blocksize_bits = root->fs_info->sb->s_blocksize_bits;
 517
 518        root = root->fs_info->csum_root;
 519
 520        path = btrfs_alloc_path();
 521
 522        while (1) {
 523                key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
 524                key.offset = end_byte - 1;
 525                key.type = BTRFS_EXTENT_CSUM_KEY;
 526
 527                path->leave_spinning = 1;
 528                ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 529                if (ret > 0) {
 530                        if (path->slots[0] == 0)
 531                                goto out;
 532                        path->slots[0]--;
 533                }
 534                leaf = path->nodes[0];
 535                btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
 536
 537                if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
 538                    key.type != BTRFS_EXTENT_CSUM_KEY) {
 539                        break;
 540                }
 541
 542                if (key.offset >= end_byte)
 543                        break;
 544
 545                csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
 546                csum_end <<= blocksize_bits;
 547                csum_end += key.offset;
 548
 549                /* this csum ends before we start, we're done */
 550                if (csum_end <= bytenr)
 551                        break;
 552
 553                /* delete the entire item, it is inside our range */
 554                if (key.offset >= bytenr && csum_end <= end_byte) {
 555                        ret = btrfs_del_item(trans, root, path);
 556                        BUG_ON(ret);
 557                        if (key.offset == bytenr)
 558                                break;
 559                } else if (key.offset < bytenr && csum_end > end_byte) {
 560                        unsigned long offset;
 561                        unsigned long shift_len;
 562                        unsigned long item_offset;
 563                        /*
 564                         *        [ bytenr - len ]
 565                         *     [csum                ]
 566                         *
 567                         * Our bytes are in the middle of the csum,
 568                         * we need to split this item and insert a new one.
 569                         *
 570                         * But we can't drop the path because the
 571                         * csum could change, get removed, extended etc.
 572                         *
 573                         * The trick here is the max size of a csum item leaves
 574                         * enough room in the tree block for a single
 575                         * item header.  So, we split the item in place,
 576                         * adding a new header pointing to the existing
 577                         * bytes.  Then we loop around again and we have
 578                         * a nicely formed csum item that we can neatly
 579                         * truncate.
 580                         */
 581                        offset = (bytenr - key.offset) >> blocksize_bits;
 582                        offset *= csum_size;
 583
 584                        shift_len = (len >> blocksize_bits) * csum_size;
 585
 586                        item_offset = btrfs_item_ptr_offset(leaf,
 587                                                            path->slots[0]);
 588
 589                        memset_extent_buffer(leaf, 0, item_offset + offset,
 590                                             shift_len);
 591                        key.offset = bytenr;
 592
 593                        /*
 594                         * btrfs_split_item returns -EAGAIN when the
 595                         * item changed size or key
 596                         */
 597                        ret = btrfs_split_item(trans, root, path, &key, offset);
 598                        BUG_ON(ret && ret != -EAGAIN);
 599
 600                        key.offset = end_byte - 1;
 601                } else {
 602                        ret = truncate_one_csum(trans, root, path,
 603                                                &key, bytenr, len);
 604                        BUG_ON(ret);
 605                        if (key.offset < bytenr)
 606                                break;
 607                }
 608                btrfs_release_path(root, path);
 609        }
 610out:
 611        btrfs_free_path(path);
 612        return 0;
 613}
 614
 615int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
 616                           struct btrfs_root *root,
 617                           struct btrfs_ordered_sum *sums)
 618{
 619        u64 bytenr;
 620        int ret;
 621        struct btrfs_key file_key;
 622        struct btrfs_key found_key;
 623        u64 next_offset;
 624        u64 total_bytes = 0;
 625        int found_next;
 626        struct btrfs_path *path;
 627        struct btrfs_csum_item *item;
 628        struct btrfs_csum_item *item_end;
 629        struct extent_buffer *leaf = NULL;
 630        u64 csum_offset;
 631        struct btrfs_sector_sum *sector_sum;
 632        u32 nritems;
 633        u32 ins_size;
 634        char *eb_map;
 635        char *eb_token;
 636        unsigned long map_len;
 637        unsigned long map_start;
 638        u16 csum_size =
 639                btrfs_super_csum_size(&root->fs_info->super_copy);
 640
 641        path = btrfs_alloc_path();
 642        BUG_ON(!path);
 643        sector_sum = sums->sums;
 644again:
 645        next_offset = (u64)-1;
 646        found_next = 0;
 647        file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
 648        file_key.offset = sector_sum->bytenr;
 649        bytenr = sector_sum->bytenr;
 650        btrfs_set_key_type(&file_key, BTRFS_EXTENT_CSUM_KEY);
 651
 652        item = btrfs_lookup_csum(trans, root, path, sector_sum->bytenr, 1);
 653        if (!IS_ERR(item)) {
 654                leaf = path->nodes[0];
 655                ret = 0;
 656                goto found;
 657        }
 658        ret = PTR_ERR(item);
 659        if (ret == -EFBIG) {
 660                u32 item_size;
 661                /* we found one, but it isn't big enough yet */
 662                leaf = path->nodes[0];
 663                item_size = btrfs_item_size_nr(leaf, path->slots[0]);
 664                if ((item_size / csum_size) >=
 665                    MAX_CSUM_ITEMS(root, csum_size)) {
 666                        /* already at max size, make a new one */
 667                        goto insert;
 668                }
 669        } else {
 670                int slot = path->slots[0] + 1;
 671                /* we didn't find a csum item, insert one */
 672                nritems = btrfs_header_nritems(path->nodes[0]);
 673                if (path->slots[0] >= nritems - 1) {
 674                        ret = btrfs_next_leaf(root, path);
 675                        if (ret == 1)
 676                                found_next = 1;
 677                        if (ret != 0)
 678                                goto insert;
 679                        slot = 0;
 680                }
 681                btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
 682                if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
 683                    found_key.type != BTRFS_EXTENT_CSUM_KEY) {
 684                        found_next = 1;
 685                        goto insert;
 686                }
 687                next_offset = found_key.offset;
 688                found_next = 1;
 689                goto insert;
 690        }
 691
 692        /*
 693         * at this point, we know the tree has an item, but it isn't big
 694         * enough yet to put our csum in.  Grow it
 695         */
 696        btrfs_release_path(root, path);
 697        ret = btrfs_search_slot(trans, root, &file_key, path,
 698                                csum_size, 1);
 699        if (ret < 0)
 700                goto fail_unlock;
 701
 702        if (ret > 0) {
 703                if (path->slots[0] == 0)
 704                        goto insert;
 705                path->slots[0]--;
 706        }
 707
 708        leaf = path->nodes[0];
 709        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
 710        csum_offset = (bytenr - found_key.offset) >>
 711                        root->fs_info->sb->s_blocksize_bits;
 712
 713        if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY ||
 714            found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
 715            csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
 716                goto insert;
 717        }
 718
 719        if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
 720            csum_size) {
 721                u32 diff = (csum_offset + 1) * csum_size;
 722
 723                /*
 724                 * is the item big enough already?  we dropped our lock
 725                 * before and need to recheck
 726                 */
 727                if (diff < btrfs_item_size_nr(leaf, path->slots[0]))
 728                        goto csum;
 729
 730                diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
 731                if (diff != csum_size)
 732                        goto insert;
 733
 734                ret = btrfs_extend_item(trans, root, path, diff);
 735                BUG_ON(ret);
 736                goto csum;
 737        }
 738
 739insert:
 740        btrfs_release_path(root, path);
 741        csum_offset = 0;
 742        if (found_next) {
 743                u64 tmp = total_bytes + root->sectorsize;
 744                u64 next_sector = sector_sum->bytenr;
 745                struct btrfs_sector_sum *next = sector_sum + 1;
 746
 747                while (tmp < sums->len) {
 748                        if (next_sector + root->sectorsize != next->bytenr)
 749                                break;
 750                        tmp += root->sectorsize;
 751                        next_sector = next->bytenr;
 752                        next++;
 753                }
 754                tmp = min(tmp, next_offset - file_key.offset);
 755                tmp >>= root->fs_info->sb->s_blocksize_bits;
 756                tmp = max((u64)1, tmp);
 757                tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size));
 758                ins_size = csum_size * tmp;
 759        } else {
 760                ins_size = csum_size;
 761        }
 762        path->leave_spinning = 1;
 763        ret = btrfs_insert_empty_item(trans, root, path, &file_key,
 764                                      ins_size);
 765        path->leave_spinning = 0;
 766        if (ret < 0)
 767                goto fail_unlock;
 768        if (ret != 0) {
 769                WARN_ON(1);
 770                goto fail_unlock;
 771        }
 772csum:
 773        leaf = path->nodes[0];
 774        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
 775        ret = 0;
 776        item = (struct btrfs_csum_item *)((unsigned char *)item +
 777                                          csum_offset * csum_size);
 778found:
 779        item_end = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
 780        item_end = (struct btrfs_csum_item *)((unsigned char *)item_end +
 781                                      btrfs_item_size_nr(leaf, path->slots[0]));
 782        eb_token = NULL;
 783next_sector:
 784
 785        if (!eb_token ||
 786           (unsigned long)item + csum_size >= map_start + map_len) {
 787                int err;
 788
 789                if (eb_token)
 790                        unmap_extent_buffer(leaf, eb_token, KM_USER1);
 791                eb_token = NULL;
 792                err = map_private_extent_buffer(leaf, (unsigned long)item,
 793                                                csum_size,
 794                                                &eb_token, &eb_map,
 795                                                &map_start, &map_len, KM_USER1);
 796                if (err)
 797                        eb_token = NULL;
 798        }
 799        if (eb_token) {
 800                memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
 801                       &sector_sum->sum, csum_size);
 802        } else {
 803                write_extent_buffer(leaf, &sector_sum->sum,
 804                                    (unsigned long)item, csum_size);
 805        }
 806
 807        total_bytes += root->sectorsize;
 808        sector_sum++;
 809        if (total_bytes < sums->len) {
 810                item = (struct btrfs_csum_item *)((char *)item +
 811                                                  csum_size);
 812                if (item < item_end && bytenr + PAGE_CACHE_SIZE ==
 813                    sector_sum->bytenr) {
 814                        bytenr = sector_sum->bytenr;
 815                        goto next_sector;
 816                }
 817        }
 818        if (eb_token) {
 819                unmap_extent_buffer(leaf, eb_token, KM_USER1);
 820                eb_token = NULL;
 821        }
 822        btrfs_mark_buffer_dirty(path->nodes[0]);
 823        if (total_bytes < sums->len) {
 824                btrfs_release_path(root, path);
 825                cond_resched();
 826                goto again;
 827        }
 828out:
 829        btrfs_free_path(path);
 830        return ret;
 831
 832fail_unlock:
 833        goto out;
 834}
 835