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