diff options
author | Yan, Zheng <zheng.yan@oracle.com> | 2010-05-16 10:48:47 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-05-25 10:34:51 -0400 |
commit | 0ca1f7ceb1991099ed5273885ebcf4323948c72e (patch) | |
tree | 10758d6a55c529aced177da3f6bf45cf26361913 /fs/btrfs/extent_io.c | |
parent | a22285a6a32390195235171b89d157ed1a1fe932 (diff) |
Btrfs: Update metadata reservation for delayed allocation
Introduce metadata reservation context for delayed allocation
and update various related functions.
This patch also introduces EXTENT_FIRST_DELALLOC control bit for
set/clear_extent_bit. It tells set/clear_bit_hook whether they
are processing the first extent_state with EXTENT_DELALLOC bit
set. This change is important if set/clear_extent_bit involves
multiple extent_state.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 63 |
1 files changed, 30 insertions, 33 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index d2d03684fab2..1a57c17d4029 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -335,21 +335,18 @@ static int merge_state(struct extent_io_tree *tree, | |||
335 | } | 335 | } |
336 | 336 | ||
337 | static int set_state_cb(struct extent_io_tree *tree, | 337 | static int set_state_cb(struct extent_io_tree *tree, |
338 | struct extent_state *state, | 338 | struct extent_state *state, int *bits) |
339 | unsigned long bits) | ||
340 | { | 339 | { |
341 | if (tree->ops && tree->ops->set_bit_hook) { | 340 | if (tree->ops && tree->ops->set_bit_hook) { |
342 | return tree->ops->set_bit_hook(tree->mapping->host, | 341 | return tree->ops->set_bit_hook(tree->mapping->host, |
343 | state->start, state->end, | 342 | state, bits); |
344 | state->state, bits); | ||
345 | } | 343 | } |
346 | 344 | ||
347 | return 0; | 345 | return 0; |
348 | } | 346 | } |
349 | 347 | ||
350 | static void clear_state_cb(struct extent_io_tree *tree, | 348 | static void clear_state_cb(struct extent_io_tree *tree, |
351 | struct extent_state *state, | 349 | struct extent_state *state, int *bits) |
352 | unsigned long bits) | ||
353 | { | 350 | { |
354 | if (tree->ops && tree->ops->clear_bit_hook) | 351 | if (tree->ops && tree->ops->clear_bit_hook) |
355 | tree->ops->clear_bit_hook(tree->mapping->host, state, bits); | 352 | tree->ops->clear_bit_hook(tree->mapping->host, state, bits); |
@@ -367,9 +364,10 @@ static void clear_state_cb(struct extent_io_tree *tree, | |||
367 | */ | 364 | */ |
368 | static int insert_state(struct extent_io_tree *tree, | 365 | static int insert_state(struct extent_io_tree *tree, |
369 | struct extent_state *state, u64 start, u64 end, | 366 | struct extent_state *state, u64 start, u64 end, |
370 | int bits) | 367 | int *bits) |
371 | { | 368 | { |
372 | struct rb_node *node; | 369 | struct rb_node *node; |
370 | int bits_to_set = *bits & ~EXTENT_CTLBITS; | ||
373 | int ret; | 371 | int ret; |
374 | 372 | ||
375 | if (end < start) { | 373 | if (end < start) { |
@@ -384,9 +382,9 @@ static int insert_state(struct extent_io_tree *tree, | |||
384 | if (ret) | 382 | if (ret) |
385 | return ret; | 383 | return ret; |
386 | 384 | ||
387 | if (bits & EXTENT_DIRTY) | 385 | if (bits_to_set & EXTENT_DIRTY) |
388 | tree->dirty_bytes += end - start + 1; | 386 | tree->dirty_bytes += end - start + 1; |
389 | state->state |= bits; | 387 | state->state |= bits_to_set; |
390 | node = tree_insert(&tree->state, end, &state->rb_node); | 388 | node = tree_insert(&tree->state, end, &state->rb_node); |
391 | if (node) { | 389 | if (node) { |
392 | struct extent_state *found; | 390 | struct extent_state *found; |
@@ -456,13 +454,13 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig, | |||
456 | * struct is freed and removed from the tree | 454 | * struct is freed and removed from the tree |
457 | */ | 455 | */ |
458 | static int clear_state_bit(struct extent_io_tree *tree, | 456 | static int clear_state_bit(struct extent_io_tree *tree, |
459 | struct extent_state *state, int bits, int wake, | 457 | struct extent_state *state, |
460 | int delete) | 458 | int *bits, int wake) |
461 | { | 459 | { |
462 | int bits_to_clear = bits & ~EXTENT_DO_ACCOUNTING; | 460 | int bits_to_clear = *bits & ~EXTENT_CTLBITS; |
463 | int ret = state->state & bits_to_clear; | 461 | int ret = state->state & bits_to_clear; |
464 | 462 | ||
465 | if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) { | 463 | if ((bits_to_clear & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) { |
466 | u64 range = state->end - state->start + 1; | 464 | u64 range = state->end - state->start + 1; |
467 | WARN_ON(range > tree->dirty_bytes); | 465 | WARN_ON(range > tree->dirty_bytes); |
468 | tree->dirty_bytes -= range; | 466 | tree->dirty_bytes -= range; |
@@ -471,9 +469,8 @@ static int clear_state_bit(struct extent_io_tree *tree, | |||
471 | state->state &= ~bits_to_clear; | 469 | state->state &= ~bits_to_clear; |
472 | if (wake) | 470 | if (wake) |
473 | wake_up(&state->wq); | 471 | wake_up(&state->wq); |
474 | if (delete || state->state == 0) { | 472 | if (state->state == 0) { |
475 | if (state->tree) { | 473 | if (state->tree) { |
476 | clear_state_cb(tree, state, state->state); | ||
477 | rb_erase(&state->rb_node, &tree->state); | 474 | rb_erase(&state->rb_node, &tree->state); |
478 | state->tree = NULL; | 475 | state->tree = NULL; |
479 | free_extent_state(state); | 476 | free_extent_state(state); |
@@ -514,6 +511,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | |||
514 | int set = 0; | 511 | int set = 0; |
515 | int clear = 0; | 512 | int clear = 0; |
516 | 513 | ||
514 | if (delete) | ||
515 | bits |= ~EXTENT_CTLBITS; | ||
516 | bits |= EXTENT_FIRST_DELALLOC; | ||
517 | |||
517 | if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY)) | 518 | if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY)) |
518 | clear = 1; | 519 | clear = 1; |
519 | again: | 520 | again: |
@@ -580,8 +581,7 @@ hit_next: | |||
580 | if (err) | 581 | if (err) |
581 | goto out; | 582 | goto out; |
582 | if (state->end <= end) { | 583 | if (state->end <= end) { |
583 | set |= clear_state_bit(tree, state, bits, wake, | 584 | set |= clear_state_bit(tree, state, &bits, wake); |
584 | delete); | ||
585 | if (last_end == (u64)-1) | 585 | if (last_end == (u64)-1) |
586 | goto out; | 586 | goto out; |
587 | start = last_end + 1; | 587 | start = last_end + 1; |
@@ -602,7 +602,7 @@ hit_next: | |||
602 | if (wake) | 602 | if (wake) |
603 | wake_up(&state->wq); | 603 | wake_up(&state->wq); |
604 | 604 | ||
605 | set |= clear_state_bit(tree, prealloc, bits, wake, delete); | 605 | set |= clear_state_bit(tree, prealloc, &bits, wake); |
606 | 606 | ||
607 | prealloc = NULL; | 607 | prealloc = NULL; |
608 | goto out; | 608 | goto out; |
@@ -613,7 +613,7 @@ hit_next: | |||
613 | else | 613 | else |
614 | next_node = NULL; | 614 | next_node = NULL; |
615 | 615 | ||
616 | set |= clear_state_bit(tree, state, bits, wake, delete); | 616 | set |= clear_state_bit(tree, state, &bits, wake); |
617 | if (last_end == (u64)-1) | 617 | if (last_end == (u64)-1) |
618 | goto out; | 618 | goto out; |
619 | start = last_end + 1; | 619 | start = last_end + 1; |
@@ -706,19 +706,19 @@ out: | |||
706 | 706 | ||
707 | static int set_state_bits(struct extent_io_tree *tree, | 707 | static int set_state_bits(struct extent_io_tree *tree, |
708 | struct extent_state *state, | 708 | struct extent_state *state, |
709 | int bits) | 709 | int *bits) |
710 | { | 710 | { |
711 | int ret; | 711 | int ret; |
712 | int bits_to_set = *bits & ~EXTENT_CTLBITS; | ||
712 | 713 | ||
713 | ret = set_state_cb(tree, state, bits); | 714 | ret = set_state_cb(tree, state, bits); |
714 | if (ret) | 715 | if (ret) |
715 | return ret; | 716 | return ret; |
716 | 717 | if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) { | |
717 | if ((bits & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) { | ||
718 | u64 range = state->end - state->start + 1; | 718 | u64 range = state->end - state->start + 1; |
719 | tree->dirty_bytes += range; | 719 | tree->dirty_bytes += range; |
720 | } | 720 | } |
721 | state->state |= bits; | 721 | state->state |= bits_to_set; |
722 | 722 | ||
723 | return 0; | 723 | return 0; |
724 | } | 724 | } |
@@ -757,6 +757,7 @@ static int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | |||
757 | u64 last_start; | 757 | u64 last_start; |
758 | u64 last_end; | 758 | u64 last_end; |
759 | 759 | ||
760 | bits |= EXTENT_FIRST_DELALLOC; | ||
760 | again: | 761 | again: |
761 | if (!prealloc && (mask & __GFP_WAIT)) { | 762 | if (!prealloc && (mask & __GFP_WAIT)) { |
762 | prealloc = alloc_extent_state(mask); | 763 | prealloc = alloc_extent_state(mask); |
@@ -778,7 +779,7 @@ again: | |||
778 | */ | 779 | */ |
779 | node = tree_search(tree, start); | 780 | node = tree_search(tree, start); |
780 | if (!node) { | 781 | if (!node) { |
781 | err = insert_state(tree, prealloc, start, end, bits); | 782 | err = insert_state(tree, prealloc, start, end, &bits); |
782 | prealloc = NULL; | 783 | prealloc = NULL; |
783 | BUG_ON(err == -EEXIST); | 784 | BUG_ON(err == -EEXIST); |
784 | goto out; | 785 | goto out; |
@@ -802,7 +803,7 @@ hit_next: | |||
802 | goto out; | 803 | goto out; |
803 | } | 804 | } |
804 | 805 | ||
805 | err = set_state_bits(tree, state, bits); | 806 | err = set_state_bits(tree, state, &bits); |
806 | if (err) | 807 | if (err) |
807 | goto out; | 808 | goto out; |
808 | 809 | ||
@@ -852,7 +853,7 @@ hit_next: | |||
852 | if (err) | 853 | if (err) |
853 | goto out; | 854 | goto out; |
854 | if (state->end <= end) { | 855 | if (state->end <= end) { |
855 | err = set_state_bits(tree, state, bits); | 856 | err = set_state_bits(tree, state, &bits); |
856 | if (err) | 857 | if (err) |
857 | goto out; | 858 | goto out; |
858 | cache_state(state, cached_state); | 859 | cache_state(state, cached_state); |
@@ -877,7 +878,7 @@ hit_next: | |||
877 | else | 878 | else |
878 | this_end = last_start - 1; | 879 | this_end = last_start - 1; |
879 | err = insert_state(tree, prealloc, start, this_end, | 880 | err = insert_state(tree, prealloc, start, this_end, |
880 | bits); | 881 | &bits); |
881 | BUG_ON(err == -EEXIST); | 882 | BUG_ON(err == -EEXIST); |
882 | if (err) { | 883 | if (err) { |
883 | prealloc = NULL; | 884 | prealloc = NULL; |
@@ -903,7 +904,7 @@ hit_next: | |||
903 | err = split_state(tree, state, prealloc, end + 1); | 904 | err = split_state(tree, state, prealloc, end + 1); |
904 | BUG_ON(err == -EEXIST); | 905 | BUG_ON(err == -EEXIST); |
905 | 906 | ||
906 | err = set_state_bits(tree, prealloc, bits); | 907 | err = set_state_bits(tree, prealloc, &bits); |
907 | if (err) { | 908 | if (err) { |
908 | prealloc = NULL; | 909 | prealloc = NULL; |
909 | goto out; | 910 | goto out; |
@@ -966,8 +967,7 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | |||
966 | { | 967 | { |
967 | return clear_extent_bit(tree, start, end, | 968 | return clear_extent_bit(tree, start, end, |
968 | EXTENT_DIRTY | EXTENT_DELALLOC | | 969 | EXTENT_DIRTY | EXTENT_DELALLOC | |
969 | EXTENT_DO_ACCOUNTING, 0, 0, | 970 | EXTENT_DO_ACCOUNTING, 0, 0, NULL, mask); |
970 | NULL, mask); | ||
971 | } | 971 | } |
972 | 972 | ||
973 | int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end, | 973 | int set_extent_new(struct extent_io_tree *tree, u64 start, u64 end, |
@@ -1435,9 +1435,6 @@ int extent_clear_unlock_delalloc(struct inode *inode, | |||
1435 | if (op & EXTENT_CLEAR_DELALLOC) | 1435 | if (op & EXTENT_CLEAR_DELALLOC) |
1436 | clear_bits |= EXTENT_DELALLOC; | 1436 | clear_bits |= EXTENT_DELALLOC; |
1437 | 1437 | ||
1438 | if (op & EXTENT_CLEAR_ACCOUNTING) | ||
1439 | clear_bits |= EXTENT_DO_ACCOUNTING; | ||
1440 | |||
1441 | clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS); | 1438 | clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS); |
1442 | if (!(op & (EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY | | 1439 | if (!(op & (EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY | |
1443 | EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK | | 1440 | EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK | |