aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-12-10 09:10:46 -0500
committerChris Mason <chris.mason@oracle.com>2008-12-10 09:10:46 -0500
commit459931eca5f4b8c9ad259d07cc1ca49afed54804 (patch)
tree86088c14cff53f93281dc25022b61fb1d86c2458 /fs/btrfs
parent580afd76e451deb6772d0507de580fb1df14da6c (diff)
Btrfs: Delete csum items when freeing extents
This finishes off the new checksumming code by removing csum items for extents that are no longer in use. The trick is doing it without racing because a single csum item may hold csums for more than one extent. Extra checks are added to btrfs_csum_file_blocks to make sure that we are using the correct csum item after dropping locks. A new btrfs_split_item is added to split a single csum item so it can be split without dropping the leaf lock. This is used to remove csum bytes from the middle of an item. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.c131
-rw-r--r--fs/btrfs/ctree.h13
-rw-r--r--fs/btrfs/extent-tree.c6
-rw-r--r--fs/btrfs/file-item.c226
4 files changed, 335 insertions, 41 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 19c0dd33b1e8..c0c95cccbb5b 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1512,7 +1512,8 @@ cow_done:
1512 if (ret && slot > 0) 1512 if (ret && slot > 0)
1513 slot -= 1; 1513 slot -= 1;
1514 p->slots[level] = slot; 1514 p->slots[level] = slot;
1515 if (ins_len > 0 && btrfs_header_nritems(b) >= 1515 if ((p->search_for_split || ins_len > 0) &&
1516 btrfs_header_nritems(b) >=
1516 BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { 1517 BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
1517 int sret = split_node(trans, root, p, level); 1518 int sret = split_node(trans, root, p, level);
1518 BUG_ON(sret > 0); 1519 BUG_ON(sret > 0);
@@ -1596,7 +1597,8 @@ cow_done:
1596 goto done; 1597 goto done;
1597 } 1598 }
1598 } 1599 }
1599 unlock_up(p, level, lowest_unlock); 1600 if (!p->search_for_split)
1601 unlock_up(p, level, lowest_unlock);
1600 goto done; 1602 goto done;
1601 } 1603 }
1602 } 1604 }
@@ -2636,11 +2638,11 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
2636 int num_doubles = 0; 2638 int num_doubles = 0;
2637 struct btrfs_disk_key disk_key; 2639 struct btrfs_disk_key disk_key;
2638 2640
2639 if (extend) 2641 if (extend && data_size)
2640 space_needed = data_size; 2642 space_needed = data_size;
2641 2643
2642 /* first try to make some room by pushing left and right */ 2644 /* first try to make some room by pushing left and right */
2643 if (ins_key->type != BTRFS_DIR_ITEM_KEY) { 2645 if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
2644 wret = push_leaf_right(trans, root, path, data_size, 0); 2646 wret = push_leaf_right(trans, root, path, data_size, 0);
2645 if (wret < 0) { 2647 if (wret < 0) {
2646 return wret; 2648 return wret;
@@ -2721,7 +2723,7 @@ again:
2721 } else { 2723 } else {
2722 if (leaf_space_used(l, 0, mid + 1) + space_needed > 2724 if (leaf_space_used(l, 0, mid + 1) + space_needed >
2723 BTRFS_LEAF_DATA_SIZE(root)) { 2725 BTRFS_LEAF_DATA_SIZE(root)) {
2724 if (!extend && slot == 0) { 2726 if (!extend && data_size && slot == 0) {
2725 btrfs_cpu_key_to_disk(&disk_key, ins_key); 2727 btrfs_cpu_key_to_disk(&disk_key, ins_key);
2726 btrfs_set_header_nritems(right, 0); 2728 btrfs_set_header_nritems(right, 0);
2727 wret = insert_ptr(trans, root, path, 2729 wret = insert_ptr(trans, root, path,
@@ -2742,7 +2744,7 @@ again:
2742 } 2744 }
2743 btrfs_mark_buffer_dirty(right); 2745 btrfs_mark_buffer_dirty(right);
2744 return ret; 2746 return ret;
2745 } else if (extend && slot == 0) { 2747 } else if ((extend || !data_size) && slot == 0) {
2746 mid = 1; 2748 mid = 1;
2747 } else { 2749 } else {
2748 mid = slot; 2750 mid = slot;
@@ -2828,6 +2830,123 @@ again:
2828} 2830}
2829 2831
2830/* 2832/*
2833 * This function splits a single item into two items,
2834 * giving 'new_key' to the new item and splitting the
2835 * old one at split_offset (from the start of the item).
2836 *
2837 * The path may be released by this operation. After
2838 * the split, the path is pointing to the old item. The
2839 * new item is going to be in the same node as the old one.
2840 *
2841 * Note, the item being split must be smaller enough to live alone on
2842 * a tree block with room for one extra struct btrfs_item
2843 *
2844 * This allows us to split the item in place, keeping a lock on the
2845 * leaf the entire time.
2846 */
2847int btrfs_split_item(struct btrfs_trans_handle *trans,
2848 struct btrfs_root *root,
2849 struct btrfs_path *path,
2850 struct btrfs_key *new_key,
2851 unsigned long split_offset)
2852{
2853 u32 item_size;
2854 struct extent_buffer *leaf;
2855 struct btrfs_key orig_key;
2856 struct btrfs_item *item;
2857 struct btrfs_item *new_item;
2858 int ret = 0;
2859 int slot;
2860 u32 nritems;
2861 u32 orig_offset;
2862 struct btrfs_disk_key disk_key;
2863 char *buf;
2864
2865 leaf = path->nodes[0];
2866 btrfs_item_key_to_cpu(leaf, &orig_key, path->slots[0]);
2867 if (btrfs_leaf_free_space(root, leaf) >= sizeof(struct btrfs_item))
2868 goto split;
2869
2870 item_size = btrfs_item_size_nr(leaf, path->slots[0]);
2871 btrfs_release_path(root, path);
2872
2873 path->search_for_split = 1;
2874 path->keep_locks = 1;
2875
2876 ret = btrfs_search_slot(trans, root, &orig_key, path, 0, 1);
2877 path->search_for_split = 0;
2878
2879 /* if our item isn't there or got smaller, return now */
2880 if (ret != 0 || item_size != btrfs_item_size_nr(path->nodes[0],
2881 path->slots[0])) {
2882 path->keep_locks = 0;
2883 return -EAGAIN;
2884 }
2885
2886 ret = split_leaf(trans, root, &orig_key, path, 0, 0);
2887 path->keep_locks = 0;
2888 BUG_ON(ret);
2889
2890 BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item));
2891 leaf = path->nodes[0];
2892
2893split:
2894 item = btrfs_item_nr(leaf, path->slots[0]);
2895 orig_offset = btrfs_item_offset(leaf, item);
2896 item_size = btrfs_item_size(leaf, item);
2897
2898
2899 buf = kmalloc(item_size, GFP_NOFS);
2900 read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf,
2901 path->slots[0]), item_size);
2902 slot = path->slots[0] + 1;
2903 leaf = path->nodes[0];
2904
2905 nritems = btrfs_header_nritems(leaf);
2906
2907 if (slot != nritems) {
2908 /* shift the items */
2909 memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1),
2910 btrfs_item_nr_offset(slot),
2911 (nritems - slot) * sizeof(struct btrfs_item));
2912
2913 }
2914
2915 btrfs_cpu_key_to_disk(&disk_key, new_key);
2916 btrfs_set_item_key(leaf, &disk_key, slot);
2917
2918 new_item = btrfs_item_nr(leaf, slot);
2919
2920 btrfs_set_item_offset(leaf, new_item, orig_offset);
2921 btrfs_set_item_size(leaf, new_item, item_size - split_offset);
2922
2923 btrfs_set_item_offset(leaf, item,
2924 orig_offset + item_size - split_offset);
2925 btrfs_set_item_size(leaf, item, split_offset);
2926
2927 btrfs_set_header_nritems(leaf, nritems + 1);
2928
2929 /* write the data for the start of the original item */
2930 write_extent_buffer(leaf, buf,
2931 btrfs_item_ptr_offset(leaf, path->slots[0]),
2932 split_offset);
2933
2934 /* write the data for the new item */
2935 write_extent_buffer(leaf, buf + split_offset,
2936 btrfs_item_ptr_offset(leaf, slot),
2937 item_size - split_offset);
2938 btrfs_mark_buffer_dirty(leaf);
2939
2940 ret = 0;
2941 if (btrfs_leaf_free_space(root, leaf) < 0) {
2942 btrfs_print_leaf(root, leaf);
2943 BUG();
2944 }
2945 kfree(buf);
2946 return ret;
2947}
2948
2949/*
2831 * make the item pointed to by the path smaller. new_size indicates 2950 * make the item pointed to by the path smaller. new_size indicates
2832 * how small to make it, and from_end tells us if we just chop bytes 2951 * how small to make it, and from_end tells us if we just chop bytes
2833 * off the end of the item or if we shift the item to chop bytes off 2952 * off the end of the item or if we shift the item to chop bytes off
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f72b43819349..5b0c79d22c09 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -409,6 +409,12 @@ struct btrfs_path {
409 int keep_locks; 409 int keep_locks;
410 int skip_locking; 410 int skip_locking;
411 int lowest_level; 411 int lowest_level;
412
413 /*
414 * set by btrfs_split_item, tells search_slot to keep all locks
415 * and to force calls to keep space in the nodes
416 */
417 int search_for_split;
412}; 418};
413 419
414/* 420/*
@@ -1816,6 +1822,11 @@ int btrfs_truncate_item(struct btrfs_trans_handle *trans,
1816 struct btrfs_root *root, 1822 struct btrfs_root *root,
1817 struct btrfs_path *path, 1823 struct btrfs_path *path,
1818 u32 new_size, int from_end); 1824 u32 new_size, int from_end);
1825int btrfs_split_item(struct btrfs_trans_handle *trans,
1826 struct btrfs_root *root,
1827 struct btrfs_path *path,
1828 struct btrfs_key *new_key,
1829 unsigned long split_offset);
1819int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root 1830int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
1820 *root, struct btrfs_key *key, struct btrfs_path *p, int 1831 *root, struct btrfs_key *key, struct btrfs_path *p, int
1821 ins_len, int cow); 1832 ins_len, int cow);
@@ -1953,6 +1964,8 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
1953 struct btrfs_key *location, int mod); 1964 struct btrfs_key *location, int mod);
1954 1965
1955/* file-item.c */ 1966/* file-item.c */
1967int btrfs_del_csums(struct btrfs_trans_handle *trans,
1968 struct btrfs_root *root, u64 bytenr, u64 len);
1956int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, 1969int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
1957 struct bio *bio, u32 *dst); 1970 struct bio *bio, u32 *dst);
1958int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, 1971int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 803647bc8400..cc74316dc426 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2484,7 +2484,6 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2484 mark_free = 1; 2484 mark_free = 1;
2485 BUG_ON(ret < 0); 2485 BUG_ON(ret < 0);
2486 } 2486 }
2487
2488 /* block accounting for super block */ 2487 /* block accounting for super block */
2489 spin_lock_irq(&info->delalloc_lock); 2488 spin_lock_irq(&info->delalloc_lock);
2490 super_used = btrfs_super_bytes_used(&info->super_copy); 2489 super_used = btrfs_super_bytes_used(&info->super_copy);
@@ -2504,6 +2503,11 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2504 mark_free); 2503 mark_free);
2505 BUG_ON(ret); 2504 BUG_ON(ret);
2506 2505
2506 if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
2507 ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
2508 BUG_ON(ret);
2509 }
2510
2507#ifdef BIO_RW_DISCARD 2511#ifdef BIO_RW_DISCARD
2508 /* Tell the block device(s) that the sectors can be discarded */ 2512 /* Tell the block device(s) that the sectors can be discarded */
2509 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, 2513 ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index a3ad2ce00116..3ebef871ee6c 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -310,6 +310,179 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
310 return 0; 310 return 0;
311} 311}
312 312
313/*
314 * helper function for csum removal, this expects the
315 * key to describe the csum pointed to by the path, and it expects
316 * the csum to overlap the range [bytenr, len]
317 *
318 * The csum should not be entirely contained in the range and the
319 * range should not be entirely contained in the csum.
320 *
321 * This calls btrfs_truncate_item with the correct args based on the
322 * overlap, and fixes up the key as required.
323 */
324static noinline int truncate_one_csum(struct btrfs_trans_handle *trans,
325 struct btrfs_root *root,
326 struct btrfs_path *path,
327 struct btrfs_key *key,
328 u64 bytenr, u64 len)
329{
330 struct extent_buffer *leaf;
331 u16 csum_size =
332 btrfs_super_csum_size(&root->fs_info->super_copy);
333 u64 csum_end;
334 u64 end_byte = bytenr + len;
335 u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits;
336 int ret;
337
338 leaf = path->nodes[0];
339 csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
340 csum_end <<= root->fs_info->sb->s_blocksize_bits;
341 csum_end += key->offset;
342
343 if (key->offset < bytenr && csum_end <= end_byte) {
344 /*
345 * [ bytenr - len ]
346 * [ ]
347 * [csum ]
348 * A simple truncate off the end of the item
349 */
350 u32 new_size = (bytenr - key->offset) >> blocksize_bits;
351 new_size *= csum_size;
352 ret = btrfs_truncate_item(trans, root, path, new_size, 1);
353 BUG_ON(ret);
354 } else if (key->offset >= bytenr && csum_end > end_byte &&
355 end_byte > key->offset) {
356 /*
357 * [ bytenr - len ]
358 * [ ]
359 * [csum ]
360 * we need to truncate from the beginning of the csum
361 */
362 u32 new_size = (csum_end - end_byte) >> blocksize_bits;
363 new_size *= csum_size;
364
365 ret = btrfs_truncate_item(trans, root, path, new_size, 0);
366 BUG_ON(ret);
367
368 key->offset = end_byte;
369 ret = btrfs_set_item_key_safe(trans, root, path, key);
370 BUG_ON(ret);
371 } else {
372 BUG();
373 }
374 return 0;
375}
376
377/*
378 * deletes the csum items from the csum tree for a given
379 * range of bytes.
380 */
381int btrfs_del_csums(struct btrfs_trans_handle *trans,
382 struct btrfs_root *root, u64 bytenr, u64 len)
383{
384 struct btrfs_path *path;
385 struct btrfs_key key;
386 u64 end_byte = bytenr + len;
387 u64 csum_end;
388 struct extent_buffer *leaf;
389 int ret;
390 u16 csum_size =
391 btrfs_super_csum_size(&root->fs_info->super_copy);
392 int blocksize_bits = root->fs_info->sb->s_blocksize_bits;
393
394 root = root->fs_info->csum_root;
395
396 path = btrfs_alloc_path();
397
398 while(1) {
399 key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
400 key.offset = end_byte - 1;
401 key.type = BTRFS_EXTENT_CSUM_KEY;
402
403 ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
404 if (ret > 0) {
405 if (path->slots[0] == 0)
406 goto out;
407 path->slots[0]--;
408 }
409 leaf = path->nodes[0];
410 btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
411
412 if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
413 key.type != BTRFS_EXTENT_CSUM_KEY) {
414 break;
415 }
416
417 if (key.offset >= end_byte)
418 break;
419
420 csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size;
421 csum_end <<= blocksize_bits;
422 csum_end += key.offset;
423
424 /* this csum ends before we start, we're done */
425 if (csum_end <= bytenr)
426 break;
427
428 /* delete the entire item, it is inside our range */
429 if (key.offset >= bytenr && csum_end <= end_byte) {
430 ret = btrfs_del_item(trans, root, path);
431 BUG_ON(ret);
432 } else if (key.offset < bytenr && csum_end > end_byte) {
433 unsigned long offset;
434 unsigned long shift_len;
435 unsigned long item_offset;
436 /*
437 * [ bytenr - len ]
438 * [csum ]
439 *
440 * Our bytes are in the middle of the csum,
441 * we need to split this item and insert a new one.
442 *
443 * But we can't drop the path because the
444 * csum could change, get removed, extended etc.
445 *
446 * The trick here is the max size of a csum item leaves
447 * enough room in the tree block for a single
448 * item header. So, we split the item in place,
449 * adding a new header pointing to the existing
450 * bytes. Then we loop around again and we have
451 * a nicely formed csum item that we can neatly
452 * truncate.
453 */
454 offset = (bytenr - key.offset) >> blocksize_bits;
455 offset *= csum_size;
456
457 shift_len = (len >> blocksize_bits) * csum_size;
458
459 item_offset = btrfs_item_ptr_offset(leaf,
460 path->slots[0]);
461
462 memset_extent_buffer(leaf, 0, item_offset + offset,
463 shift_len);
464 key.offset = bytenr;
465
466 /*
467 * btrfs_split_item returns -EAGAIN when the
468 * item changed size or key
469 */
470 ret = btrfs_split_item(trans, root, path, &key, offset);
471 BUG_ON(ret && ret != -EAGAIN);
472
473 key.offset = end_byte - 1;
474 } else {
475 ret = truncate_one_csum(trans, root, path,
476 &key, bytenr, len);
477 BUG_ON(ret);
478 }
479 btrfs_release_path(root, path);
480 }
481out:
482 btrfs_free_path(path);
483 return 0;
484}
485
313int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, 486int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
314 struct btrfs_root *root, 487 struct btrfs_root *root,
315 struct btrfs_ordered_sum *sums) 488 struct btrfs_ordered_sum *sums)
@@ -396,28 +569,40 @@ again:
396 csum_size, 1); 569 csum_size, 1);
397 if (ret < 0) 570 if (ret < 0)
398 goto fail_unlock; 571 goto fail_unlock;
399 if (ret == 0) { 572
400 BUG(); 573 if (ret > 0) {
401 } 574 if (path->slots[0] == 0)
402 if (path->slots[0] == 0) { 575 goto insert;
403 goto insert; 576 path->slots[0]--;
404 } 577 }
405 path->slots[0]--; 578
406 leaf = path->nodes[0]; 579 leaf = path->nodes[0];
407 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 580 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
408 csum_offset = (bytenr - found_key.offset) >> 581 csum_offset = (bytenr - found_key.offset) >>
409 root->fs_info->sb->s_blocksize_bits; 582 root->fs_info->sb->s_blocksize_bits;
583
410 if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY || 584 if (btrfs_key_type(&found_key) != BTRFS_EXTENT_CSUM_KEY ||
411 found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || 585 found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
412 csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { 586 csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) {
413 goto insert; 587 goto insert;
414 } 588 }
589
415 if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / 590 if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) /
416 csum_size) { 591 csum_size) {
417 u32 diff = (csum_offset + 1) * csum_size; 592 u32 diff = (csum_offset + 1) * csum_size;
593
594 /*
595 * is the item big enough already? we dropped our lock
596 * before and need to recheck
597 */
598 if (diff < btrfs_item_size_nr(leaf, path->slots[0]))
599 goto csum;
600
418 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); 601 diff = diff - btrfs_item_size_nr(leaf, path->slots[0]);
419 if (diff != csum_size) 602 if (diff != csum_size) {
420 goto insert; 603 goto insert;
604 }
605
421 ret = btrfs_extend_item(trans, root, path, diff); 606 ret = btrfs_extend_item(trans, root, path, diff);
422 BUG_ON(ret); 607 BUG_ON(ret);
423 goto csum; 608 goto csum;
@@ -518,30 +703,3 @@ out:
518fail_unlock: 703fail_unlock:
519 goto out; 704 goto out;
520} 705}
521
522int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
523 struct btrfs_root *root, struct btrfs_path *path,
524 u64 isize)
525{
526 struct btrfs_key key;
527 struct extent_buffer *leaf = path->nodes[0];
528 int slot = path->slots[0];
529 int ret;
530 u32 new_item_size;
531 u64 new_item_span;
532 u64 blocks;
533
534 btrfs_item_key_to_cpu(leaf, &key, slot);
535 if (isize <= key.offset)
536 return 0;
537 new_item_span = isize - key.offset;
538 blocks = (new_item_span + root->sectorsize - 1) >>
539 root->fs_info->sb->s_blocksize_bits;
540 new_item_size = blocks *
541 btrfs_super_csum_size(&root->fs_info->super_copy);
542 if (new_item_size >= btrfs_item_size_nr(leaf, slot))
543 return 0;
544 ret = btrfs_truncate_item(trans, root, path, new_item_size, 1);
545 BUG_ON(ret);
546 return ret;
547}